248 lines
10 KiB
Java
248 lines
10 KiB
Java
package eu.eudat.interceptors;
|
|
|
|
|
|
import eu.eudat.commons.enums.ProviderType;
|
|
import eu.eudat.commons.enums.IsActive;
|
|
import eu.eudat.commons.scope.user.UserScope;
|
|
import eu.eudat.data.CredentialEntity;
|
|
import eu.eudat.data.entities.UserInfo;
|
|
import eu.eudat.data.entities.UserRole;
|
|
import eu.eudat.exceptions.security.NullEmailException;
|
|
import eu.eudat.types.Authorities;
|
|
import gr.cite.commons.web.oidc.principal.CurrentPrincipalResolver;
|
|
import gr.cite.commons.web.oidc.principal.extractor.ClaimExtractor;
|
|
import gr.cite.tools.exception.MyApplicationException;
|
|
import gr.cite.tools.logging.LoggerService;
|
|
import jakarta.persistence.EntityManager;
|
|
import jakarta.persistence.PersistenceContext;
|
|
import jakarta.persistence.Tuple;
|
|
import jakarta.persistence.TypedQuery;
|
|
import jakarta.persistence.criteria.CriteriaBuilder;
|
|
import jakarta.persistence.criteria.CriteriaQuery;
|
|
import jakarta.persistence.criteria.Root;
|
|
import org.slf4j.LoggerFactory;
|
|
import org.springframework.beans.factory.annotation.Autowired;
|
|
import org.springframework.lang.NonNull;
|
|
import org.springframework.stereotype.Component;
|
|
import org.springframework.transaction.PlatformTransactionManager;
|
|
import org.springframework.transaction.TransactionDefinition;
|
|
import org.springframework.transaction.TransactionStatus;
|
|
import org.springframework.transaction.support.DefaultTransactionDefinition;
|
|
import org.springframework.ui.ModelMap;
|
|
import org.springframework.web.context.request.ServletWebRequest;
|
|
import org.springframework.web.context.request.WebRequest;
|
|
import org.springframework.web.context.request.WebRequestInterceptor;
|
|
|
|
import javax.management.InvalidApplicationException;
|
|
import java.util.Date;
|
|
import java.util.List;
|
|
import java.util.Locale;
|
|
import java.util.UUID;
|
|
|
|
@Component
|
|
public class UserInterceptor implements WebRequestInterceptor {
|
|
private static final LoggerService logger = new LoggerService(LoggerFactory.getLogger(UserInterceptor.class));
|
|
private final UserScope userScope;
|
|
private final ClaimExtractor claimExtractor;
|
|
private final CurrentPrincipalResolver currentPrincipalResolver;
|
|
private final PlatformTransactionManager transactionManager;
|
|
private final UserInterceptorCacheService userInterceptorCacheService;
|
|
@PersistenceContext
|
|
public EntityManager entityManager;
|
|
|
|
@Autowired
|
|
public UserInterceptor(
|
|
UserScope userScope,
|
|
ClaimExtractor claimExtractor,
|
|
CurrentPrincipalResolver currentPrincipalResolver,
|
|
PlatformTransactionManager transactionManager,
|
|
UserInterceptorCacheService userInterceptorCacheService
|
|
) {
|
|
this.userScope = userScope;
|
|
this.currentPrincipalResolver = currentPrincipalResolver;
|
|
this.claimExtractor = claimExtractor;
|
|
this.transactionManager = transactionManager;
|
|
this.userInterceptorCacheService = userInterceptorCacheService;
|
|
}
|
|
|
|
@Override
|
|
public void preHandle(WebRequest request) throws InvalidApplicationException {
|
|
UUID userId = null;
|
|
if (this.currentPrincipalResolver.currentPrincipal().isAuthenticated()) {
|
|
String subjectId = this.claimExtractor.subjectString(this.currentPrincipalResolver.currentPrincipal());
|
|
var aa = this.claimExtractor.roles(this.currentPrincipalResolver.currentPrincipal());
|
|
UserInterceptorCacheService.UserInterceptorCacheValue cacheValue = this.userInterceptorCacheService.lookup(this.userInterceptorCacheService.buildKey(subjectId));
|
|
if (cacheValue != null) {
|
|
userId = cacheValue.getUserId();
|
|
} else {
|
|
userId = this.getUserIdFromDatabaseBySubject(subjectId);
|
|
if (userId == null ) {
|
|
String email = this.claimExtractor.email(this.currentPrincipalResolver.currentPrincipal());
|
|
if (email != null && !email.isBlank()) {
|
|
userId = this.getUserIdFromDatabaseByEmail(email);
|
|
userId = this.createOrUpdateUser(subjectId, userId);
|
|
} else {
|
|
boolean checkMailNull = ((ServletWebRequest) request).getRequest().getServletPath().toLowerCase(Locale.ROOT).startsWith("/api/emailConfirmation".toLowerCase(Locale.ROOT));
|
|
if (!checkMailNull) throw new NullEmailException();
|
|
}
|
|
}
|
|
|
|
if (userId != null) this.userInterceptorCacheService.put(new UserInterceptorCacheService.UserInterceptorCacheValue(subjectId, userId));
|
|
}
|
|
}
|
|
this.userScope.setUserId(userId);
|
|
}
|
|
|
|
private UUID getUserIdFromDatabaseBySubject(String subjectId) {
|
|
CriteriaBuilder credentialCriteriaBuilder = this.entityManager.getCriteriaBuilder();
|
|
CriteriaQuery<Tuple> credentialQuery = credentialCriteriaBuilder.createQuery(Tuple.class);
|
|
Root<CredentialEntity> credentialRoot = credentialQuery.from(CredentialEntity.class);
|
|
credentialQuery.where(
|
|
credentialCriteriaBuilder.and(
|
|
credentialCriteriaBuilder.equal(credentialRoot.get(CredentialEntity._externalId), subjectId),
|
|
credentialCriteriaBuilder.equal(credentialRoot.get(CredentialEntity._isActive), IsActive.Active),
|
|
credentialCriteriaBuilder.equal(credentialRoot.get(CredentialEntity._provider), ProviderType.Keycloack)
|
|
));
|
|
|
|
credentialQuery.multiselect(credentialRoot.get(CredentialEntity._userId).alias(UserInfo._id));
|
|
|
|
List<Tuple> results = this.entityManager.createQuery(credentialQuery).getResultList();
|
|
return this.getUUIDFromTuple(results, UserInfo._id);
|
|
}
|
|
|
|
private UUID getUserIdFromDatabaseByEmail(String email) {
|
|
CriteriaBuilder emailCriteriaBuilder = this.entityManager.getCriteriaBuilder();
|
|
CriteriaQuery<Tuple> emailQuery = emailCriteriaBuilder.createQuery(Tuple.class);
|
|
Root<UserInfo> emailRoot = emailQuery.from(UserInfo.class);
|
|
emailQuery.where(
|
|
emailCriteriaBuilder.and(
|
|
emailCriteriaBuilder.equal(emailRoot.get(UserInfo._email), email),
|
|
emailCriteriaBuilder.equal(emailRoot.get(UserInfo._userStatus), 0) //TODO: Authn
|
|
));
|
|
|
|
emailQuery.multiselect(emailRoot.get(UserInfo._id).alias(UserInfo._id));
|
|
|
|
List<Tuple> results = this.entityManager.createQuery(emailQuery).getResultList();
|
|
return this.getUUIDFromTuple(results, UserInfo._id);
|
|
}
|
|
|
|
private UUID getUUIDFromTuple(List<Tuple> results, String field){
|
|
if (results.size() > 0) {//TODO: Authn
|
|
Object o;
|
|
try {
|
|
o = results.get(0).get(field);
|
|
} catch (IllegalArgumentException e) {
|
|
return null;
|
|
}
|
|
if (o == null) return null;
|
|
try {
|
|
return UUID.class.cast(o);
|
|
} catch (ClassCastException e) {
|
|
return null;
|
|
}
|
|
}
|
|
return null;
|
|
}
|
|
|
|
private UUID createOrUpdateUser(String subjectId, UUID userId) {
|
|
String name = this.claimExtractor.name(this.currentPrincipalResolver.currentPrincipal());
|
|
String emailVerified = this.claimExtractor.emailVerified(this.currentPrincipalResolver.currentPrincipal());
|
|
String email = this.claimExtractor.email(this.currentPrincipalResolver.currentPrincipal());
|
|
if (name == null) name = subjectId;
|
|
|
|
UserInfo user = null;
|
|
UserRole userRole = null;
|
|
boolean isUpdateUser = userId != null;
|
|
if (!isUpdateUser) {
|
|
|
|
user = new UserInfo();
|
|
user.setId(UUID.randomUUID());
|
|
user.setVerified_email("true".equals(emailVerified));//TODO: Authn
|
|
user.setName(name);
|
|
user.setEmail(email);
|
|
user.setCreated(new Date());
|
|
user.setLastloggedin(new Date());
|
|
user.setLastloggedin(new Date());
|
|
user.setAuthorization_level((short) 1);//TODO: Authn
|
|
user.setUsertype((short) 1);
|
|
user.setUserStatus((short) 0);
|
|
// user.setAdditionalinfo("{\"data\":{\"avatar\":{\"url\":\"" + profile.getAvatarUrl()
|
|
// + "\"},\"zenodoToken\":\"" + profile.getZenodoId()
|
|
// + "\", \"expirationDate\": \"" + Instant.now().plusSeconds((profile.getZenodoExpire() != null ? profile.getZenodoExpire(): 0)).toEpochMilli()
|
|
// + "\", \"zenodoRefresh\": \"" + profile.getZenodoRefresh()
|
|
// + (profile.getProvider() == TokenValidatorFactoryImpl.LoginProvider.ZENODO ? "\", \"zenodoEmail\": \"" + profile.getEmail() : "") +"\"}}");
|
|
user.setAdditionalinfo("{\"data\":{\"avatar\":{\"url\":\"\"},\"zenodoToken\":\"\", \"expirationDate\": \"\", \"zenodoRefresh\": \"\", \"zenodoEmail\": \"\"}}"); //TODO: Authn
|
|
|
|
userRole = new UserRole();
|
|
userRole.setId(UUID.randomUUID());
|
|
userRole.setUserInfo(user);
|
|
userRole.setRole(Authorities.USER.getValue());
|
|
} else {
|
|
CriteriaBuilder emailCriteriaBuilder = this.entityManager.getCriteriaBuilder();
|
|
CriteriaQuery<UserInfo> userQuery = emailCriteriaBuilder.createQuery(UserInfo.class);
|
|
Root<UserInfo> userRoot = userQuery.from(UserInfo.class);
|
|
userQuery.where(
|
|
emailCriteriaBuilder.and(
|
|
emailCriteriaBuilder.equal(userRoot.get(UserInfo._id), userId),
|
|
emailCriteriaBuilder.equal(userRoot.get(UserInfo._userStatus), 0) //TODO: Authn
|
|
));
|
|
userQuery.select(userRoot);
|
|
TypedQuery<UserInfo> q = this.entityManager.createQuery(userQuery);
|
|
List<UserInfo> userInfos = q.getResultList();
|
|
if (userInfos == null || userInfos.size() < 1) {
|
|
throw new MyApplicationException("Can not found user " + userId);
|
|
}
|
|
user = userInfos.get(0);
|
|
user.setAdditionalinfo("{\"data\":{\"avatar\":{\"url\":\"\"},\"zenodoToken\":\"\", \"expirationDate\": \"\", \"zenodoRefresh\": \"\", \"zenodoEmail\": \"\"}}"); //TODO: Authn
|
|
}
|
|
|
|
CredentialEntity credentialEntity = new CredentialEntity();
|
|
credentialEntity.setId(UUID.randomUUID());
|
|
credentialEntity.setUserId(user.getId());
|
|
credentialEntity.setSecret(subjectId);
|
|
credentialEntity.setCreationTime(new Date());
|
|
credentialEntity.setLastUpdateTime(new Date());
|
|
credentialEntity.setIsActive(IsActive.Active);
|
|
credentialEntity.setProvider(ProviderType.Keycloack);//TODO: Authn
|
|
credentialEntity.setExternalId(subjectId);
|
|
credentialEntity.setEmail(email);
|
|
credentialEntity.setPublicValue(email);
|
|
|
|
|
|
DefaultTransactionDefinition definition = new DefaultTransactionDefinition();
|
|
definition.setName(UUID.randomUUID().toString());
|
|
definition.setIsolationLevel(TransactionDefinition.ISOLATION_READ_COMMITTED);
|
|
definition.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRED);
|
|
TransactionStatus status = null;
|
|
try {
|
|
status = transactionManager.getTransaction(definition);
|
|
if (!isUpdateUser) {
|
|
user = this.entityManager.merge(user);
|
|
this.entityManager.flush();
|
|
userRole.setUserInfo(user);
|
|
credentialEntity.setUserId(user.getId());
|
|
this.entityManager.merge(userRole);
|
|
this.entityManager.merge(credentialEntity);
|
|
} else {
|
|
this.entityManager.persist(user);
|
|
this.entityManager.persist(credentialEntity);
|
|
}
|
|
this.entityManager.flush();
|
|
transactionManager.commit(status);
|
|
} catch (Exception ex) {
|
|
if (status != null) transactionManager.rollback(status);
|
|
throw ex;
|
|
}
|
|
return user.getId();
|
|
}
|
|
|
|
@Override
|
|
public void postHandle(@NonNull WebRequest request, ModelMap model) {
|
|
this.userScope.setUserId(null);
|
|
}
|
|
|
|
@Override
|
|
public void afterCompletion(@NonNull WebRequest request, Exception ex) {
|
|
}
|
|
}
|