问题
External OAuth2 Provider doesn't have public JwkUri, so I tried too override default behavior using following code snippet:
@EnableWebSecurity
public class DirectlyConfiguredJwkSetUri extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.antMatchers("**/oauth2/code/esia**", "**/code/esia**", "**esia**").permitAll()
.antMatchers("/user").fullyAuthenticated()
.anyRequest().authenticated()
.and()
.csrf().disable()
.cors().disable()
.oauth2Client()
.clientRegistrationRepository(this.clientRegistrationRepository)
.authorizationCodeGrant()
.authorizationRequestResolver(new CustomAuthorizationRequestResolver(
this.clientRegistrationRepository, esiaConfig, signatureUtil, timeUtil))
.accessTokenResponseClient(customAccessTokenResponseClient())
.and().and().oauth2Login().tokenEndpoint().accessTokenResponseClient(customAccessTokenResponseClient())
.and().and().oauth2ResourceServer().jwt();
}
@Bean
JwtDecoder jwtDecoder() {
return new CustomJwtDecoder();
}
}
class CustomJwtDecoder implements JwtDecoder {
@Override
public Jwt decode(String token) throws JwtException {
System.out.println(token);
return null;
}
}
However Spring Security somehow still uses default realization and I am getting the following error...
[missing_signature_verifier] Failed to find a Signature Verifier for Client Registration: 'esia'. Check to ensure you have configured the JwkSet URI.
Also, I tried to set custom AuthenticationProvider but spring ignores it.
I guess the catch is that spring`s OAuth2LoginConfigurer method init(B http) calls new OidcAuthorizationCodeAuthenticationProvider(accessTokenResponseClient, oidcUserService)
回答1:
For 5.1.3.RELEASE it looks like you cannot get around this problem easily.
It stems from the OidcAuthorizationCodeAuthenticationProvider.getJwtDecoder
This happens in line 156 which is a call to a private method
@Override
public Authentication authenticate(Authentication authentication) throws AuthenticationException {
...
OidcIdToken idToken = createOidcToken(clientRegistration, accessTokenResponse);
...
}
The one option I see is if you make a copy of this code, and modify it yourself. Extending the class itself is not meaningful because all of the logic happens pretty much in the authenticate
method. So you're still overriding it. then you add your provider using the http.authenticationProvider
method
Another option is to override the SecurityConfigurerAdapter.postProcess method of the OAuth2LoginConfigurer
class and do something clever there. Like populating the JWT decoder map through reflection.
Neither are admittedly preferred solutions. I believe that's why the refactoring happened for the 5.2 release.
Given the latest 5.2.x release then You're almost there, but you must override the correct bean
@Bean
public JwtDecoderFactory<ClientRegistration> jwtDecoderFactory() {
final JwtDecoder decoder = jwtDecoder();
return context -> decoder;
}
and if you don't want to use lambdas
@Bean
public JwtDecoderFactory<ClientRegistration> jwtDecoderFactory() {
final JwtDecoder decoder = jwtDecoder();
return new JwtDecoderFactory<ClientRegistration>() {
@Override
public JwtDecoder createDecoder(ClientRegistration context) {
return decoder;
}
};
}
How did I figure this out, well I took a look at the OAuth2LoginConfigurer.java class which does
JwtDecoderFactory<ClientRegistration> jwtDecoderFactory = getJwtDecoderFactoryBean();
and the private method that fetches the bean look like this
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;
}
回答2:
I was facing the same issue even with 5.2.x release. In my case, the real problem was not in the JwtDecoder. I have fixed the issue by setting the jwk-set-uri property (you can change the provider name by the provider which you are using e.g okta, google etc.) :
security.oauth2.client.provider.azure.jwk-set-uri: https://login.microsoftonline.com/{tenant}/discovery/keys
来源:https://stackoverflow.com/questions/54512182/spring-jwt-decoder-openid-token