Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Jwt decoding should support multiple algorithms #6883

Closed
rwinch opened this issue May 15, 2019 · 8 comments · Fixed by #7162
Closed

Jwt decoding should support multiple algorithms #6883

rwinch opened this issue May 15, 2019 · 8 comments · Fixed by #7162
Assignees
Labels
in: oauth2 An issue in OAuth2 modules (oauth2-core, oauth2-client, oauth2-resource-server, oauth2-jose) type: enhancement A general enhancement
Milestone

Comments

@rwinch
Copy link
Member

rwinch commented May 15, 2019

Summary

We should add a strategy where Jwt decoders can delegate to other Jwt decoders based upon the algorithm that is in the JWT that was passed into it. This would allow supporting multiple algorithms returned by an IdP as discussed in #5465 (comment)

A possible way to do this would be to have a JwtDecoder implementation that calls other JwtDecoders, though note this might require decoding the JWT twice.

@rwinch rwinch added in: oauth2 An issue in OAuth2 modules (oauth2-core, oauth2-client, oauth2-resource-server, oauth2-jose) type: enhancement A general enhancement labels May 15, 2019
@rwinch rwinch added this to the 5.2.x milestone May 15, 2019
@jzheaux jzheaux changed the title Add JwtDecoder implementation that supports multiple algorithms Jwt decoding should support multiple algorithms May 20, 2019
@dnl50
Copy link
Contributor

dnl50 commented Jun 3, 2019

Would it be possible to implement a JwtDecoder that decodes the header of the given token first to determine the signing algorithm used. The signing algorithm would then be used to find a decoder that supports the signing algorithm.

public class DelegatingJwtDecoder implements JwtDecoder {

	private List<DelegatedJwtDecoder> decoders;

	@Override
	public Jwt decode(String token) throws JwtException {
		String decodedHeader = decodeHeader(token);
		String signingAlg = getSigningAlgorithm(decodedHeader);
		DelegatedJwtDecoder jwtDecoder = findDecoder(signingAlg);

		return jwtDecoder.decode(token);
	}

	private String decodeHeader(String token) {
		// decode the Base64 encoded header of the token
	}

	private String getSigningAlgorithm(String tokenHeader) {
		// get the algorithm from the token header
	}

	private DelegatedJwtDecoder findDecoderSupportingAlgorithm(String algorithm) {
		return decoders.stream()
				.filter(decoder -> decoder.supportsAlgorithm(algorithm))
				.findFirst()
				.orElseThrow(() -> new IllegalArgumentException("No decoder found that support the signing algorithm!"));
	}

}

The DelegatedJwtDecoder would have an additional boolean supportsAlgorithm(String algorithm) method which would receive the signing algorithm the given token was signed with.

public interface DelegatedJwtDecoder extends JwtDecoder {

	boolean supportsAlgorithm(String algorithm);

}

@jgrandja
Copy link
Contributor

jgrandja commented Jun 3, 2019

@dnl50 I believe the example implementation you provided is similar to what @rwinch has suggested. However, I don't believe we need to introduce a new interface DelegatedJwtDecoder with the additional operation supportsAlgorithm().

Instead, we would provide a new implementation of JwtDecoder which would be constructed with a Map of alg to JwtDecoder to allow for this. It might not be a Map but would have to provide this type of mapping.

@compfantasy
Copy link

According to spring security reference, the algorithm can be override by providing a JwtDecoder bean, but it doesn't work after I did that because the initialization of NimbusJwtDecoderJwkSupport locates at line 212 of OidcAuthorizationCodeAuthenticationProvider.java

@jgrandja
Copy link
Contributor

@compfantasy The PR #6495 introduced support in 5.2.0.M2 for a configurable JWS algorithm via OidcIdTokenDecoderFactory.setJwsAlgorithmResolver() or ReactiveOidcIdTokenDecoderFactory.setJwsAlgorithmResolver().

NOTE: NimbusJwtDecoderJwkSupport is deprecated in favour of NimbusJwtDecoder, which is used/configured by OidcIdTokenDecoderFactory.

@compfantasy
Copy link

@jgrandja Does this mean that I just need upgrade current version of spring-security-oauth2-jose-5.1.4.RELEASE to 5.2.0.M2, then configure jwsAlgorithm in client registration? do you have a simple demo project regarding this change?thanks

@compfantasy
Copy link

@jgrandja I already upgraded the version of spring-security-oauth2-client and spring-secuirty-oauth2-core to 5.2.0.M2, I can see there is a class named OidcIdTokenDecoderFactory, but how can i use setJwsAlgorithmResolver() to make JwsAlgorithm working in the spring context? I tried to create a new OidcTokenDecoderFactory bean and set the JwsAlgorithm to RS512, it doesn't work, and I tried to create a new JwtDecoder bean, it doesn't work for me as well, very appreciate if you can help here.

@jgrandja
Copy link
Contributor

@compfantasy Can you please put together a minimal sample so I can see what you have so far and share via a GitHub repository. This will be the most effective way to help resolve this for you.

@jzheaux jzheaux self-assigned this Jul 29, 2019
@jzheaux jzheaux modified the milestones: 5.2.x, 5.2.0.M4 Jul 29, 2019
@jzheaux jzheaux modified the milestones: 5.2.0.M4, 5.2.0.RC1 Aug 5, 2019
jzheaux added a commit to jzheaux/spring-security that referenced this issue Aug 20, 2019
jzheaux added a commit that referenced this issue Aug 20, 2019
kostya05983 pushed a commit to kostya05983/spring-security that referenced this issue Aug 26, 2019
@HungUnicorn
Copy link

HungUnicorn commented Aug 12, 2022

@compfantasy Can you please put together a minimal sample so I can see what you have so far and share via a GitHub repository. This will be the most effective way to help resolve this for you.

Do I need a CustomJwtDecoderFactory like

@Bean
public JwtDecoderFactory<ClientRegistration> customJwtDecoderFactory() {
    return new CustomJwtDecoderFactory();
}

static class CustomJwtDecoderFactory implements JwtDecoderFactory<ClientRegistration> {
    public JwtDecoder createDecoder(ClientRegistration reg) {
        //...

        return new CustomJwtDecoder();
    }
}

then I create different decoders as

JWSKeySelector<SecurityContext> jwsKeySelector =
            JWSAlgorithmFamilyJWSKeySelector.fromJWKSetURL(this.jwkSetUrl);

    DefaultJWTProcessor<SecurityContext> jwtProcessor =
            new DefaultJWTProcessor<>();
    jwtProcessor.setJWSKeySelector(jwsKeySelector);

    return new NimbusJwtDecoder(jwtProcessor);

the problem is how OAuth2LoginAuthenticationFilter can know which decoder to use given the registration?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
in: oauth2 An issue in OAuth2 modules (oauth2-core, oauth2-client, oauth2-resource-server, oauth2-jose) type: enhancement A general enhancement
Projects
None yet
Development

Successfully merging a pull request may close this issue.

6 participants