spring-projects / spring-security

Spring Security
http://spring.io/projects/spring-security
Apache License 2.0
8.6k stars 5.81k forks source link

Support unsigned ID tokens for OIDC #9494

Open ibaskine opened 3 years ago

ibaskine commented 3 years ago

Describe the bug Our attempt to certify our OIDC support with OpenID failed because Spring Security OIDC doesn't support unsigned ID tokens. As OIDC standard requires clients to support unsigned ID tokens I think Spring implementation shall allow them. It can be disallowed by default but it shall be possible to configure filter to support it.

BTW underlying Nimbus library allows unsigned ID tokens.

To Reproduce Just point you sample or any other web application with OIDC filter to OpenID certification site and run the oidcc-client-test-idtoken-sig-none test.

BTW I think it is a good idea to certify every your release.

Expected behavior It shall support unsigned ID tokens.

Sample

A link to a GitHub repository with a minimal, reproducible sample.

Reports that include a sample will take priority over reports that do not. At times, we may require a sample, so it is good to try and include a sample up front.

jgrandja commented 3 years ago

@ibaskine In section 2. ID Token, it states:

ID Tokens MUST be signed using JWS [JWS] and optionally both signed and then encrypted...

ID Tokens MUST NOT use none as the alg value unless the Response Type used returns no ID Token from the Authorization Endpoint (such as when using the Authorization Code Flow) and the Client explicitly requested the use of none at Registration time

I was surprised from the last statement as in that scenario an ID Token could be unsigned. I'm really curious on your use case for this scenario. Can you elaborate so I can better understand?

FYI, this scenario is NOT secure since the ID Token is NOT integrity protected and I don't see why a client should trust the ID Token and ultimately authenticate the user.

jogu commented 3 years ago

FYI, this scenario is NOT secure since the ID Token is NOT integrity protected and I don't see why a client should trust the ID Token and ultimately authenticate the user.

The ID Token in this scenario (response_type=code) is returned from the token endpoint, so is integrity protected by virtue of being returned over a TLS protected channel. (If TLS is broken to the point of not assuring integrity then you have much bigger problems...)

This is why the OpenID Connect standard allows an unsigned id_token to be returned in that case. Even if the id_token is signed, the client is not required to verify the signature as per https://openid.net/specs/openid-connect-core-1_0.html#IDTokenValidation :

If the ID Token is received via direct communication between the Client and the Token Endpoint (which it is in this flow), the TLS server validation MAY be used to validate the issuer in place of checking the token signature.

(I'm not familiar with Spring so if the id_token is being handled by systems other than the original OAuth2 client that received it then the situation is more complicated and what I wrote above is probably not relevant.)

jgrandja commented 3 years ago

@jogu Thanks for pointing this out:

If the ID Token is received via direct communication between the Client and the Token Endpoint (which it is in this flow), the TLS server validation MAY be used to validate the issuer in place of checking the token signature.

I forgot about this conditional validation.

is integrity protected by virtue of being returned over a TLS protected channel

True. But we'll need to determine if the flow was in fact performed over TLS. Local development is usually not and we can't force TLS during local development.

Either way, we need to apply this fix. Would you be interested in submitting a PR for this?

onururan commented 3 years ago

@jgrandja @jogu Do you have any recommendations as a workaround until we get this fix delivered? @ibaskine

jgrandja commented 3 years ago

@ibaskine @onururan @jogu

As a temporary workaround, to allow for unsigned ID tokens, the application can provide a @Bean of type JwtDecoderFactory<ClientRegistration>. The default implementation is OidcIdTokenDecoderFactory.

The custom JwtDecoderFactory<ClientRegistration> would need to return a JwtDecoder associated to a specific ClientRegistration that would accept an unsigned JWT. It would simply just parse the Jwt.

See the reference on how to configure a custom JwtDecoderFactory<ClientRegistration> @Bean.