This is the codeAbility Sharing Platform! Learn more about the codeAbility Sharing Platform.

Skip to content
Snippets Groups Projects
Commit 681470ee authored by Michael Breu's avatar Michael Breu :speech_balloon:
Browse files

Fixing Problem with Admin-Role assigned to OAuth2-User

parent 7546256c
Branches
Tags
2 merge requests!17Initial Merge to Prepare Release 1.0.0,!1Resolve "Metadaten konsolideren"
......@@ -4,6 +4,9 @@ import static org.springframework.http.MediaType.APPLICATION_FORM_URLENCODED_VAL
import java.net.URI;
import java.util.Collections;
import java.util.HashSet;
import java.util.Optional;
import java.util.Set;
import javax.servlet.DispatcherType;
......@@ -27,18 +30,25 @@ import org.springframework.security.config.annotation.web.configuration.WebSecur
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.oauth2.client.endpoint.DefaultAuthorizationCodeTokenResponseClient;
import org.springframework.security.oauth2.client.endpoint.OAuth2AccessTokenResponseClient;
import org.springframework.security.oauth2.client.endpoint.OAuth2AuthorizationCodeGrantRequest;
import org.springframework.security.oauth2.client.endpoint.OAuth2AuthorizationCodeGrantRequestEntityConverter;
import org.springframework.security.oauth2.client.oidc.userinfo.OidcUserRequest;
import org.springframework.security.oauth2.client.oidc.userinfo.OidcUserService;
import org.springframework.security.oauth2.client.registration.ClientRegistration;
import org.springframework.security.oauth2.client.userinfo.OAuth2UserService;
import org.springframework.security.oauth2.core.DelegatingOAuth2TokenValidator;
import org.springframework.security.oauth2.core.OAuth2TokenValidator;
import org.springframework.security.oauth2.core.endpoint.OAuth2AuthorizationExchange;
import org.springframework.security.oauth2.core.endpoint.OAuth2ParameterNames;
import org.springframework.security.oauth2.core.endpoint.PkceParameterNames;
import org.springframework.security.oauth2.core.oidc.user.DefaultOidcUser;
import org.springframework.security.oauth2.core.oidc.user.OidcUser;
import org.springframework.security.oauth2.jwt.Jwt;
import org.springframework.security.oauth2.jwt.JwtDecoder;
import org.springframework.security.oauth2.jwt.JwtDecoders;
......@@ -57,10 +67,15 @@ import org.springframework.web.filter.ForwardedHeaderFilter;
import org.springframework.web.util.UriComponentsBuilder;
import org.zalando.problem.spring.web.advice.security.SecurityProblemSupport;
import at.ac.uibk.gitsearch.domain.User;
import at.ac.uibk.gitsearch.security.AuthoritiesConstants;
import at.ac.uibk.gitsearch.security.jwt.JWTConfigurer;
import at.ac.uibk.gitsearch.security.jwt.TokenProvider;
import at.ac.uibk.gitsearch.security.oauth2.SavedRequestAwareAuthenticationSuccessHandlerWithJWTSupport;
import at.ac.uibk.gitsearch.security.oauth2.UserDetailsFetcher;
import at.ac.uibk.gitsearch.service.UserService;
import at.ac.uibk.gitsearch.service.dto.UserDTO;
import at.ac.uibk.gitsearch.service.mapper.UserMapper;
import io.github.jhipster.config.JHipsterProperties;
@EnableWebSecurity
......@@ -77,14 +92,18 @@ public class SecurityConfiguration extends WebSecurityConfigurerAdapter {
private final CorsFilter corsFilter;
private final SecurityProblemSupport problemSupport;
private UserDetailsFetcher userDetailsFetcher;
public SecurityConfiguration(TokenProvider tokenProvider, CorsFilter corsFilter,
UserDetailsFetcher userDetailsFetcher,
JHipsterProperties jHipsterProperties, SecurityProblemSupport problemSupport
) {
this.tokenProvider = tokenProvider;
this.corsFilter = corsFilter;
this.problemSupport = problemSupport;
this.jHipsterProperties = jHipsterProperties;
this.userDetailsFetcher = userDetailsFetcher;
}
@Bean
......@@ -153,6 +172,9 @@ public class SecurityConfiguration extends WebSecurityConfigurerAdapter {
.and()
.apply(securityConfigurerAdapter())
.and()
.oauth2Login(oauth2 -> oauth2
.userInfoEndpoint(userInfo -> userInfo
.oidcUserService(this.oidcUserService())))
.oauth2Login().successHandler(getAuthenticationSuccessHandler())
.and()
.oauth2ResourceServer() // .bearerTokenResolver(bearerTokenResolver)
......@@ -332,6 +354,65 @@ public class SecurityConfiguration extends WebSecurityConfigurerAdapter {
SavedRequestAwareAuthenticationSuccessHandlerWithJWTSupport successHandler = new SavedRequestAwareAuthenticationSuccessHandlerWithJWTSupport(tokenProvider);
return successHandler;
}
private OAuth2UserService<OidcUserRequest, OidcUser> oidcUserService() {
final OidcUserService delegate = new OidcUserService();
final Set<String> defaultAuthorities = new HashSet<String>();
defaultAuthorities.add(AuthoritiesConstants.USER);
final UserService userService = getApplicationContext().getBean(UserService.class);
final UserMapper userMapper = getApplicationContext().getBean(UserMapper.class);
return (userRequest) -> {
// Delegate to the default implementation for loading a user
OidcUser oidcUser = delegate.loadUser(userRequest);
Set<GrantedAuthority> mappedAuthorities = new HashSet<>();
mappedAuthorities.addAll(oidcUser.getAuthorities());
String email = oidcUser.getEmail();
Optional<User> userO = userService.getUserWithAuthoritiesByEmail(email);
if(userO.isPresent()) {
UserDTO userDto = userMapper.userToUserDTO(userO.get());
boolean hasChanged = userDetailsFetcher.updateUserDetails(userDto, oidcUser, userRequest.getAccessToken(), userRequest.getClientRegistration());
if (hasChanged)
userService.updateUser(userDto);
userO.get().getAuthorities()
.forEach(
auth -> {
if(mappedAuthorities.stream()
.filter(existingAuth -> existingAuth.getAuthority().equals(auth.getName()))
.findAny().isEmpty()) {
mappedAuthorities.add(new SimpleGrantedAuthority(auth.getName()));}
}
);
} else {
UserDTO u = new UserDTO();
u.setFirstName(oidcUser.getGivenName());
u.setLastName(oidcUser.getFamilyName());
u.setLogin(email);
u.setActivated(true);
u.setLastModifiedBy("system");
u.setCreatedDate(java.time.Instant.now());
u.setAuthorities(defaultAuthorities);
u.setEmail(oidcUser.getEmail());
@SuppressWarnings("unused")
boolean hasChanged = userDetailsFetcher.updateUserDetails(u, oidcUser, userRequest.getAccessToken(), userRequest.getClientRegistration());
userService.createUser(u);
}
oidcUser = new DefaultOidcUser(mappedAuthorities, oidcUser.getIdToken(), oidcUser.getUserInfo());
return oidcUser;
};
}
}
package at.ac.uibk.gitsearch.security.oauth2;
import java.util.HashSet;
import java.util.Optional;
import java.util.Set;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.event.EventListener;
import org.springframework.security.authentication.event.AbstractAuthenticationEvent;
import org.springframework.security.authentication.event.AuthenticationSuccessEvent;
import org.springframework.security.authentication.event.InteractiveAuthenticationSuccessEvent;
import org.springframework.security.oauth2.client.authentication.OAuth2LoginAuthenticationToken;
import org.springframework.security.oauth2.core.oidc.user.OidcUser;
import org.springframework.stereotype.Service;
import at.ac.uibk.gitsearch.domain.User;
import at.ac.uibk.gitsearch.security.AuthoritiesConstants;
import at.ac.uibk.gitsearch.security.jwt.TokenProvider;
import at.ac.uibk.gitsearch.service.UserService;
import at.ac.uibk.gitsearch.service.dto.UserDTO;
import at.ac.uibk.gitsearch.service.mapper.UserMapper;
/**
* inserts a new authenticated user into Database
* @author Michael Breu
*
*/
@Service
public class OAuth2AuthenticationSuccessEventHandler{
private final Set<String> defaultAuthorities = new HashSet<String>();
@Autowired
private UserDetailsFetcher userDetailsFetcher;
@Autowired
private UserMapper userMapper;
@Autowired
private TokenProvider tokenProvider;
public OAuth2AuthenticationSuccessEventHandler() {
defaultAuthorities.add(AuthoritiesConstants.USER);
}
@Autowired
private UserService userService;
@EventListener({AuthenticationSuccessEvent.class, InteractiveAuthenticationSuccessEvent.class})
public void processAuthenticationSuccessEvent(AbstractAuthenticationEvent e) {
if (!(e.getAuthentication() instanceof OAuth2LoginAuthenticationToken)) {
return;
}
// TODO find a better place to store user details for JWT Token
// remember OAuth2LoginAuthenticationToken in current Security Context
tokenProvider.rememberAccess((OAuth2LoginAuthenticationToken) e.getAuthentication());
Object principal = e.getAuthentication().getPrincipal();
if (principal instanceof OidcUser) {
OidcUser oidcUser = (OidcUser) principal;
String email = oidcUser.getEmail();
Optional<User> userO = userService.getUserWithAuthoritiesByEmail(email);
if(userO.isPresent()) {
UserDTO userDto = userMapper.userToUserDTO(userO.get());
boolean hasChanged = userDetailsFetcher.updateUserDetails(userDto, oidcUser, (OAuth2LoginAuthenticationToken) e.getAuthentication());
if (hasChanged)
userService.updateUser(userDto);
} else {
UserDTO u = new UserDTO();
u.setFirstName(oidcUser.getGivenName());
u.setLastName(oidcUser.getFamilyName());
u.setLogin(email);
u.setActivated(true);
u.setLastModifiedBy("system");
u.setCreatedDate(java.time.Instant.now());
u.setAuthorities(defaultAuthorities);
u.setEmail(oidcUser.getEmail());
@SuppressWarnings("unused")
boolean hasChanged = userDetailsFetcher.updateUserDetails(u, oidcUser, (OAuth2LoginAuthenticationToken) e.getAuthentication());
userService.createUser(u);
}
}
}
}
\ No newline at end of file
......@@ -10,7 +10,8 @@ import org.gitlab4j.api.GitLabApi;
import org.gitlab4j.api.GitLabApiException;
import org.gitlab4j.api.models.User;
import org.springframework.security.oauth2.client.authentication.OAuth2LoginAuthenticationToken;
import org.springframework.security.oauth2.client.registration.ClientRegistration.ProviderDetails;
import org.springframework.security.oauth2.client.registration.ClientRegistration;
import org.springframework.security.oauth2.core.OAuth2AccessToken;
import org.springframework.security.oauth2.core.oidc.user.OidcUser;
import org.springframework.stereotype.Component;
......@@ -27,29 +28,43 @@ public class UserDetailsFetcher {
/** fills in data from OIDC repository.
* returns true, if user data really changed **/
public boolean updateUserDetails(UserDTO u, OidcUser oidcUser, OAuth2LoginAuthenticationToken accessToken) {
String idToken = accessToken.getAccessToken().getTokenValue();
ProviderDetails providerDetails = accessToken.getClientRegistration().getProviderDetails();
String issuerURI = (String) providerDetails.getConfigurationMetadata().get("issuer");
try( GitLabApi gitLabApi = new GitLabApi(issuerURI, TokenType.OAUTH2_ACCESS, idToken)) {
boolean modified = false;
gitLabApi.enableRequestResponseLogging();
// List<Project> memberProjects = gitLabApi.getProjectApi().getMemberProjects();
User gitUser = gitLabApi.getUserApi().getCurrentUser();
modified |= updateAttribute(gitUser.getAvatarUrl(),u.getImageUrl(), u::setImageUrl);
modified |= updateAttribute(gitUser.getEmail(), u.getEmail(), u::setEmail);
modified |= updateAttribute(gitUser.getName(),u.getLastName(), u::setLastName);
// modified |= updateAttribute(gitUser.getUsername(),u.getLogin(), u::setLogin);
if (modified) u.setLastModifiedDate(Instant.now());
// testMetaDataGenerator.generateTestData(gitLabApi, issuerURI, idToken);
return modified;
} catch (GitLabApiException e) {
logger.warn("Cannot fetch details for user {}", oidcUser.getName(), e);
}
return false;
public boolean updateUserDetails(UserDTO u, OidcUser oidcUser, OAuth2LoginAuthenticationToken oAuth2LoginAuthenticationToken) {
final OAuth2AccessToken accessToken = oAuth2LoginAuthenticationToken.getAccessToken();
final ClientRegistration clientRegistration = oAuth2LoginAuthenticationToken.getClientRegistration();
return updateUserDetails(u, oidcUser, accessToken, clientRegistration);
}
/**
* fills in date from OIDC repository
* @param u
* @param oidcUser
* @param accessToken
* @param clientRegistration
* @return
*/
public boolean updateUserDetails(UserDTO u, OidcUser oidcUser, final OAuth2AccessToken accessToken,
final ClientRegistration clientRegistration) {
String idToken = accessToken.getTokenValue();
String issuerURI = (String) clientRegistration.getProviderDetails().getConfigurationMetadata().get("issuer");
try( GitLabApi gitLabApi = new GitLabApi(issuerURI, TokenType.OAUTH2_ACCESS, idToken)) {
boolean modified = false;
gitLabApi.enableRequestResponseLogging();
// List<Project> memberProjects = gitLabApi.getProjectApi().getMemberProjects();
User gitUser = gitLabApi.getUserApi().getCurrentUser();
modified |= updateAttribute(gitUser.getAvatarUrl(),u.getImageUrl(), u::setImageUrl);
modified |= updateAttribute(gitUser.getEmail(), u.getEmail(), u::setEmail);
modified |= updateAttribute(gitUser.getName(),u.getLastName(), u::setLastName);
// modified |= updateAttribute(gitUser.getUsername(),u.getLogin(), u::setLogin);
if (modified) u.setLastModifiedDate(Instant.now());
// testMetaDataGenerator.generateTestData(gitLabApi, issuerURI, idToken);
return modified;
} catch (GitLabApiException e) {
logger.warn("Cannot fetch details for user {}", oidcUser.getName(), e);
}
return false;
}
private static boolean updateAttribute (String newString, String oldString, Consumer<String> setter) {
......
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment