Skip to content

Commit

Permalink
Refactor SecurityUtils.getCurrentUser
Browse files Browse the repository at this point in the history
  • Loading branch information
kostobog committed May 3, 2024
1 parent 420d676 commit faca007
Show file tree
Hide file tree
Showing 8 changed files with 91 additions and 32 deletions.
5 changes: 3 additions & 2 deletions src/main/java/cz/cvut/kbss/analysis/dao/FaultTreeDao.java
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
import cz.cvut.kbss.analysis.model.FaultTree;
import cz.cvut.kbss.analysis.model.FaultTreeSummary;
import cz.cvut.kbss.analysis.service.IdentifierService;
import cz.cvut.kbss.analysis.service.security.SecurityUtils;
import cz.cvut.kbss.analysis.util.Vocabulary;
import cz.cvut.kbss.jopa.model.EntityManager;
import cz.cvut.kbss.jopa.model.descriptors.EntityDescriptor;
Expand All @@ -22,8 +23,8 @@
public class FaultTreeDao extends ManagedEntityDao<FaultTree> {

@Autowired
protected FaultTreeDao(EntityManager em, PersistenceConf config, IdentifierService identifierService) {
super(FaultTree.class, em, config, identifierService);
protected FaultTreeDao(EntityManager em, PersistenceConf config, IdentifierService identifierService, SecurityUtils securityUtils) {
super(FaultTree.class, em, config, identifierService, securityUtils);
}

public boolean isRootEvent(URI faultEventIri) {
Expand Down
7 changes: 5 additions & 2 deletions src/main/java/cz/cvut/kbss/analysis/dao/ManagedEntityDao.java
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,11 @@ public class ManagedEntityDao<T extends ManagedEntity> extends NamedEntityDao<T>
public static URI P_CREATOR = URI.create( DC.Terms.CREATOR);
public static URI P_LAST_EDITOR = URI.create(Vocabulary.s_c_editor);

protected ManagedEntityDao(Class<T> type, EntityManager em, PersistenceConf config, IdentifierService identifierService) {
protected final SecurityUtils securityUtils;

protected ManagedEntityDao(Class<T> type, EntityManager em, PersistenceConf config, IdentifierService identifierService, SecurityUtils securityUtils) {
super(type, em, config, identifierService);
this.securityUtils = securityUtils;
}


Expand All @@ -41,7 +44,7 @@ protected void setEntityDescriptor(EntityDescriptor descriptor) {
}

public void setChangedByContext(URI context, Date date){
UserReference user = SecurityUtils.currentUserReference();
UserReference user = securityUtils.getCurrentUserReference();
em.createNativeQuery("""
DELETE{
GRAPH ?context{
Expand Down
5 changes: 3 additions & 2 deletions src/main/java/cz/cvut/kbss/analysis/dao/SystemDao.java
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
import cz.cvut.kbss.analysis.config.conf.PersistenceConf;
import cz.cvut.kbss.analysis.model.System;
import cz.cvut.kbss.analysis.service.IdentifierService;
import cz.cvut.kbss.analysis.service.security.SecurityUtils;
import cz.cvut.kbss.jopa.model.EntityManager;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Repository;
Expand All @@ -11,7 +12,7 @@
public class SystemDao extends ManagedEntityDao<System> {

@Autowired
protected SystemDao(EntityManager em, PersistenceConf config, IdentifierService identifierService) {
super(System.class, em, config, identifierService);
protected SystemDao(EntityManager em, PersistenceConf config, IdentifierService identifierService, SecurityUtils securityUtils) {
super(System.class, em, config, identifierService, securityUtils);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -21,24 +21,26 @@
*/
public abstract class ComplexManagedEntityRepositoryService<T extends ManagedEntity> extends BaseRepositoryService<T> {
protected final UserDao userDao;
protected final SecurityUtils securityUtils;

public ComplexManagedEntityRepositoryService(Validator validator, UserDao userDao) {
public ComplexManagedEntityRepositoryService(Validator validator, UserDao userDao, SecurityUtils securityUtils) {
super(validator);
this.userDao = userDao;
this.securityUtils = securityUtils;
}

@Override
protected void preUpdate(@NonNull T instance) {
super.preUpdate(instance);
UserReference user = SecurityUtils.currentUserReference();
UserReference user = securityUtils.getCurrentUserReference();
instance.setLastEditor(user);
instance.setModified(new Date());
}

@Override
protected void prePersist(@NonNull T instance) {
super.prePersist(instance);
UserReference user = SecurityUtils.currentUserReference();
UserReference user = securityUtils.getCurrentUserReference();
instance.setCreator(user);
instance.setCreated(new Date());
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
import cz.cvut.kbss.analysis.model.fta.FTAMinimalCutSetEvaluation;
import cz.cvut.kbss.analysis.model.fta.FtaEventType;
import cz.cvut.kbss.analysis.model.fta.GateType;
import cz.cvut.kbss.analysis.service.security.SecurityUtils;
import cz.cvut.kbss.analysis.service.util.FaultTreeTraversalUtils;
import cz.cvut.kbss.analysis.service.util.Pair;
import cz.cvut.kbss.analysis.util.Vocabulary;
Expand All @@ -37,7 +38,6 @@ public class FaultTreeRepositoryService extends ComplexManagedEntityRepositorySe
private final FunctionRepositoryService functionRepositoryService;
private final IdentifierService identifierService;


private final ThreadLocal<Set<Behavior>> visitedBehaviors = new ThreadLocal<>();

@Autowired
Expand All @@ -47,9 +47,10 @@ public FaultTreeRepositoryService(@Qualifier("defaultValidator") Validator valid
FaultEventRepositoryService faultEventRepositoryService,
FunctionRepositoryService functionRepositoryService,
IdentifierService identifierService,
UserDao userDao
UserDao userDao,
SecurityUtils securityUtils
) {
super(validator, userDao);
super(validator, userDao, securityUtils);
this.faultTreeDao = faultTreeDao;
this.faultEventScenarioDao = faultEventScenarioDao;
this.faultEventRepositoryService = faultEventRepositoryService;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
import cz.cvut.kbss.analysis.model.FailureMode;
import cz.cvut.kbss.analysis.model.Item;
import cz.cvut.kbss.analysis.model.System;
import cz.cvut.kbss.analysis.service.security.SecurityUtils;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
Expand All @@ -33,10 +34,11 @@ public SystemRepositoryService(@Qualifier("defaultValidator") Validator validato
SystemDao systemDao,
ComponentRepositoryService componentRepositoryService,
ComponentDao componentDao,
UserDao userDao
UserDao userDao,
SecurityUtils securityUtils

) {
super(validator, userDao);
super(validator, userDao, securityUtils);
this.systemDao = systemDao;
this.componentRepositoryService = componentRepositoryService;
this.componentDao = componentDao;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,12 +24,18 @@ public class UserRepositoryService extends BaseRepositoryService<User> {

private final UserDao userDao;
private final PasswordEncoder passwordEncoder;
private final SecurityUtils securityUtils;

@Autowired
public UserRepositoryService(@Qualifier("defaultValidator") Validator validator, UserDao userDao, PasswordEncoder passwordEncoder) {
public UserRepositoryService(@Qualifier("defaultValidator") Validator validator, UserDao userDao, PasswordEncoder passwordEncoder, SecurityUtils securityUtils) {
super(validator);
this.userDao = userDao;
this.passwordEncoder = passwordEncoder;
this.securityUtils = securityUtils;
}

public User getCurrentUser() {
return securityUtils.getCurrentUser();
}

@Override
Expand All @@ -54,7 +60,7 @@ public URI register(User user) {
public void updateCurrent(UserUpdateDTO userUpdate) {
log.info("> updateCurrent - {}", userUpdate.getUsername());

User currentUser = SecurityUtils.currentUser();
User currentUser = getCurrentUser();
if (!currentUser.getUri().equals(userUpdate.getUri())) {
log.warn("< updateCurrent - URIs do not match! {} != {}", currentUser.getUri(), userUpdate.getUri());
throw new LogicViolationException("User update uri does not match current user!");
Expand Down
Original file line number Diff line number Diff line change
@@ -1,49 +1,92 @@
package cz.cvut.kbss.analysis.service.security;

import cz.cvut.kbss.analysis.config.conf.SecurityConf;
import cz.cvut.kbss.analysis.dao.UserDao;
import cz.cvut.kbss.analysis.exception.EntityNotFoundException;
import cz.cvut.kbss.analysis.model.User;
import cz.cvut.kbss.analysis.model.UserReference;
import org.springframework.security.core.Authentication;
import org.springframework.security.authentication.AbstractAuthenticationToken;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.context.SecurityContext;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.context.SecurityContextImpl;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.oauth2.core.oidc.OidcUserInfo;
import org.springframework.security.oauth2.jwt.Jwt;
import org.springframework.stereotype.Service;

/**
* Handle user session-related functions.
*/
@Service
public class SecurityUtils {

public SecurityUtils() {

private final UserDao userDao;

private final SecurityConf config;

public SecurityUtils(UserDao userDao, SecurityConf config) {
this.userDao = userDao;
this.config = config;
// Ensures security context is propagated to additionally spun threads, e.g., used
// by @Async methods
SecurityContextHolder.setStrategyName(SecurityContextHolder.MODE_INHERITABLETHREADLOCAL);
SecurityContextHolder.setStrategyName(SecurityContextHolder.MODE_INHERITABLETHREADLOCAL); // TODO check what it does
}

/**
* Gets the currently authenticated user.
* If the user is impersonating another user, the impersonated user is returned.
* Otherwise, the currently authenticated user is returned.
*
* <p>It allows to access the currently logged in user without injecting {@code SecurityUtils}
* as a bean.
*
* @return Currently logged in user
* @return
*/
public static User currentUser() {
return (User) SecurityContextHolder.getContext().getAuthentication().getPrincipal();
public User getCurrentUser() {
final SecurityContext context = SecurityContextHolder.getContext();
assert context != null;
final Object principal = context.getAuthentication().getPrincipal();
if (principal instanceof Jwt) {
return resolveAccountFromOAuthPrincipal((Jwt) principal);
} else {
final String username = context.getAuthentication().getName();
//TODO impersonalization?
return userDao.findByUsername(username).orElseThrow().copy();
}
}
public UserReference getCurrentUserReference() {
return new UserReference(getCurrentUser());
}

public static UserReference currentUserReference(){
return new UserReference(currentUser());
// TODO map role, but I am not sure which changes in the model when be required if I add addRole method to User
private User resolveAccountFromOAuthPrincipal(Jwt principal) {
final OidcUserInfo userInfo = new OidcUserInfo(principal.getClaims());
// final List<String> roles = new OidcGrantedAuthoritiesExtractor(config).extractRoles(principal);
// var user = userDao.findByUsername(userInfo.getPreferredUsername());
// roles.stream().map(r -> "ROLE_" + r).forEach(user::addRole);
return userDao.findByUsername(userInfo.getPreferredUsername()).orElseThrow(() -> EntityNotFoundException.create("User", userInfo.getPreferredUsername()));
}



/**
* Sets authentication to the current thread's security context.
* Sets the current security context to the user represented by the provided user details.
* <p>
* Note that this method erases credentials from the provided user details for security reasons.
* <p>
* This method should be used only when internal authentication is used.
*
* @param authentication Currently logged-in user's authentication
* @param userDetails User details
*/
public void setCurrentUser(Authentication authentication) {
public static AbstractAuthenticationToken setCurrentUser(UserDetails userDetails) {
final UsernamePasswordAuthenticationToken token =
UsernamePasswordAuthenticationToken.authenticated(userDetails, userDetails.getPassword(),
userDetails.getAuthorities());
token.setDetails(userDetails);
token.eraseCredentials(); // Do not pass credentials around

final SecurityContext context = new SecurityContextImpl();
context.setAuthentication(authentication);
context.setAuthentication(token);
SecurityContextHolder.setContext(context);
return token;
}

}
Expand Down

0 comments on commit faca007

Please sign in to comment.