Refacto oauth2 granted authorities (#2684)
* refacto: oauth2 * feat: clear user from cache on logout
This commit is contained in:
committed by
GitHub
parent
a3cf835ae2
commit
4306548b4a
@@ -48,7 +48,7 @@ public class HawkbitMgmtClient {
|
||||
private final MgmtTenantManagementRestApi tenantManagementRestApi;
|
||||
private final MgmtActionRestApi actionRestApi;
|
||||
|
||||
HawkbitMgmtClient(final Tenant tenant, final HawkbitClient hawkbitClient) {
|
||||
public HawkbitMgmtClient(final Tenant tenant, final HawkbitClient hawkbitClient) {
|
||||
this.tenant = tenant;
|
||||
this.hawkbitClient = hawkbitClient;
|
||||
|
||||
@@ -66,23 +66,23 @@ public class HawkbitMgmtClient {
|
||||
actionRestApi = service(MgmtActionRestApi.class);
|
||||
}
|
||||
|
||||
boolean hasSoftwareModulesRead() {
|
||||
public boolean hasSoftwareModulesRead() {
|
||||
return hasRead(() -> softwareModuleRestApi.getSoftwareModule(-1L));
|
||||
}
|
||||
|
||||
boolean hasRolloutRead() {
|
||||
public boolean hasRolloutRead() {
|
||||
return hasRead(() -> rolloutRestApi.getRollout(-1L));
|
||||
}
|
||||
|
||||
boolean hasDistributionSetRead() {
|
||||
public boolean hasDistributionSetRead() {
|
||||
return hasRead(() -> distributionSetRestApi.getDistributionSet(-1L));
|
||||
}
|
||||
|
||||
boolean hasTargetRead() {
|
||||
public boolean hasTargetRead() {
|
||||
return hasRead(() -> targetRestApi.getTarget("_#ETE$ER"));
|
||||
}
|
||||
|
||||
boolean hasConfigRead() {
|
||||
public boolean hasConfigRead() {
|
||||
return hasRead(() -> tenantManagementRestApi.getTenantConfigurationValue("_#ETE$ER"));
|
||||
}
|
||||
|
||||
|
||||
@@ -71,7 +71,8 @@ public class MainLayout extends AppLayout {
|
||||
protected void afterNavigation() {
|
||||
super.afterNavigation();
|
||||
viewTitle.setText(
|
||||
Optional.ofNullable(getContent().getClass().getAnnotation(PageTitle.class))
|
||||
Optional.ofNullable(getContent())
|
||||
.map(c -> c.getClass().getAnnotation(PageTitle.class))
|
||||
.map(PageTitle::value)
|
||||
.orElse(""));
|
||||
if (UI.getCurrent().getActiveViewLocation().getPath().isEmpty()) {
|
||||
|
||||
@@ -21,52 +21,43 @@ import lombok.extern.slf4j.Slf4j;
|
||||
import org.eclipse.hawkbit.sdk.HawkbitClient;
|
||||
import org.eclipse.hawkbit.sdk.HawkbitServer;
|
||||
import org.eclipse.hawkbit.sdk.Tenant;
|
||||
import org.eclipse.hawkbit.ui.simple.security.OAuth2TokenManager;
|
||||
import org.eclipse.hawkbit.ui.simple.view.util.Utils;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.boot.SpringApplication;
|
||||
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||
import org.springframework.cache.annotation.EnableCaching;
|
||||
import org.springframework.cloud.openfeign.FeignClientsConfiguration;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Import;
|
||||
import org.springframework.scheduling.annotation.EnableScheduling;
|
||||
import org.springframework.security.authentication.AuthenticationManager;
|
||||
import org.springframework.security.authentication.BadCredentialsException;
|
||||
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
|
||||
import org.springframework.security.core.Authentication;
|
||||
import org.springframework.security.core.authority.SimpleGrantedAuthority;
|
||||
import org.springframework.security.core.context.SecurityContext;
|
||||
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.userinfo.OAuth2UserService;
|
||||
import org.springframework.security.oauth2.core.oidc.user.DefaultOidcUser;
|
||||
import org.springframework.security.oauth2.core.oidc.user.OidcUser;
|
||||
|
||||
import java.net.HttpURLConnection;
|
||||
import java.net.URL;
|
||||
import java.util.Base64;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.Collections;
|
||||
import java.util.Objects;
|
||||
import java.util.function.Function;
|
||||
|
||||
import static feign.Util.ISO_8859_1;
|
||||
import static java.util.Collections.emptyList;
|
||||
|
||||
@Slf4j
|
||||
@Theme("hawkbit")
|
||||
@PWA(name = "hawkBit UI", shortName = "hawkBit UI")
|
||||
@EnableCaching
|
||||
@EnableScheduling
|
||||
@SpringBootApplication
|
||||
@Import(FeignClientsConfiguration.class)
|
||||
public class SimpleUIApp implements AppShellConfigurator {
|
||||
|
||||
private static final String AUTHORIZATION_HEADER = "Authorization";
|
||||
private static final Function<OAuth2TokenManager, RequestInterceptor> AUTHORIZATION = oAuth2TokenManager -> requestTemplate -> {
|
||||
private static final RequestInterceptor AUTHORIZATION = requestTemplate -> {
|
||||
final Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
|
||||
if (authentication instanceof OAuth2AuthenticationToken authenticationToken) {
|
||||
String bearerToken = oAuth2TokenManager.getToken(authenticationToken);
|
||||
requestTemplate.header(AUTHORIZATION_HEADER, "Bearer " + bearerToken);
|
||||
if (authentication.getPrincipal() instanceof OidcUser oidcUser) {
|
||||
requestTemplate.header(AUTHORIZATION_HEADER, "Bearer " + oidcUser.getIdToken().getTokenValue());
|
||||
} else {
|
||||
requestTemplate.header(
|
||||
AUTHORIZATION_HEADER, "Basic " + Base64.getEncoder().encodeToString(
|
||||
@@ -92,16 +83,13 @@ public class SimpleUIApp implements AppShellConfigurator {
|
||||
final HawkbitServer hawkBitServer,
|
||||
final Encoder encoder,
|
||||
final Decoder decoder,
|
||||
final Contract contract,
|
||||
@Autowired(required = false)
|
||||
final OAuth2TokenManager oAuth2TokenManager
|
||||
final Contract contract
|
||||
) {
|
||||
return new HawkbitClient(
|
||||
hawkBitServer, encoder, decoder, contract,
|
||||
ERROR_DECODER,
|
||||
(tenant, controller) ->
|
||||
controller == null
|
||||
? AUTHORIZATION.apply(oAuth2TokenManager)
|
||||
(tenant, controller) -> controller == null
|
||||
? AUTHORIZATION
|
||||
: HawkbitClient.DEFAULT_REQUEST_INTERCEPTOR_FN.apply(tenant, controller)
|
||||
);
|
||||
}
|
||||
@@ -111,21 +99,6 @@ public class SimpleUIApp implements AppShellConfigurator {
|
||||
return new HawkbitMgmtClient(tenant, hawkbitClient);
|
||||
}
|
||||
|
||||
@Bean
|
||||
OAuth2UserService<OidcUserRequest, OidcUser> oidcUserService(final HawkbitMgmtClient hawkbitClient) {
|
||||
final OidcUserService delegate = new OidcUserService();
|
||||
return userRequest -> {
|
||||
OidcUser oidcUser = delegate.loadUser(userRequest);
|
||||
final OAuth2AuthenticationToken tempToken = new OAuth2AuthenticationToken(
|
||||
oidcUser,
|
||||
emptyList(),
|
||||
userRequest.getClientRegistration().getRegistrationId()
|
||||
);
|
||||
final List<SimpleGrantedAuthority> grantedAuthorities = getGrantedAuthorities(hawkbitClient, tempToken);
|
||||
return new DefaultOidcUser(grantedAuthorities, oidcUser.getIdToken(), oidcUser.getUserInfo());
|
||||
};
|
||||
}
|
||||
|
||||
// accepts all user / pass, just delegating them to the feign client
|
||||
@Bean
|
||||
AuthenticationManager authenticationManager(final HawkbitMgmtClient hawkbitClient, final HawkbitServer server) {
|
||||
@@ -138,9 +111,7 @@ public class SimpleUIApp implements AppShellConfigurator {
|
||||
throw new BadCredentialsException("Incorrect username or password!");
|
||||
}
|
||||
|
||||
final List<SimpleGrantedAuthority> grantedAuthorities = getGrantedAuthorities(
|
||||
hawkbitClient, new UsernamePasswordAuthenticationToken(username, password));
|
||||
return new UsernamePasswordAuthenticationToken(username, password, grantedAuthorities) {
|
||||
return new UsernamePasswordAuthenticationToken(username, password, Collections.emptyList()) {
|
||||
|
||||
@Override
|
||||
public void eraseCredentials() {
|
||||
@@ -151,35 +122,6 @@ public class SimpleUIApp implements AppShellConfigurator {
|
||||
};
|
||||
}
|
||||
|
||||
private List<SimpleGrantedAuthority> getGrantedAuthorities(final HawkbitMgmtClient hawkbitClient, Authentication authentication) {
|
||||
final List<String> roles = new LinkedList<>();
|
||||
roles.add("ANONYMOUS");
|
||||
final SecurityContext unauthorizedContext = SecurityContextHolder.createEmptyContext();
|
||||
unauthorizedContext.setAuthentication(authentication);
|
||||
final SecurityContext currentContext = SecurityContextHolder.getContext();
|
||||
try {
|
||||
SecurityContextHolder.setContext(unauthorizedContext);
|
||||
if (hawkbitClient.hasSoftwareModulesRead()) {
|
||||
roles.add("SOFTWARE_MODULE_READ");
|
||||
}
|
||||
if (hawkbitClient.hasRolloutRead()) {
|
||||
roles.add("ROLLOUT_READ");
|
||||
}
|
||||
if (hawkbitClient.hasDistributionSetRead()) {
|
||||
roles.add("DISTRIBUTION_SET_READ");
|
||||
}
|
||||
if (hawkbitClient.hasTargetRead()) {
|
||||
roles.add("TARGET_READ");
|
||||
}
|
||||
if (hawkbitClient.hasConfigRead()) {
|
||||
roles.add("CONFIG_READ");
|
||||
}
|
||||
} finally {
|
||||
SecurityContextHolder.setContext(currentContext);
|
||||
}
|
||||
return roles.stream().map(role -> new SimpleGrantedAuthority("ROLE_" + role)).toList();
|
||||
}
|
||||
|
||||
public static boolean isAuthenticated(String username, String password, String mgmtUrl) {
|
||||
try {
|
||||
final URL url = new URL(mgmtUrl + "/rest/v1/rollouts");
|
||||
|
||||
@@ -18,9 +18,11 @@ import org.springframework.stereotype.Component;
|
||||
public class AuthenticatedUser {
|
||||
|
||||
private final AuthenticationContext authenticationContext;
|
||||
private final GrantedAuthoritiesService grantedAuthoritiesService;
|
||||
|
||||
public AuthenticatedUser(final AuthenticationContext authenticationContext) {
|
||||
public AuthenticatedUser(final AuthenticationContext authenticationContext, GrantedAuthoritiesService grantedAuthoritiesService) {
|
||||
this.authenticationContext = authenticationContext;
|
||||
this.grantedAuthoritiesService = grantedAuthoritiesService;
|
||||
}
|
||||
|
||||
public Optional<String> getName() {
|
||||
@@ -28,6 +30,7 @@ public class AuthenticatedUser {
|
||||
}
|
||||
|
||||
public void logout() {
|
||||
this.getName().ifPresent(grantedAuthoritiesService::evictUserFromCache);
|
||||
authenticationContext.logout();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,65 @@
|
||||
/**
|
||||
* Copyright (c) 2025 Contributors to the Eclipse Foundation
|
||||
*
|
||||
* This program and the accompanying materials are made
|
||||
* available under the terms of the Eclipse Public License 2.0
|
||||
* which is available at https://www.eclipse.org/legal/epl-2.0/
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.eclipse.hawkbit.ui.simple.security;
|
||||
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.eclipse.hawkbit.ui.simple.HawkbitMgmtClient;
|
||||
import org.springframework.cache.annotation.CacheEvict;
|
||||
import org.springframework.cache.annotation.Cacheable;
|
||||
import org.springframework.scheduling.annotation.Scheduled;
|
||||
import org.springframework.security.core.Authentication;
|
||||
import org.springframework.security.core.authority.SimpleGrantedAuthority;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
@Service
|
||||
@AllArgsConstructor
|
||||
@Slf4j
|
||||
public class GrantedAuthoritiesService {
|
||||
|
||||
public static final String USER_CACHE = "userDetails";
|
||||
private HawkbitMgmtClient hawkbitClient;
|
||||
|
||||
@Cacheable(cacheNames = "userDetails", key = "#authentication.getName()")
|
||||
public List<SimpleGrantedAuthority> getGrantedAuthorities(Authentication authentication) {
|
||||
final List<String> roles = new LinkedList<>();
|
||||
roles.add("ANONYMOUS");
|
||||
if (hawkbitClient.hasSoftwareModulesRead()) {
|
||||
roles.add("SOFTWARE_MODULE_READ");
|
||||
}
|
||||
if (hawkbitClient.hasRolloutRead()) {
|
||||
roles.add("ROLLOUT_READ");
|
||||
}
|
||||
if (hawkbitClient.hasDistributionSetRead()) {
|
||||
roles.add("DISTRIBUTION_SET_READ");
|
||||
}
|
||||
if (hawkbitClient.hasTargetRead()) {
|
||||
roles.add("TARGET_READ");
|
||||
}
|
||||
if (hawkbitClient.hasConfigRead()) {
|
||||
roles.add("CONFIG_READ");
|
||||
}
|
||||
return roles.stream().map(role -> new SimpleGrantedAuthority("ROLE_" + role)).toList();
|
||||
}
|
||||
|
||||
@Scheduled(fixedRateString = "${caching.spring.userDetailsTTL:1h}")
|
||||
@CacheEvict(cacheNames = USER_CACHE, allEntries = true)
|
||||
public void emptyCache() {
|
||||
log.debug("emptying userDetails cache");
|
||||
}
|
||||
|
||||
@CacheEvict(cacheNames = "userDetails")
|
||||
public void evictUserFromCache(String principalName) {
|
||||
log.debug("remove user from {} cache", principalName);
|
||||
}
|
||||
}
|
||||
@@ -1,57 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) 2025 Contributors to the Eclipse Foundation
|
||||
*
|
||||
* This program and the accompanying materials are made
|
||||
* available under the terms of the Eclipse Public License 2.0
|
||||
* which is available at https://www.eclipse.org/legal/epl-2.0/
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.eclipse.hawkbit.ui.simple.security;
|
||||
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
|
||||
import org.springframework.security.core.context.SecurityContext;
|
||||
import org.springframework.security.core.context.SecurityContextHolder;
|
||||
import org.springframework.security.oauth2.client.OAuth2AuthorizeRequest;
|
||||
import org.springframework.security.oauth2.client.OAuth2AuthorizedClient;
|
||||
import org.springframework.security.oauth2.client.OAuth2AuthorizedClientManager;
|
||||
import org.springframework.security.oauth2.client.OAuth2AuthorizedClientService;
|
||||
import org.springframework.security.oauth2.client.authentication.OAuth2AuthenticationToken;
|
||||
import org.springframework.security.oauth2.core.oidc.user.DefaultOidcUser;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
@Component
|
||||
@ConditionalOnProperty(prefix = "hawkbit.server.security.oauth2.client", name = "enabled")
|
||||
public class OAuth2TokenManager {
|
||||
|
||||
private final OAuth2AuthorizedClientService clientService;
|
||||
private final OAuth2AuthorizedClientManager clientManager;
|
||||
|
||||
OAuth2TokenManager(
|
||||
final OAuth2AuthorizedClientService clientService,
|
||||
final OAuth2AuthorizedClientManager clientManager
|
||||
) {
|
||||
this.clientService = clientService;
|
||||
this.clientManager = clientManager;
|
||||
}
|
||||
|
||||
public String getToken(final OAuth2AuthenticationToken authentication) {
|
||||
final String currentToken = ((DefaultOidcUser) authentication.getPrincipal()).getIdToken().getTokenValue();
|
||||
String registrationId = authentication.getAuthorizedClientRegistrationId();
|
||||
|
||||
// This ensures that there is a client already, otherwise we won't be able to call the manager for authorization
|
||||
OAuth2AuthorizedClient authorizedClient = clientService.loadAuthorizedClient(registrationId, authentication.getName());
|
||||
if (authorizedClient == null) return currentToken;
|
||||
|
||||
// Will ensure that the token is refreshed if needed; do not rely on it being not null as it won't be available
|
||||
// during the first calls made to get the rights and generate the authorities
|
||||
OAuth2AuthorizeRequest request = OAuth2AuthorizeRequest.withClientRegistrationId(registrationId).principal(authentication).build();
|
||||
// since Spring Security 6.5 this will trigger a refresh of the id token
|
||||
authorizedClient = clientManager.authorize(request);
|
||||
if (authorizedClient == null) return currentToken;
|
||||
|
||||
// we need to fetch the newly created context containing the matching token
|
||||
SecurityContext securityContext = SecurityContextHolder.getContext();
|
||||
return ((DefaultOidcUser) securityContext.getAuthentication().getPrincipal()).getIdToken().getTokenValue();
|
||||
}
|
||||
}
|
||||
@@ -11,6 +11,7 @@ package org.eclipse.hawkbit.ui.simple.security;
|
||||
|
||||
import com.vaadin.flow.spring.security.VaadinAwareSecurityContextHolderStrategyConfiguration;
|
||||
import com.vaadin.flow.spring.security.VaadinSecurityConfigurer;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.eclipse.hawkbit.ui.simple.view.LoginView;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.beans.factory.annotation.Qualifier;
|
||||
@@ -24,19 +25,27 @@ import org.springframework.security.config.annotation.web.configuration.EnableWe
|
||||
import org.springframework.security.config.annotation.web.configurers.oauth2.client.OAuth2LoginConfigurer;
|
||||
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
|
||||
import org.springframework.security.crypto.password.PasswordEncoder;
|
||||
import org.springframework.security.oauth2.client.registration.InMemoryClientRegistrationRepository;
|
||||
import org.springframework.security.web.SecurityFilterChain;
|
||||
import org.springframework.security.web.authentication.AuthenticationFailureHandler;
|
||||
|
||||
import java.net.URLEncoder;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import org.springframework.security.web.access.intercept.AuthorizationFilter;
|
||||
|
||||
@EnableWebSecurity
|
||||
@Configuration
|
||||
@EnableConfigurationProperties(OidcClientProperties.class)
|
||||
@Slf4j
|
||||
@Import(VaadinAwareSecurityContextHolderStrategyConfiguration.class)
|
||||
public class SecurityConfiguration {
|
||||
|
||||
private Customizer<OAuth2LoginConfigurer<HttpSecurity>> oAuth2LoginConfigurerCustomizer;
|
||||
@Autowired
|
||||
private UserDetailsSetter userDetailsSetter;
|
||||
|
||||
@Autowired(required = false)
|
||||
private InMemoryClientRegistrationRepository clientRegistrationRepository;
|
||||
|
||||
@Autowired(required = false)
|
||||
public void setOAuth2LoginConfigurerCustomizer(
|
||||
@@ -52,23 +61,24 @@ public class SecurityConfiguration {
|
||||
@Bean
|
||||
public AuthenticationFailureHandler customFailureHandler() {
|
||||
// Redirect back to login with your message
|
||||
return (request, response, exception) ->
|
||||
response.sendRedirect("/login?error=" + URLEncoder.encode(exception.getMessage(), StandardCharsets.UTF_8));
|
||||
return (request, response, exception) -> response.sendRedirect("/login?error=" + URLEncoder.encode(exception.getMessage(),
|
||||
StandardCharsets.UTF_8));
|
||||
}
|
||||
|
||||
@Bean
|
||||
SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
|
||||
http.authorizeHttpRequests(authorize -> authorize.requestMatchers("/images/*.png").permitAll());
|
||||
if (oAuth2LoginConfigurerCustomizer != null) {
|
||||
http.oauth2Login(oAuth2LoginConfigurerCustomizer);
|
||||
} else {
|
||||
http.formLogin(form -> form
|
||||
.loginPage("/login")
|
||||
.failureHandler(customFailureHandler()));
|
||||
}
|
||||
http.addFilterAfter(userDetailsSetter, AuthorizationFilter.class);
|
||||
return http.with(VaadinSecurityConfigurer.vaadin(), configurer -> {
|
||||
if (oAuth2LoginConfigurerCustomizer == null) {
|
||||
configurer.loginView(LoginView.class);
|
||||
|
||||
} else {
|
||||
var defaultClientRegistration = clientRegistrationRepository.iterator().next();
|
||||
configurer.oauth2LoginPage(
|
||||
"/oauth2/authorization/" + defaultClientRegistration.getRegistrationId(),
|
||||
"{baseUrl}/"
|
||||
);
|
||||
}
|
||||
}).build();
|
||||
}
|
||||
|
||||
@@ -0,0 +1,72 @@
|
||||
/**
|
||||
* Copyright (c) 2025 Contributors to the Eclipse Foundation
|
||||
*
|
||||
* This program and the accompanying materials are made
|
||||
* available under the terms of the Eclipse Public License 2.0
|
||||
* which is available at https://www.eclipse.org/legal/epl-2.0/
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.eclipse.hawkbit.ui.simple.security;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.time.Instant;
|
||||
import java.util.Collection;
|
||||
|
||||
import jakarta.servlet.FilterChain;
|
||||
import jakarta.servlet.ServletException;
|
||||
import jakarta.servlet.http.HttpServletRequest;
|
||||
import jakarta.servlet.http.HttpServletResponse;
|
||||
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.springframework.security.authentication.AccountExpiredException;
|
||||
import org.springframework.security.authentication.AnonymousAuthenticationToken;
|
||||
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
|
||||
import org.springframework.security.core.Authentication;
|
||||
import org.springframework.security.core.GrantedAuthority;
|
||||
import org.springframework.security.core.context.SecurityContextHolderStrategy;
|
||||
import org.springframework.security.oauth2.client.authentication.OAuth2AuthenticationToken;
|
||||
import org.springframework.security.oauth2.core.oidc.user.OidcUser;
|
||||
import org.springframework.stereotype.Component;
|
||||
import org.springframework.web.filter.OncePerRequestFilter;
|
||||
|
||||
@RequiredArgsConstructor
|
||||
@Component
|
||||
@Slf4j
|
||||
class UserDetailsSetter extends OncePerRequestFilter {
|
||||
|
||||
private final SecurityContextHolderStrategy securityContextHolderStrategy;
|
||||
private final GrantedAuthoritiesService grantedAuthoritiesService;
|
||||
|
||||
@Override
|
||||
protected void doFilterInternal(@NotNull final HttpServletRequest request, @NotNull final HttpServletResponse response,
|
||||
@NotNull final FilterChain filterChain)
|
||||
throws ServletException, IOException {
|
||||
|
||||
Authentication authentication = securityContextHolderStrategy.getContext().getAuthentication();
|
||||
Authentication newAuthentication;
|
||||
|
||||
if (!(authentication instanceof AnonymousAuthenticationToken) && authentication.isAuthenticated()) {
|
||||
Collection<? extends GrantedAuthority> grantedAuthorities = grantedAuthoritiesService.getGrantedAuthorities(authentication);
|
||||
|
||||
if (authentication instanceof OAuth2AuthenticationToken oAuth2AuthenticationToken) {
|
||||
newAuthentication = new OAuth2AuthenticationToken(oAuth2AuthenticationToken.getPrincipal(), grantedAuthorities,
|
||||
oAuth2AuthenticationToken.getAuthorizedClientRegistrationId());
|
||||
if (authentication.getPrincipal() instanceof OidcUser user) {
|
||||
// if there is no refresh token and the access token is expired then relogin is required
|
||||
if (user.getIdToken().getExpiresAt() != null && Instant.now().isAfter(user.getIdToken().getExpiresAt())) {
|
||||
throw new AccountExpiredException("Token expired");
|
||||
}
|
||||
}
|
||||
} else {
|
||||
newAuthentication = new UsernamePasswordAuthenticationToken(authentication.getName(), authentication.getCredentials(),
|
||||
grantedAuthorities);
|
||||
}
|
||||
|
||||
securityContextHolderStrategy.getContext().setAuthentication(newAuthentication);
|
||||
}
|
||||
filterChain.doFilter(request, response);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user