Support configurable JwtDecoder for IdToken verification
Fixes gh-5717
This commit is contained in:
@@ -16,6 +16,7 @@
|
||||
package org.springframework.security.config.annotation.web.configurers.oauth2.client;
|
||||
|
||||
import org.springframework.beans.factory.BeanFactoryUtils;
|
||||
import org.springframework.beans.factory.NoUniqueBeanDefinitionException;
|
||||
import org.springframework.context.ApplicationContext;
|
||||
import org.springframework.core.ResolvableType;
|
||||
import org.springframework.security.authentication.AuthenticationProvider;
|
||||
@@ -55,6 +56,7 @@ import org.springframework.security.oauth2.core.endpoint.OAuth2AuthorizationRequ
|
||||
import org.springframework.security.oauth2.core.oidc.OidcScopes;
|
||||
import org.springframework.security.oauth2.core.oidc.user.OidcUser;
|
||||
import org.springframework.security.oauth2.core.user.OAuth2User;
|
||||
import org.springframework.security.oauth2.jwt.JwtDecoderFactory;
|
||||
import org.springframework.security.web.AuthenticationEntryPoint;
|
||||
import org.springframework.security.web.authentication.DelegatingAuthenticationEntryPoint;
|
||||
import org.springframework.security.web.authentication.LoginUrlAuthenticationEntryPoint;
|
||||
@@ -488,6 +490,10 @@ public final class OAuth2LoginConfigurer<B extends HttpSecurityBuilder<B>> exten
|
||||
|
||||
OidcAuthorizationCodeAuthenticationProvider oidcAuthorizationCodeAuthenticationProvider =
|
||||
new OidcAuthorizationCodeAuthenticationProvider(accessTokenResponseClient, oidcUserService);
|
||||
JwtDecoderFactory<ClientRegistration> jwtDecoderFactory = this.getJwtDecoderFactoryBean();
|
||||
if (jwtDecoderFactory != null) {
|
||||
oidcAuthorizationCodeAuthenticationProvider.setJwtDecoderFactory(jwtDecoderFactory);
|
||||
}
|
||||
if (userAuthoritiesMapper != null) {
|
||||
oidcAuthorizationCodeAuthenticationProvider.setAuthoritiesMapper(userAuthoritiesMapper);
|
||||
}
|
||||
@@ -541,6 +547,19 @@ public final class OAuth2LoginConfigurer<B extends HttpSecurityBuilder<B>> exten
|
||||
return new AntPathRequestMatcher(loginProcessingUrl);
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private JwtDecoderFactory<ClientRegistration> getJwtDecoderFactoryBean() {
|
||||
ResolvableType type = ResolvableType.forClassWithGenerics(JwtDecoderFactory.class, ClientRegistration.class);
|
||||
String[] names = this.getBuilder().getSharedObject(ApplicationContext.class).getBeanNamesForType(type);
|
||||
if (names.length > 1) {
|
||||
throw new NoUniqueBeanDefinitionException(type, names);
|
||||
}
|
||||
if (names.length == 1) {
|
||||
return (JwtDecoderFactory<ClientRegistration>) this.getBuilder().getSharedObject(ApplicationContext.class).getBean(names[0]);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private GrantedAuthoritiesMapper getGrantedAuthoritiesMapper() {
|
||||
GrantedAuthoritiesMapper grantedAuthoritiesMapper =
|
||||
this.getBuilder().getSharedObject(GrantedAuthoritiesMapper.class);
|
||||
|
||||
@@ -16,28 +16,6 @@
|
||||
|
||||
package org.springframework.security.config.web.server;
|
||||
|
||||
import static org.springframework.security.web.server.DelegatingServerAuthenticationEntryPoint.DelegateEntry;
|
||||
import static org.springframework.security.web.server.util.matcher.ServerWebExchangeMatcher.MatchResult.match;
|
||||
import static org.springframework.security.web.server.util.matcher.ServerWebExchangeMatcher.MatchResult.notMatch;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.PrintWriter;
|
||||
import java.io.StringWriter;
|
||||
import java.security.interfaces.RSAPublicKey;
|
||||
import java.time.Duration;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
import java.util.function.Function;
|
||||
import java.util.UUID;
|
||||
|
||||
import reactor.core.publisher.Mono;
|
||||
import reactor.util.context.Context;
|
||||
|
||||
import org.springframework.beans.BeansException;
|
||||
import org.springframework.context.ApplicationContext;
|
||||
import org.springframework.core.Ordered;
|
||||
@@ -55,6 +33,8 @@ import org.springframework.security.authorization.AuthorizationDecision;
|
||||
import org.springframework.security.authorization.ReactiveAuthorizationManager;
|
||||
import org.springframework.security.core.Authentication;
|
||||
import org.springframework.security.core.AuthenticationException;
|
||||
import org.springframework.security.core.GrantedAuthority;
|
||||
import org.springframework.security.core.authority.AuthorityUtils;
|
||||
import org.springframework.security.core.context.ReactiveSecurityContextHolder;
|
||||
import org.springframework.security.oauth2.client.InMemoryReactiveOAuth2AuthorizedClientService;
|
||||
import org.springframework.security.oauth2.client.ReactiveOAuth2AuthorizedClientService;
|
||||
@@ -80,6 +60,7 @@ import org.springframework.security.oauth2.core.user.OAuth2User;
|
||||
import org.springframework.security.oauth2.jwt.Jwt;
|
||||
import org.springframework.security.oauth2.jwt.NimbusReactiveJwtDecoder;
|
||||
import org.springframework.security.oauth2.jwt.ReactiveJwtDecoder;
|
||||
import org.springframework.security.oauth2.jwt.ReactiveJwtDecoderFactory;
|
||||
import org.springframework.security.oauth2.server.resource.authentication.JwtAuthenticationConverter;
|
||||
import org.springframework.security.oauth2.server.resource.authentication.JwtReactiveAuthenticationManager;
|
||||
import org.springframework.security.oauth2.server.resource.authentication.ReactiveJwtAuthenticationConverterAdapter;
|
||||
@@ -92,6 +73,7 @@ import org.springframework.security.web.server.MatcherSecurityWebFilterChain;
|
||||
import org.springframework.security.web.server.SecurityWebFilterChain;
|
||||
import org.springframework.security.web.server.ServerAuthenticationEntryPoint;
|
||||
import org.springframework.security.web.server.WebFilterExchange;
|
||||
import org.springframework.security.web.server.authentication.AnonymousAuthenticationWebFilter;
|
||||
import org.springframework.security.web.server.authentication.AuthenticationWebFilter;
|
||||
import org.springframework.security.web.server.authentication.HttpBasicServerAuthenticationEntryPoint;
|
||||
import org.springframework.security.web.server.authentication.RedirectServerAuthenticationEntryPoint;
|
||||
@@ -159,9 +141,27 @@ import org.springframework.web.cors.reactive.DefaultCorsProcessor;
|
||||
import org.springframework.web.server.ServerWebExchange;
|
||||
import org.springframework.web.server.WebFilter;
|
||||
import org.springframework.web.server.WebFilterChain;
|
||||
import org.springframework.security.web.server.authentication.AnonymousAuthenticationWebFilter;
|
||||
import org.springframework.security.core.GrantedAuthority;
|
||||
import org.springframework.security.core.authority.AuthorityUtils;
|
||||
import reactor.core.publisher.Mono;
|
||||
import reactor.util.context.Context;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.PrintWriter;
|
||||
import java.io.StringWriter;
|
||||
import java.security.interfaces.RSAPublicKey;
|
||||
import java.time.Duration;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
import java.util.UUID;
|
||||
import java.util.function.Function;
|
||||
|
||||
import static org.springframework.security.web.server.DelegatingServerAuthenticationEntryPoint.DelegateEntry;
|
||||
import static org.springframework.security.web.server.util.matcher.ServerWebExchangeMatcher.MatchResult.match;
|
||||
import static org.springframework.security.web.server.util.matcher.ServerWebExchangeMatcher.MatchResult.notMatch;
|
||||
|
||||
/**
|
||||
* A {@link ServerHttpSecurity} is similar to Spring Security's {@code HttpSecurity} but for WebFlux.
|
||||
@@ -618,7 +618,14 @@ public class ServerHttpSecurity {
|
||||
boolean oidcAuthenticationProviderEnabled = ClassUtils.isPresent(
|
||||
"org.springframework.security.oauth2.jwt.JwtDecoder", this.getClass().getClassLoader());
|
||||
if (oidcAuthenticationProviderEnabled) {
|
||||
OidcAuthorizationCodeReactiveAuthenticationManager oidc = new OidcAuthorizationCodeReactiveAuthenticationManager(client, getOidcUserService());
|
||||
OidcAuthorizationCodeReactiveAuthenticationManager oidc =
|
||||
new OidcAuthorizationCodeReactiveAuthenticationManager(client, getOidcUserService());
|
||||
ResolvableType type = ResolvableType.forClassWithGenerics(
|
||||
ReactiveJwtDecoderFactory.class, ClientRegistration.class);
|
||||
ReactiveJwtDecoderFactory<ClientRegistration> jwtDecoderFactory = getBeanOrNull(type);
|
||||
if (jwtDecoderFactory != null) {
|
||||
oidc.setJwtDecoderFactory(jwtDecoderFactory);
|
||||
}
|
||||
result = new DelegatingReactiveAuthenticationManager(oidc, result);
|
||||
}
|
||||
return result;
|
||||
|
||||
Reference in New Issue
Block a user