Sonar issues from PR #865 fixed
Signed-off-by: Dominic Schabel <dominic.schabel@bosch-si.com>
This commit is contained in:
@@ -8,6 +8,22 @@
|
|||||||
*/
|
*/
|
||||||
package org.eclipse.hawkbit.autoconfigure.security;
|
package org.eclipse.hawkbit.autoconfigure.security;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.LinkedHashSet;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
import javax.servlet.Filter;
|
||||||
|
import javax.servlet.FilterChain;
|
||||||
|
import javax.servlet.FilterConfig;
|
||||||
|
import javax.servlet.ServletException;
|
||||||
|
import javax.servlet.ServletRequest;
|
||||||
|
import javax.servlet.ServletResponse;
|
||||||
|
import javax.servlet.http.HttpServletRequest;
|
||||||
|
import javax.servlet.http.HttpServletResponse;
|
||||||
|
|
||||||
import org.eclipse.hawkbit.im.authentication.TenantAwareAuthenticationDetails;
|
import org.eclipse.hawkbit.im.authentication.TenantAwareAuthenticationDetails;
|
||||||
import org.eclipse.hawkbit.im.authentication.UserAuthenticationFilter;
|
import org.eclipse.hawkbit.im.authentication.UserAuthenticationFilter;
|
||||||
import org.eclipse.hawkbit.repository.SystemManagement;
|
import org.eclipse.hawkbit.repository.SystemManagement;
|
||||||
@@ -18,7 +34,7 @@ import org.springframework.boot.autoconfigure.security.oauth2.client.ClientsConf
|
|||||||
import org.springframework.context.annotation.Bean;
|
import org.springframework.context.annotation.Bean;
|
||||||
import org.springframework.context.annotation.Conditional;
|
import org.springframework.context.annotation.Conditional;
|
||||||
import org.springframework.context.annotation.Configuration;
|
import org.springframework.context.annotation.Configuration;
|
||||||
import org.springframework.security.authentication.*;
|
import org.springframework.security.authentication.AbstractAuthenticationToken;
|
||||||
import org.springframework.security.core.Authentication;
|
import org.springframework.security.core.Authentication;
|
||||||
import org.springframework.security.core.GrantedAuthority;
|
import org.springframework.security.core.GrantedAuthority;
|
||||||
import org.springframework.security.core.authority.AuthorityUtils;
|
import org.springframework.security.core.authority.AuthorityUtils;
|
||||||
@@ -42,7 +58,8 @@ import org.springframework.security.oauth2.jwt.JwtDecoder;
|
|||||||
import org.springframework.security.oauth2.jwt.JwtException;
|
import org.springframework.security.oauth2.jwt.JwtException;
|
||||||
import org.springframework.security.oauth2.jwt.NimbusJwtDecoderJwkSupport;
|
import org.springframework.security.oauth2.jwt.NimbusJwtDecoderJwkSupport;
|
||||||
import org.springframework.security.oauth2.server.resource.authentication.JwtAuthenticationToken;
|
import org.springframework.security.oauth2.server.resource.authentication.JwtAuthenticationToken;
|
||||||
import org.springframework.security.web.authentication.*;
|
import org.springframework.security.web.authentication.AuthenticationSuccessHandler;
|
||||||
|
import org.springframework.security.web.authentication.SavedRequestAwareAuthenticationSuccessHandler;
|
||||||
import org.springframework.security.web.authentication.logout.LogoutHandler;
|
import org.springframework.security.web.authentication.logout.LogoutHandler;
|
||||||
import org.springframework.security.web.authentication.logout.SecurityContextLogoutHandler;
|
import org.springframework.security.web.authentication.logout.SecurityContextLogoutHandler;
|
||||||
import org.springframework.util.CollectionUtils;
|
import org.springframework.util.CollectionUtils;
|
||||||
@@ -50,17 +67,6 @@ import org.springframework.util.StringUtils;
|
|||||||
import org.springframework.web.client.RestTemplate;
|
import org.springframework.web.client.RestTemplate;
|
||||||
import org.springframework.web.util.UriComponentsBuilder;
|
import org.springframework.web.util.UriComponentsBuilder;
|
||||||
|
|
||||||
import javax.servlet.*;
|
|
||||||
import javax.servlet.http.HttpServletRequest;
|
|
||||||
import javax.servlet.http.HttpServletResponse;
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.util.Collection;
|
|
||||||
import java.util.Collections;
|
|
||||||
import java.util.LinkedHashSet;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.Map;
|
|
||||||
import java.util.Set;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Auto-configuration for OpenID Connect user management.
|
* Auto-configuration for OpenID Connect user management.
|
||||||
*
|
*
|
||||||
@@ -75,7 +81,8 @@ public class OidcUserManagementAutoConfiguration {
|
|||||||
*/
|
*/
|
||||||
@Bean
|
@Bean
|
||||||
@ConditionalOnMissingBean
|
@ConditionalOnMissingBean
|
||||||
public OAuth2UserService<OidcUserRequest, OidcUser> oidcUserDetailsService(JwtAuthoritiesExtractor extractor) {
|
public OAuth2UserService<OidcUserRequest, OidcUser> oidcUserDetailsService(
|
||||||
|
final JwtAuthoritiesExtractor extractor) {
|
||||||
return new JwtAuthoritiesOidcUserService(extractor);
|
return new JwtAuthoritiesOidcUserService(extractor);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -98,7 +105,8 @@ public class OidcUserManagementAutoConfiguration {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return a jwt authorities extractor which interprets the roles of a user as their authorities.
|
* @return a jwt authorities extractor which interprets the roles of a user
|
||||||
|
* as their authorities.
|
||||||
*/
|
*/
|
||||||
@Bean
|
@Bean
|
||||||
@ConditionalOnMissingBean
|
@ConditionalOnMissingBean
|
||||||
@@ -127,24 +135,24 @@ class JwtAuthoritiesOidcUserService extends OidcUserService {
|
|||||||
|
|
||||||
private final JwtAuthoritiesExtractor authoritiesExtractor;
|
private final JwtAuthoritiesExtractor authoritiesExtractor;
|
||||||
|
|
||||||
JwtAuthoritiesOidcUserService(JwtAuthoritiesExtractor authoritiesExtractor) {
|
JwtAuthoritiesOidcUserService(final JwtAuthoritiesExtractor authoritiesExtractor) {
|
||||||
super();
|
super();
|
||||||
|
|
||||||
this.authoritiesExtractor = authoritiesExtractor;
|
this.authoritiesExtractor = authoritiesExtractor;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public OidcUser loadUser(OidcUserRequest userRequest) {
|
public OidcUser loadUser(final OidcUserRequest userRequest) {
|
||||||
OidcUser user = super.loadUser(userRequest);
|
final OidcUser user = super.loadUser(userRequest);
|
||||||
ClientRegistration clientRegistration = userRequest.getClientRegistration();
|
final ClientRegistration clientRegistration = userRequest.getClientRegistration();
|
||||||
|
|
||||||
Set<GrantedAuthority> authorities = new LinkedHashSet<>(authoritiesExtractor.extract(clientRegistration,
|
final Set<GrantedAuthority> authorities = authoritiesExtractor.extract(clientRegistration,
|
||||||
userRequest.getAccessToken().getTokenValue()));
|
userRequest.getAccessToken().getTokenValue());
|
||||||
if (authorities.isEmpty()) {
|
if (authorities.isEmpty()) {
|
||||||
return user;
|
return user;
|
||||||
}
|
}
|
||||||
|
|
||||||
String userNameAttributeName = clientRegistration.getProviderDetails().getUserInfoEndpoint()
|
final String userNameAttributeName = clientRegistration.getProviderDetails().getUserInfoEndpoint()
|
||||||
.getUserNameAttributeName();
|
.getUserNameAttributeName();
|
||||||
OidcUser oidcUser;
|
OidcUser oidcUser;
|
||||||
if (StringUtils.hasText(userNameAttributeName)) {
|
if (StringUtils.hasText(userNameAttributeName)) {
|
||||||
@@ -169,12 +177,12 @@ class OidcAuthenticationSuccessHandler extends SavedRequestAwareAuthenticationSu
|
|||||||
private SystemSecurityContext systemSecurityContext;
|
private SystemSecurityContext systemSecurityContext;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response,
|
public void onAuthenticationSuccess(final HttpServletRequest request, final HttpServletResponse response,
|
||||||
Authentication authentication) throws ServletException, IOException {
|
final Authentication authentication) throws ServletException, IOException {
|
||||||
if (authentication instanceof AbstractAuthenticationToken) {
|
if (authentication instanceof AbstractAuthenticationToken) {
|
||||||
final String defaultTenant = "DEFAULT";
|
final String defaultTenant = "DEFAULT";
|
||||||
|
|
||||||
AbstractAuthenticationToken token = (AbstractAuthenticationToken) authentication;
|
final AbstractAuthenticationToken token = (AbstractAuthenticationToken) authentication;
|
||||||
token.setDetails(new TenantAwareAuthenticationDetails(defaultTenant, false));
|
token.setDetails(new TenantAwareAuthenticationDetails(defaultTenant, false));
|
||||||
|
|
||||||
systemSecurityContext.runAsSystemAsTenant(systemManagement::getTenantMetadata, defaultTenant);
|
systemSecurityContext.runAsSystemAsTenant(systemManagement::getTenantMetadata, defaultTenant);
|
||||||
@@ -190,25 +198,27 @@ class OidcAuthenticationSuccessHandler extends SavedRequestAwareAuthenticationSu
|
|||||||
class OidcLogoutHandler extends SecurityContextLogoutHandler {
|
class OidcLogoutHandler extends SecurityContextLogoutHandler {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void logout(HttpServletRequest request, HttpServletResponse response, Authentication authentication) {
|
public void logout(final HttpServletRequest request, final HttpServletResponse response,
|
||||||
|
final Authentication authentication) {
|
||||||
super.logout(request, response, authentication);
|
super.logout(request, response, authentication);
|
||||||
|
|
||||||
Object principal = authentication.getPrincipal();
|
final Object principal = authentication.getPrincipal();
|
||||||
if (principal instanceof OidcUser) {
|
if (principal instanceof OidcUser) {
|
||||||
OidcUser user = (OidcUser) authentication.getPrincipal();
|
final OidcUser user = (OidcUser) authentication.getPrincipal();
|
||||||
String endSessionEndpoint = user.getIssuer() + "/protocol/openid-connect/logout";
|
final String endSessionEndpoint = user.getIssuer() + "/protocol/openid-connect/logout";
|
||||||
|
|
||||||
UriComponentsBuilder builder = UriComponentsBuilder.fromUriString(endSessionEndpoint)
|
final UriComponentsBuilder builder = UriComponentsBuilder.fromUriString(endSessionEndpoint)
|
||||||
.queryParam("id_token_hint", user.getIdToken().getTokenValue());
|
.queryParam("id_token_hint", user.getIdToken().getTokenValue());
|
||||||
|
|
||||||
RestTemplate restTemplate = new RestTemplate();
|
final RestTemplate restTemplate = new RestTemplate();
|
||||||
restTemplate.getForEntity(builder.toUriString(), String.class);
|
restTemplate.getForEntity(builder.toUriString(), String.class);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Utility class to extract authorities out of the jwt. It interprets the user's role as their authorities.
|
* Utility class to extract authorities out of the jwt. It interprets the user's
|
||||||
|
* role as their authorities.
|
||||||
*/
|
*/
|
||||||
class JwtAuthoritiesExtractor {
|
class JwtAuthoritiesExtractor {
|
||||||
|
|
||||||
@@ -216,50 +226,46 @@ class JwtAuthoritiesExtractor {
|
|||||||
|
|
||||||
private static final OAuth2Error INVALID_REQUEST = new OAuth2Error(OAuth2ErrorCodes.INVALID_REQUEST);
|
private static final OAuth2Error INVALID_REQUEST = new OAuth2Error(OAuth2ErrorCodes.INVALID_REQUEST);
|
||||||
|
|
||||||
JwtAuthoritiesExtractor(GrantedAuthoritiesMapper authoritiesMapper) {
|
JwtAuthoritiesExtractor(final GrantedAuthoritiesMapper authoritiesMapper) {
|
||||||
super();
|
super();
|
||||||
|
|
||||||
this.authoritiesMapper = authoritiesMapper;
|
this.authoritiesMapper = authoritiesMapper;
|
||||||
}
|
}
|
||||||
|
|
||||||
Collection<? extends GrantedAuthority> extract(ClientRegistration clientRegistration,
|
Set<GrantedAuthority> extract(final ClientRegistration clientRegistration, final String tokenValue) {
|
||||||
String tokenValue) {
|
|
||||||
Jwt token;
|
|
||||||
try {
|
try {
|
||||||
// Token is already verified by spring security
|
// Token is already verified by spring security
|
||||||
JwtDecoder jwtDecoder = new NimbusJwtDecoderJwkSupport(
|
final JwtDecoder jwtDecoder = new NimbusJwtDecoderJwkSupport(
|
||||||
clientRegistration.getProviderDetails().getJwkSetUri());
|
clientRegistration.getProviderDetails().getJwkSetUri());
|
||||||
token = jwtDecoder.decode(tokenValue);
|
final Jwt token = jwtDecoder.decode(tokenValue);
|
||||||
} catch (JwtException e) {
|
|
||||||
|
return extract(clientRegistration.getClientId(), token.getClaims());
|
||||||
|
} catch (final JwtException e) {
|
||||||
throw new OAuth2AuthenticationException(INVALID_REQUEST, e);
|
throw new OAuth2AuthenticationException(INVALID_REQUEST, e);
|
||||||
}
|
}
|
||||||
|
|
||||||
return extract(clientRegistration.getClientId(), token.getClaims());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Collection<? extends GrantedAuthority> extract(String clientId, Map<String, Object> claims) {
|
@SuppressWarnings("unchecked")
|
||||||
@SuppressWarnings("unchecked")
|
Set<GrantedAuthority> extract(final String clientId, final Map<String, Object> claims) {
|
||||||
Map<String, Object> resourceMap = (Map<String, Object>) claims.get("resource_access");
|
final Map<String, Object> resourceMap = (Map<String, Object>) claims.get("resource_access");
|
||||||
|
|
||||||
@SuppressWarnings("unchecked")
|
final Map<String, Map<String, Object>> clientResource = (Map<String, Map<String, Object>>) resourceMap
|
||||||
Map<String, Map<String, Object>> clientResource = (Map<String, Map<String, Object>>) resourceMap.get(clientId);
|
.get(clientId);
|
||||||
if (CollectionUtils.isEmpty(clientResource)) {
|
if (CollectionUtils.isEmpty(clientResource)) {
|
||||||
return Collections.emptyList();
|
return Collections.emptySet();
|
||||||
}
|
}
|
||||||
|
|
||||||
@SuppressWarnings("unchecked")
|
final List<String> roles = (List<String>) clientResource.get("roles");
|
||||||
List<String> roles = (List<String>) clientResource.get("roles");
|
|
||||||
if (CollectionUtils.isEmpty(roles)) {
|
if (CollectionUtils.isEmpty(roles)) {
|
||||||
return Collections.emptyList();
|
return Collections.emptySet();
|
||||||
}
|
}
|
||||||
|
|
||||||
Collection<? extends GrantedAuthority> authorities = AuthorityUtils
|
final List<GrantedAuthority> authorities = AuthorityUtils.createAuthorityList(roles.toArray(new String[0]));
|
||||||
.createAuthorityList(roles.toArray(new String[0]));
|
|
||||||
if (authoritiesMapper != null) {
|
if (authoritiesMapper != null) {
|
||||||
authorities = authoritiesMapper.mapAuthorities(authorities);
|
return new LinkedHashSet<>(authoritiesMapper.mapAuthorities(authorities));
|
||||||
}
|
}
|
||||||
|
|
||||||
return authorities;
|
return new LinkedHashSet<>(authorities);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -276,40 +282,36 @@ class OidcBearerTokenAuthenticationFilter implements UserAuthenticationFilter, F
|
|||||||
|
|
||||||
private ClientRegistration clientRegistration;
|
private ClientRegistration clientRegistration;
|
||||||
|
|
||||||
void setClientRegistration(ClientRegistration clientRegistration) {
|
void setClientRegistration(final ClientRegistration clientRegistration) {
|
||||||
this.clientRegistration = clientRegistration;
|
this.clientRegistration = clientRegistration;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public void init(final FilterConfig filterConfig) {
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void doFilter(final ServletRequest request, final ServletResponse response, final FilterChain chain)
|
public void doFilter(final ServletRequest request, final ServletResponse response, final FilterChain chain)
|
||||||
throws IOException, ServletException {
|
throws IOException, ServletException {
|
||||||
|
|
||||||
Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
|
final Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
|
||||||
if (authentication instanceof JwtAuthenticationToken) {
|
if (authentication instanceof JwtAuthenticationToken) {
|
||||||
final String defaultTenant = "DEFAULT";
|
final String defaultTenant = "DEFAULT";
|
||||||
|
|
||||||
JwtAuthenticationToken jwtAuthenticationToken = (JwtAuthenticationToken) authentication;
|
final JwtAuthenticationToken jwtAuthenticationToken = (JwtAuthenticationToken) authentication;
|
||||||
Jwt jwt = jwtAuthenticationToken.getToken();
|
final Jwt jwt = jwtAuthenticationToken.getToken();
|
||||||
OidcIdToken idToken = new OidcIdToken(jwt.getTokenValue(), jwt.getIssuedAt(), jwt.getExpiresAt(),
|
final OidcIdToken idToken = new OidcIdToken(jwt.getTokenValue(), jwt.getIssuedAt(), jwt.getExpiresAt(),
|
||||||
jwt.getClaims());
|
jwt.getClaims());
|
||||||
OidcUserInfo userInfo = new OidcUserInfo(jwt.getClaims());
|
final OidcUserInfo userInfo = new OidcUserInfo(jwt.getClaims());
|
||||||
|
|
||||||
Collection<? extends GrantedAuthority> authorities = authoritiesExtractor.extract(
|
final Set<GrantedAuthority> authorities = authoritiesExtractor.extract(clientRegistration.getClientId(),
|
||||||
clientRegistration.getClientId(), jwt.getClaims());
|
jwt.getClaims());
|
||||||
|
|
||||||
if (authorities.isEmpty()) {
|
if (authorities.isEmpty()) {
|
||||||
((HttpServletResponse) response).sendError(HttpServletResponse.SC_FORBIDDEN);
|
((HttpServletResponse) response).sendError(HttpServletResponse.SC_FORBIDDEN);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
DefaultOidcUser user = new DefaultOidcUser(authorities, idToken, userInfo);
|
final DefaultOidcUser user = new DefaultOidcUser(authorities, idToken, userInfo);
|
||||||
|
|
||||||
OAuth2AuthenticationToken oAuth2AuthenticationToken = new OAuth2AuthenticationToken(
|
final OAuth2AuthenticationToken oAuth2AuthenticationToken = new OAuth2AuthenticationToken(user, authorities,
|
||||||
user, authorities, clientRegistration.getRegistrationId());
|
clientRegistration.getRegistrationId());
|
||||||
|
|
||||||
oAuth2AuthenticationToken.setDetails(new TenantAwareAuthenticationDetails(defaultTenant, false));
|
oAuth2AuthenticationToken.setDetails(new TenantAwareAuthenticationDetails(defaultTenant, false));
|
||||||
|
|
||||||
@@ -320,7 +322,13 @@ class OidcBearerTokenAuthenticationFilter implements UserAuthenticationFilter, F
|
|||||||
chain.doFilter(request, response);
|
chain.doFilter(request, response);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void init(final FilterConfig filterConfig) {
|
||||||
|
// Nothing to do
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void destroy() {
|
public void destroy() {
|
||||||
|
// Nothing to do
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user