OpenID Connect support (#865)
* Added OpenID Connect support Utilized Spring Security's OAuth2 respectively OIDC support as another possibility to manage users and their permissions. Signed-off-by: Brandon Schmitt <Brandon.Schmitt@kiwigrid.com> * Document OpenID Connect Support Signed-off-by: Brandon Schmitt <Brandon.Schmitt@kiwigrid.com> * Updated license in OidcUserManagementAutoConfiguration.java Signed-off-by: Brandon Schmitt <Brandon.Schmitt@kiwigrid.com> * Revert updated license notice and add Kiwigrid license file This reverts commit 23d36245 Signed-off-by: Brandon Schmitt <Brandon.Schmitt@kiwigrid.com> * Resolve SonarQube issues - Explicitly import the needed specific classes - Document public methods - Add `static` to the constant `JwtAuthoritiesOidcUserService.INVALID_REQUEST` - Remove superfluous runtime exception `OAuth2AuthenticationException` Signed-off-by: Brandon Schmitt <Brandon.Schmitt@kiwigrid.com> * Add OidcUser support in SpringSecurityAuditorAware Signed-off-by: Brandon Schmitt <Brandon.Schmitt@kiwigrid.com> * Secure Management API using OpenID Connect, too. Signed-off-by: Brandon Schmitt <Brandon.Schmitt@kiwigrid.com>
This commit is contained in:
committed by
Dominic Schabel
parent
38017ba7bc
commit
1bcced9838
@@ -0,0 +1,326 @@
|
||||
/**
|
||||
* Copyright (c) 2019 Kiwigrid GmbH and others.
|
||||
*
|
||||
* All rights reserved. This program and the accompanying materials
|
||||
* are made available under the terms of the Eclipse Public License v1.0
|
||||
* which accompanies this distribution, and is available at
|
||||
* http://www.eclipse.org/legal/epl-v10.html
|
||||
*/
|
||||
package org.eclipse.hawkbit.autoconfigure.security;
|
||||
|
||||
import org.eclipse.hawkbit.im.authentication.TenantAwareAuthenticationDetails;
|
||||
import org.eclipse.hawkbit.im.authentication.UserAuthenticationFilter;
|
||||
import org.eclipse.hawkbit.repository.SystemManagement;
|
||||
import org.eclipse.hawkbit.security.SystemSecurityContext;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
|
||||
import org.springframework.boot.autoconfigure.security.oauth2.client.ClientsConfiguredCondition;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Conditional;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.security.authentication.*;
|
||||
import org.springframework.security.core.Authentication;
|
||||
import org.springframework.security.core.GrantedAuthority;
|
||||
import org.springframework.security.core.authority.AuthorityUtils;
|
||||
import org.springframework.security.core.authority.mapping.GrantedAuthoritiesMapper;
|
||||
import org.springframework.security.core.authority.mapping.SimpleAuthorityMapper;
|
||||
import org.springframework.security.core.context.SecurityContextHolder;
|
||||
import org.springframework.security.oauth2.client.authentication.OAuth2AuthenticationToken;
|
||||
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.OAuth2AuthenticationException;
|
||||
import org.springframework.security.oauth2.core.OAuth2Error;
|
||||
import org.springframework.security.oauth2.core.OAuth2ErrorCodes;
|
||||
import org.springframework.security.oauth2.core.oidc.OidcIdToken;
|
||||
import org.springframework.security.oauth2.core.oidc.OidcUserInfo;
|
||||
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.JwtException;
|
||||
import org.springframework.security.oauth2.jwt.NimbusJwtDecoderJwkSupport;
|
||||
import org.springframework.security.oauth2.server.resource.authentication.JwtAuthenticationToken;
|
||||
import org.springframework.security.web.authentication.*;
|
||||
import org.springframework.security.web.authentication.logout.LogoutHandler;
|
||||
import org.springframework.security.web.authentication.logout.SecurityContextLogoutHandler;
|
||||
import org.springframework.util.CollectionUtils;
|
||||
import org.springframework.util.StringUtils;
|
||||
import org.springframework.web.client.RestTemplate;
|
||||
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.
|
||||
*
|
||||
*/
|
||||
@Configuration
|
||||
@Conditional(value = ClientsConfiguredCondition.class)
|
||||
public class OidcUserManagementAutoConfiguration {
|
||||
|
||||
/**
|
||||
* @return the oauth2 user details service to load a user from oidc user
|
||||
* manager
|
||||
*/
|
||||
@Bean
|
||||
@ConditionalOnMissingBean
|
||||
public OAuth2UserService<OidcUserRequest, OidcUser> oidcUserDetailsService(JwtAuthoritiesExtractor extractor) {
|
||||
return new JwtAuthoritiesOidcUserService(extractor);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the OpenID Connect authentication success handler
|
||||
*/
|
||||
@Bean
|
||||
@ConditionalOnMissingBean
|
||||
public AuthenticationSuccessHandler oidcAuthenticationSuccessHandler() {
|
||||
return new OidcAuthenticationSuccessHandler();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the OpenID Connect logout handler
|
||||
*/
|
||||
@Bean
|
||||
@ConditionalOnMissingBean
|
||||
public LogoutHandler oidcLogoutHandler() {
|
||||
return new OidcLogoutHandler();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return a jwt authorities extractor which interprets the roles of a user as their authorities.
|
||||
*/
|
||||
@Bean
|
||||
@ConditionalOnMissingBean
|
||||
public JwtAuthoritiesExtractor jwtAuthoritiesExtractor() {
|
||||
final SimpleAuthorityMapper authorityMapper = new SimpleAuthorityMapper();
|
||||
authorityMapper.setPrefix("");
|
||||
authorityMapper.setConvertToUpperCase(true);
|
||||
|
||||
return new JwtAuthoritiesExtractor(authorityMapper);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return an authentication filter for using OAuth2 Bearer Tokens.
|
||||
*/
|
||||
@Bean
|
||||
@ConditionalOnMissingBean
|
||||
public OidcBearerTokenAuthenticationFilter oidcBearerTokenAuthenticationFilter() {
|
||||
return new OidcBearerTokenAuthenticationFilter();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Extended {@link OidcUserService} supporting JWT containing authorities
|
||||
*/
|
||||
class JwtAuthoritiesOidcUserService extends OidcUserService {
|
||||
|
||||
private final JwtAuthoritiesExtractor authoritiesExtractor;
|
||||
|
||||
JwtAuthoritiesOidcUserService(JwtAuthoritiesExtractor authoritiesExtractor) {
|
||||
super();
|
||||
|
||||
this.authoritiesExtractor = authoritiesExtractor;
|
||||
}
|
||||
|
||||
@Override
|
||||
public OidcUser loadUser(OidcUserRequest userRequest) {
|
||||
OidcUser user = super.loadUser(userRequest);
|
||||
ClientRegistration clientRegistration = userRequest.getClientRegistration();
|
||||
|
||||
Set<GrantedAuthority> authorities = new LinkedHashSet<>(authoritiesExtractor.extract(clientRegistration,
|
||||
userRequest.getAccessToken().getTokenValue()));
|
||||
if (authorities.isEmpty()) {
|
||||
return user;
|
||||
}
|
||||
|
||||
String userNameAttributeName = clientRegistration.getProviderDetails().getUserInfoEndpoint()
|
||||
.getUserNameAttributeName();
|
||||
OidcUser oidcUser;
|
||||
if (StringUtils.hasText(userNameAttributeName)) {
|
||||
oidcUser = new DefaultOidcUser(authorities, userRequest.getIdToken(), user.getUserInfo(),
|
||||
userNameAttributeName);
|
||||
} else {
|
||||
oidcUser = new DefaultOidcUser(authorities, userRequest.getIdToken(), user.getUserInfo());
|
||||
}
|
||||
return oidcUser;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* OpenID Connect Authentication Success Handler which load tenant data
|
||||
*/
|
||||
class OidcAuthenticationSuccessHandler extends SavedRequestAwareAuthenticationSuccessHandler {
|
||||
|
||||
@Autowired
|
||||
private SystemManagement systemManagement;
|
||||
|
||||
@Autowired
|
||||
private SystemSecurityContext systemSecurityContext;
|
||||
|
||||
@Override
|
||||
public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response,
|
||||
Authentication authentication) throws ServletException, IOException {
|
||||
if (authentication instanceof AbstractAuthenticationToken) {
|
||||
final String defaultTenant = "DEFAULT";
|
||||
|
||||
AbstractAuthenticationToken token = (AbstractAuthenticationToken) authentication;
|
||||
token.setDetails(new TenantAwareAuthenticationDetails(defaultTenant, false));
|
||||
|
||||
systemSecurityContext.runAsSystemAsTenant(systemManagement::getTenantMetadata, defaultTenant);
|
||||
}
|
||||
|
||||
super.onAuthenticationSuccess(request, response, authentication);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* LogoutHandler to invalidate OpenID Connect tokens
|
||||
*/
|
||||
class OidcLogoutHandler extends SecurityContextLogoutHandler {
|
||||
|
||||
@Override
|
||||
public void logout(HttpServletRequest request, HttpServletResponse response, Authentication authentication) {
|
||||
super.logout(request, response, authentication);
|
||||
|
||||
Object principal = authentication.getPrincipal();
|
||||
if (principal instanceof OidcUser) {
|
||||
OidcUser user = (OidcUser) authentication.getPrincipal();
|
||||
String endSessionEndpoint = user.getIssuer() + "/protocol/openid-connect/logout";
|
||||
|
||||
UriComponentsBuilder builder = UriComponentsBuilder.fromUriString(endSessionEndpoint)
|
||||
.queryParam("id_token_hint", user.getIdToken().getTokenValue());
|
||||
|
||||
RestTemplate restTemplate = new RestTemplate();
|
||||
restTemplate.getForEntity(builder.toUriString(), String.class);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Utility class to extract authorities out of the jwt. It interprets the user's role as their authorities.
|
||||
*/
|
||||
class JwtAuthoritiesExtractor {
|
||||
|
||||
private final GrantedAuthoritiesMapper authoritiesMapper;
|
||||
|
||||
private static final OAuth2Error INVALID_REQUEST = new OAuth2Error(OAuth2ErrorCodes.INVALID_REQUEST);
|
||||
|
||||
JwtAuthoritiesExtractor(GrantedAuthoritiesMapper authoritiesMapper) {
|
||||
super();
|
||||
|
||||
this.authoritiesMapper = authoritiesMapper;
|
||||
}
|
||||
|
||||
Collection<? extends GrantedAuthority> extract(ClientRegistration clientRegistration,
|
||||
String tokenValue) {
|
||||
Jwt token;
|
||||
try {
|
||||
// Token is already verified by spring security
|
||||
JwtDecoder jwtDecoder = new NimbusJwtDecoderJwkSupport(
|
||||
clientRegistration.getProviderDetails().getJwkSetUri());
|
||||
token = jwtDecoder.decode(tokenValue);
|
||||
} catch (JwtException 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")
|
||||
Map<String, Object> resourceMap = (Map<String, Object>) claims.get("resource_access");
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
Map<String, Map<String, Object>> clientResource = (Map<String, Map<String, Object>>) resourceMap.get(clientId);
|
||||
if (CollectionUtils.isEmpty(clientResource)) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
List<String> roles = (List<String>) clientResource.get("roles");
|
||||
if (CollectionUtils.isEmpty(roles)) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
Collection<? extends GrantedAuthority> authorities = AuthorityUtils
|
||||
.createAuthorityList(roles.toArray(new String[0]));
|
||||
if (authoritiesMapper != null) {
|
||||
authorities = authoritiesMapper.mapAuthorities(authorities);
|
||||
}
|
||||
|
||||
return authorities;
|
||||
}
|
||||
}
|
||||
|
||||
class OidcBearerTokenAuthenticationFilter implements UserAuthenticationFilter, Filter {
|
||||
|
||||
@Autowired
|
||||
private JwtAuthoritiesExtractor authoritiesExtractor;
|
||||
|
||||
@Autowired
|
||||
private SystemManagement systemManagement;
|
||||
|
||||
@Autowired
|
||||
private SystemSecurityContext systemSecurityContext;
|
||||
|
||||
private ClientRegistration clientRegistration;
|
||||
|
||||
void setClientRegistration(ClientRegistration clientRegistration) {
|
||||
this.clientRegistration = clientRegistration;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void init(final FilterConfig filterConfig) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void doFilter(final ServletRequest request, final ServletResponse response, final FilterChain chain)
|
||||
throws IOException, ServletException {
|
||||
|
||||
Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
|
||||
if (authentication instanceof JwtAuthenticationToken) {
|
||||
final String defaultTenant = "DEFAULT";
|
||||
|
||||
JwtAuthenticationToken jwtAuthenticationToken = (JwtAuthenticationToken) authentication;
|
||||
Jwt jwt = jwtAuthenticationToken.getToken();
|
||||
OidcIdToken idToken = new OidcIdToken(jwt.getTokenValue(), jwt.getIssuedAt(), jwt.getExpiresAt(),
|
||||
jwt.getClaims());
|
||||
OidcUserInfo userInfo = new OidcUserInfo(jwt.getClaims());
|
||||
|
||||
Collection<? extends GrantedAuthority> authorities = authoritiesExtractor.extract(
|
||||
clientRegistration.getClientId(), jwt.getClaims());
|
||||
|
||||
if (authorities.isEmpty()) {
|
||||
((HttpServletResponse) response).sendError(HttpServletResponse.SC_FORBIDDEN);
|
||||
return;
|
||||
}
|
||||
|
||||
DefaultOidcUser user = new DefaultOidcUser(authorities, idToken, userInfo);
|
||||
|
||||
OAuth2AuthenticationToken oAuth2AuthenticationToken = new OAuth2AuthenticationToken(
|
||||
user, authorities, clientRegistration.getRegistrationId());
|
||||
|
||||
oAuth2AuthenticationToken.setDetails(new TenantAwareAuthenticationDetails(defaultTenant, false));
|
||||
|
||||
systemSecurityContext.runAsSystemAsTenant(systemManagement::getTenantMetadata, defaultTenant);
|
||||
SecurityContextHolder.getContext().setAuthentication(oAuth2AuthenticationToken);
|
||||
}
|
||||
|
||||
chain.doFilter(request, response);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void destroy() {
|
||||
}
|
||||
}
|
||||
@@ -75,15 +75,24 @@ import org.springframework.security.config.http.SessionCreationPolicy;
|
||||
import org.springframework.security.core.Authentication;
|
||||
import org.springframework.security.core.authority.SimpleGrantedAuthority;
|
||||
import org.springframework.security.core.context.SecurityContextHolder;
|
||||
import org.springframework.security.oauth2.client.oidc.userinfo.OidcUserRequest;
|
||||
import org.springframework.security.oauth2.client.registration.ClientRegistration;
|
||||
import org.springframework.security.oauth2.client.registration.InMemoryClientRegistrationRepository;
|
||||
import org.springframework.security.oauth2.client.userinfo.OAuth2UserService;
|
||||
import org.springframework.security.oauth2.core.oidc.user.OidcUser;
|
||||
import org.springframework.security.oauth2.server.resource.web.BearerTokenAuthenticationFilter;
|
||||
import org.springframework.security.web.access.intercept.FilterSecurityInterceptor;
|
||||
import org.springframework.security.web.authentication.AnonymousAuthenticationFilter;
|
||||
import org.springframework.security.web.authentication.AuthenticationSuccessHandler;
|
||||
import org.springframework.security.web.authentication.LoginUrlAuthenticationEntryPoint;
|
||||
import org.springframework.security.web.authentication.logout.LogoutHandler;
|
||||
import org.springframework.security.web.authentication.logout.SimpleUrlLogoutSuccessHandler;
|
||||
import org.springframework.security.web.authentication.preauth.RequestHeaderAuthenticationFilter;
|
||||
import org.springframework.security.web.authentication.www.BasicAuthenticationEntryPoint;
|
||||
import org.springframework.security.web.authentication.www.BasicAuthenticationFilter;
|
||||
import org.springframework.security.web.session.HttpSessionEventPublisher;
|
||||
import org.springframework.security.web.session.SessionManagementFilter;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.StringUtils;
|
||||
import org.vaadin.spring.security.VaadinSecurityContext;
|
||||
import org.vaadin.spring.security.annotation.EnableVaadinSecurity;
|
||||
@@ -457,6 +466,12 @@ public class SecurityManagedConfiguration {
|
||||
@Autowired
|
||||
private UserAuthenticationFilter userAuthenticationFilter;
|
||||
|
||||
@Autowired(required = false)
|
||||
private OidcBearerTokenAuthenticationFilter oidcBearerTokenAuthenticationFilter;
|
||||
|
||||
@Autowired(required = false)
|
||||
private InMemoryClientRegistrationRepository clientRegistrationRepository;
|
||||
|
||||
@Autowired
|
||||
private SystemManagement systemManagement;
|
||||
|
||||
@@ -492,38 +507,61 @@ public class SecurityManagedConfiguration {
|
||||
@Override
|
||||
protected void configure(final HttpSecurity http) throws Exception {
|
||||
|
||||
final BasicAuthenticationEntryPoint basicAuthEntryPoint = new BasicAuthenticationEntryPoint();
|
||||
basicAuthEntryPoint.setRealmName(securityProperties.getBasicRealm());
|
||||
|
||||
HttpSecurity httpSec = http.regexMatcher("\\/rest.*|\\/system/admin.*").csrf().disable();
|
||||
if (securityProperties.isRequireSsl()) {
|
||||
httpSec = httpSec.requiresChannel().anyRequest().requiresSecure().and();
|
||||
}
|
||||
|
||||
httpSec.addFilterBefore(new Filter() {
|
||||
@Override
|
||||
public void init(final FilterConfig filterConfig) throws ServletException {
|
||||
userAuthenticationFilter.init(filterConfig);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void doFilter(final ServletRequest request, final ServletResponse response,
|
||||
final FilterChain chain) throws IOException, ServletException {
|
||||
userAuthenticationFilter.doFilter(request, response, chain);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void destroy() {
|
||||
userAuthenticationFilter.destroy();
|
||||
}
|
||||
}, RequestHeaderAuthenticationFilter.class)
|
||||
.addFilterAfter(new AuthenticationSuccessTenantMetadataCreationFilter(systemManagement,
|
||||
systemSecurityContext), SessionManagementFilter.class)
|
||||
httpSec
|
||||
.authorizeRequests().anyRequest().authenticated()
|
||||
.antMatchers(MgmtRestConstants.BASE_SYSTEM_MAPPING + "/admin/**")
|
||||
.hasAnyAuthority(SpPermission.SYSTEM_ADMIN);
|
||||
|
||||
httpSec.httpBasic().and().exceptionHandling().authenticationEntryPoint(basicAuthEntryPoint);
|
||||
if (oidcBearerTokenAuthenticationFilter != null) {
|
||||
|
||||
// Only get the first client registration. Testing against every client could increase the
|
||||
// attack vector
|
||||
ClientRegistration clientRegistration = null;
|
||||
for (ClientRegistration cr : clientRegistrationRepository) {
|
||||
clientRegistration = cr;
|
||||
break;
|
||||
}
|
||||
|
||||
Assert.notNull(clientRegistration, "There must be a valid client registration");
|
||||
httpSec.oauth2ResourceServer()
|
||||
.jwt().jwkSetUri(clientRegistration.getProviderDetails().getJwkSetUri());
|
||||
|
||||
oidcBearerTokenAuthenticationFilter.setClientRegistration(clientRegistration);
|
||||
|
||||
httpSec.addFilterAfter(oidcBearerTokenAuthenticationFilter, BearerTokenAuthenticationFilter.class);
|
||||
}
|
||||
else {
|
||||
final BasicAuthenticationEntryPoint basicAuthEntryPoint = new BasicAuthenticationEntryPoint();
|
||||
basicAuthEntryPoint.setRealmName(securityProperties.getBasicRealm());
|
||||
|
||||
httpSec.addFilterBefore(new Filter() {
|
||||
@Override
|
||||
public void init(final FilterConfig filterConfig) throws ServletException {
|
||||
userAuthenticationFilter.init(filterConfig);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void doFilter(final ServletRequest request, final ServletResponse response,
|
||||
final FilterChain chain) throws IOException, ServletException {
|
||||
userAuthenticationFilter.doFilter(request, response, chain);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void destroy() {
|
||||
userAuthenticationFilter.destroy();
|
||||
}
|
||||
}, RequestHeaderAuthenticationFilter.class);
|
||||
httpSec.httpBasic().and().exceptionHandling().authenticationEntryPoint(basicAuthEntryPoint);
|
||||
}
|
||||
|
||||
httpSec.addFilterAfter(new AuthenticationSuccessTenantMetadataCreationFilter(systemManagement,
|
||||
systemSecurityContext), SessionManagementFilter.class);
|
||||
|
||||
httpSec.anonymous().disable();
|
||||
httpSec.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS);
|
||||
}
|
||||
@@ -546,6 +584,15 @@ public class SecurityManagedConfiguration {
|
||||
|
||||
private final VaadinUrlAuthenticationSuccessHandler handler;
|
||||
|
||||
@Autowired(required = false)
|
||||
private AuthenticationSuccessHandler oidcAuthenticationSuccessHandler;
|
||||
|
||||
@Autowired(required = false)
|
||||
private LogoutHandler oidcLogoutHandler;
|
||||
|
||||
@Autowired(required = false)
|
||||
private OAuth2UserService<OidcUserRequest, OidcUser> oidcUserService;
|
||||
|
||||
public UISecurityConfigurationAdapter(final VaadinRedirectStrategy redirectStrategy) {
|
||||
handler = new TenantMetadataSavedRequestAwareVaadinAuthenticationSuccessHandler();
|
||||
handler.setRedirectStrategy(redirectStrategy);
|
||||
@@ -614,13 +661,21 @@ public class SecurityManagedConfiguration {
|
||||
@Override
|
||||
protected void configure(final HttpSecurity http) throws Exception {
|
||||
|
||||
boolean enableOidc = oidcUserService != null && oidcAuthenticationSuccessHandler != null
|
||||
&& oidcLogoutHandler != null;
|
||||
|
||||
// workaround regex: we need to exclude the URL /UI/HEARTBEAT here
|
||||
// because we bound the vaadin application to /UI and not to root,
|
||||
// described in vaadin-forum:
|
||||
// https://vaadin.com/forum#!/thread/3200565.
|
||||
HttpSecurity httpSec = http.regexMatcher("(?!.*HEARTBEAT)^.*\\/UI.*$")
|
||||
// disable as CSRF is handled by Vaadin
|
||||
.csrf().disable();
|
||||
HttpSecurity httpSec = null;
|
||||
if (enableOidc) {
|
||||
httpSec = http.regexMatcher("(?!.*HEARTBEAT)^.*\\/(UI|oauth2).*$");
|
||||
} else {
|
||||
httpSec = http.regexMatcher("(?!.*HEARTBEAT)^.*\\/UI.*$");
|
||||
}
|
||||
// disable as CSRF is handled by Vaadin
|
||||
httpSec.csrf().disable();
|
||||
|
||||
if (hawkbitSecurityProperties.isRequireSsl()) {
|
||||
httpSec = httpSec.requiresChannel().anyRequest().requiresSecure().and();
|
||||
@@ -634,16 +689,27 @@ public class SecurityManagedConfiguration {
|
||||
httpSec.headers().contentSecurityPolicy(hawkbitSecurityProperties.getContentSecurityPolicy());
|
||||
}
|
||||
|
||||
final SimpleUrlLogoutSuccessHandler simpleUrlLogoutSuccessHandler = new SimpleUrlLogoutSuccessHandler();
|
||||
simpleUrlLogoutSuccessHandler.setTargetUrlParameter("login");
|
||||
if (enableOidc) {
|
||||
httpSec.authorizeRequests().antMatchers("/UI/login/**").permitAll().antMatchers("/UI/UIDL/**")
|
||||
.permitAll().anyRequest().authenticated().and()
|
||||
// OIDC
|
||||
.oauth2Login().userInfoEndpoint().oidcUserService(oidcUserService).and()
|
||||
.successHandler(oidcAuthenticationSuccessHandler).and().oauth2Client().and()
|
||||
// logout
|
||||
.logout().logoutUrl("/UI/logout").addLogoutHandler(oidcLogoutHandler).logoutSuccessUrl("/");
|
||||
} else {
|
||||
final SimpleUrlLogoutSuccessHandler simpleUrlLogoutSuccessHandler = new SimpleUrlLogoutSuccessHandler();
|
||||
simpleUrlLogoutSuccessHandler.setTargetUrlParameter("login");
|
||||
|
||||
httpSec
|
||||
// UI
|
||||
.authorizeRequests().antMatchers("/UI/login/**").permitAll().antMatchers("/UI/UIDL/**").permitAll()
|
||||
.anyRequest().authenticated().and()
|
||||
// UI login / logout
|
||||
.exceptionHandling().authenticationEntryPoint(new LoginUrlAuthenticationEntryPoint("/UI/login/#/"))
|
||||
.and().logout().logoutUrl("/UI/logout").logoutSuccessHandler(simpleUrlLogoutSuccessHandler);
|
||||
httpSec
|
||||
// UI
|
||||
.authorizeRequests().antMatchers("/UI/login/**").permitAll().antMatchers("/UI/UIDL/**")
|
||||
.permitAll().anyRequest().authenticated().and()
|
||||
// UI login / logout
|
||||
.exceptionHandling()
|
||||
.authenticationEntryPoint(new LoginUrlAuthenticationEntryPoint("/UI/login/#/")).and().logout()
|
||||
.logoutUrl("/UI/logout").logoutSuccessHandler(simpleUrlLogoutSuccessHandler);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
Reference in New Issue
Block a user