-
Notifications
You must be signed in to change notification settings - Fork 1.2k
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
Access token with custom claims having value Long is throwing error: The class with java.lang.Long and name of java.lang.Long is not in the allowlist. #567
Comments
Closing as duplicate of gh-397 |
I'm seeing this same issue when attempting to use Spring Authorization Server with Okta, where the token from Okta contains a claim as follows:
It fails with the exception described in this issue after the OAuth 2 with Okta is complete and Spring Authorization Server has issued an authorization code to a relying party, and when the relying party is exchanging the authorization code for an access token. |
Okta includes a "ver" claim in the ID tokens it issues that gets serialized to json, as follows: { "@Class": "java.util.Collections$UnmodifiableMap", "ver": [ "java.lang.Long", 1 ] } This claim is added by Okta automatically (see https://developer.okta.com/docs/reference/api/oidc/#id-token). Spring Authorization Server encounters an error when attempting to deserialize this claim from Okta, as follows: The class with java.lang.Long and name of java.lang.Long is not in the allowlist. If you believe this class is safe to deserialize, please provide an explicit mapping using Jackson annotations or by providing a Mixin. If the serialization is only done by a trusted source, you can also enable default typing. See spring-projects/spring-security#4370 for details java.lang.IllegalArgumentException: The class with java.lang.Long and name of java.lang.Long is not in the allowlist. If you believe this class is safe to deserialize, please provide an explicit mapping using Jackson annotations or by providing a Mixin. If the serialization is only done by a trusted source, you can also enable default typing. See spring-projects/spring-security#4370 for details at org.springframework.security.jackson2.SecurityJackson2Modules$AllowlistTypeIdResolver.typeFromId(SecurityJackson2Modules.java:253) The issue at spring-projects#567 has a similar symptom, though this situation would be encountered by any project wanting to do OpenID Connect with Okta. I thus recommend a general fix rather than a project-specific fix as recommended at spring-projects#397. This commit defines a mixin that doesn't alter the json formatting but does instruct SecurityJackson2Modules.AllowlistTypeIdResolver to permit the deseralization of that Okta claim. For broader context, below is an example of what is stored by Spring Authorization Server in the attributes column of the oauth2_authorization table. { "@Class": "java.util.Collections$UnmodifiableMap", "org.springframework.security.oauth2.core.endpoint.OAuth2AuthorizationRequest": { "@Class": "org.springframework.security.oauth2.core.endpoint.OAuth2AuthorizationRequest", "authorizationUri": "http://localhost:5000/oauth2/authorize", "authorizationGrantType": { "value": "authorization_code" }, "responseType": { "value": "code" }, "clientId": "login-acceptance-test-client", "redirectUri": "http://127.0.0.1:5000/login-acceptance-test-client", "scopes": [ "java.util.Collections$UnmodifiableSet", [ "openid" ] ], "state": "foo", "additionalParameters": { "@Class": "java.util.Collections$UnmodifiableMap" }, "authorizationRequestUri": "http://localhost:5000/oauth2/authorize?response_type=code&client_id=login-acceptance-test-client&scope=openid&state=foo&redirect_uri=http://127.0.0.1:5000/login-acceptance-test-client", "attributes": { "@Class": "java.util.Collections$UnmodifiableMap" } }, "java.security.Principal": { "@Class": "org.springframework.security.oauth2.client.authentication.OAuth2AuthenticationToken", "principal": { "@Class": "org.springframework.security.oauth2.core.oidc.user.DefaultOidcUser", "authorities": [ "java.util.Collections$UnmodifiableSet", [ { "@Class": "org.springframework.security.oauth2.core.oidc.user.OidcUserAuthority", "authority": "ROLE_USER", "idToken": { "@Class": "org.springframework.security.oauth2.core.oidc.OidcIdToken", "tokenValue": "actualTokenValueRemoved", "issuedAt": 1652411922.000000000, "expiresAt": 1652415522.000000000, "claims": { "@Class": "java.util.Collections$UnmodifiableMap", "at_hash": "X4TpvHXTMw3kaBMRas-H6A", "sub": "00u4zn2e0w8cRRFv75d1", "ver": [ "java.lang.Long", 1 ], "amr": [ "java.util.ArrayList", [ "pwd" ] ], "iss": [ "java.net.URL", "https://dev-231911394952.okta.com" ], "preferred_username": "login.at.okta.public.local", "nonce": "pWQDfOxvpslr_FWiTqHlIRdCiT5Sfq-PWvBmSyrDki0", "aud": [ "java.util.ArrayList", [ "0oa4varwxxjIMcDph5d7" ] ], "idp": "00otba6t5x5dSt78H5d6", "auth_time": [ "java.time.Instant", 1652411920.000000000 ], "name": "login at okta public local test", "exp": [ "java.time.Instant", 1652415522.000000000 ], "iat": [ "java.time.Instant", 1652411922.000000000 ], "email": "login.at.okta.public.local@example.com", "jti": "ID.IfAKG8WvCxOy023DLl6I-WY-4pHgxMJZv1F79rqAtYM" } }, "userInfo": { "@Class": "org.springframework.security.oauth2.core.oidc.OidcUserInfo", "claims": { "@Class": "java.util.Collections$UnmodifiableMap", "sub": "00u4zn2e0w8cRRFv75d1", "zoneinfo": "America/Los_Angeles", "email_verified": true, "updated_at": [ "java.time.Instant", 1652216788.000000000 ], "name": "login at okta public local test", "preferred_username": "login.at.okta.public.local", "locale": "en_US", "given_name": "login at okta public local", "family_name": "test", "email": "login.at.okta.public.local@example.com" } } }, { "@Class": "org.springframework.security.core.authority.SimpleGrantedAuthority", "authority": "SCOPE_email" }, { "@Class": "org.springframework.security.core.authority.SimpleGrantedAuthority", "authority": "SCOPE_openid" }, { "@Class": "org.springframework.security.core.authority.SimpleGrantedAuthority", "authority": "SCOPE_phone" }, { "@Class": "org.springframework.security.core.authority.SimpleGrantedAuthority", "authority": "SCOPE_profile" } ] ], "idToken": { "@Class": "org.springframework.security.oauth2.core.oidc.OidcIdToken", "tokenValue": "actualTokenValueRemoved", "issuedAt": 1652411922.000000000, "expiresAt": 1652415522.000000000, "claims": { "@Class": "java.util.Collections$UnmodifiableMap", "at_hash": "X4TpvHXTMw3kaBMRas-H6A", "sub": "00u4zn2e0w8cRRFv75d1", "ver": [ "java.lang.Long", 1 ], "amr": [ "java.util.ArrayList", [ "pwd" ] ], "iss": [ "java.net.URL", "https://dev-231911394952.okta.com" ], "preferred_username": "login.at.okta.public.local", "nonce": "pWQDfOxvpslr_FWiTqHlIRdCiT5Sfq-PWvBmSyrDki0", "aud": [ "java.util.ArrayList", [ "0oa4varwxxjIMcDph5d7" ] ], "idp": "00otba6t5x5dSt78H5d6", "auth_time": [ "java.time.Instant", 1652411920.000000000 ], "name": "login at okta public local test", "exp": [ "java.time.Instant", 1652415522.000000000 ], "iat": [ "java.time.Instant", 1652411922.000000000 ], "email": "login.at.okta.public.local@example.com", "jti": "ID.IfAKG8WvCxOy023DLl6I-WY-4pHgxMJZv1F79rqAtYM" } }, "userInfo": { "@Class": "org.springframework.security.oauth2.core.oidc.OidcUserInfo", "claims": { "@Class": "java.util.Collections$UnmodifiableMap", "sub": "00u4zn2e0w8cRRFv75d1", "zoneinfo": "America/Los_Angeles", "email_verified": true, "updated_at": [ "java.time.Instant", 1652216788.000000000 ], "name": "login at okta public local test", "preferred_username": "login.at.okta.public.local", "locale": "en_US", "given_name": "login at okta public local", "family_name": "test", "email": "login.at.okta.public.local@example.com" } }, "nameAttributeKey": "sub" }, "authorities": [ "java.util.Collections$UnmodifiableRandomAccessList", [ { "@Class": "org.springframework.security.oauth2.core.oidc.user.OidcUserAuthority", "authority": "ROLE_USER", "idToken": { "@Class": "org.springframework.security.oauth2.core.oidc.OidcIdToken", "tokenValue": "actualTokenValueRemoved", "issuedAt": 1652411922.000000000, "expiresAt": 1652415522.000000000, "claims": { "@Class": "java.util.Collections$UnmodifiableMap", "at_hash": "X4TpvHXTMw3kaBMRas-H6A", "sub": "00u4zn2e0w8cRRFv75d1", "ver": [ "java.lang.Long", 1 ], "amr": [ "java.util.ArrayList", [ "pwd" ] ], "iss": [ "java.net.URL", "https://dev-231911394952.okta.com" ], "preferred_username": "login.at.okta.public.local", "nonce": "pWQDfOxvpslr_FWiTqHlIRdCiT5Sfq-PWvBmSyrDki0", "aud": [ "java.util.ArrayList", [ "0oa4varwxxjIMcDph5d7" ] ], "idp": "00otba6t5x5dSt78H5d6", "auth_time": [ "java.time.Instant", 1652411920.000000000 ], "name": "login at okta public local test", "exp": [ "java.time.Instant", 1652415522.000000000 ], "iat": [ "java.time.Instant", 1652411922.000000000 ], "email": "login.at.okta.public.local@example.com", "jti": "ID.IfAKG8WvCxOy023DLl6I-WY-4pHgxMJZv1F79rqAtYM" } }, "userInfo": { "@Class": "org.springframework.security.oauth2.core.oidc.OidcUserInfo", "claims": { "@Class": "java.util.Collections$UnmodifiableMap", "sub": "00u4zn2e0w8cRRFv75d1", "zoneinfo": "America/Los_Angeles", "email_verified": true, "updated_at": [ "java.time.Instant", 1652216788.000000000 ], "name": "login at okta public local test", "preferred_username": "login.at.okta.public.local", "locale": "en_US", "given_name": "login at okta public local", "family_name": "test", "email": "login.at.okta.public.local@example.com" } } }, { "@Class": "org.springframework.security.core.authority.SimpleGrantedAuthority", "authority": "SCOPE_email" }, { "@Class": "org.springframework.security.core.authority.SimpleGrantedAuthority", "authority": "SCOPE_openid" }, { "@Class": "org.springframework.security.core.authority.SimpleGrantedAuthority", "authority": "SCOPE_phone" }, { "@Class": "org.springframework.security.core.authority.SimpleGrantedAuthority", "authority": "SCOPE_profile" } ] ], "authorizedClientRegistrationId": "oktaDev", "details": { "@Class": "org.springframework.security.web.authentication.WebAuthenticationDetails", "remoteAddress": "127.0.0.1", "sessionId": "A8634EA2537A251E8B3D22A5CC4A6E3D" } }, "org.springframework.security.oauth2.server.authorization.OAuth2Authorization.AUTHORIZED_SCOPE": [ "java.util.Collections$UnmodifiableSet", [ "openid" ] ] }
Describe the bug
Custom access token with claim having value as Long is not getting revoked as during deserialization of access token object mapper throws error.
To Reproduce
User this access token to verify the deserialisation is failing
{"@Class":"java.util.Collections$UnmodifiableMap","metadata.token.claims":{"@Class":"java.util.Collections$UnmodifiableMap","sub":"535","user-authorities":["java.util.ArrayList",["ROLE_AUTHENTICATED"]],"iss":["java.net.URL","http://xxxxxxxl"],"userId":["java.lang.Long",535],"aud":["java.util.Collections$SingletonList",["messaging-client"]],"nbf":["java.time.Instant",1641370496.488606000],"permissions":["java.util.HashSet",[]],"scope":["java.util.Collections$UnmodifiableSet",["message.read"]],"name":"abcd","exp":["java.time.Instant",1641374096.488606000],"iat":["java.time.Instant",1641370496.488606000],"email":"abcd@gmail.com"},"metadata.token.invalidated":false}
Expected behavior
Access token should be properly deserialized and access token should be revoked.
Exception:
java.lang.IllegalArgumentException: The class with java.lang.Long and name of java.lang.Long is not in the allowlist. If you believe this class is safe to deserialize, please provide an explicit mapping using Jackson annotations or by providing a Mixin. If the serialization is only done by a trusted source, you can also enable default typing. See spring-projects/spring-security#4370 for details
at org.springframework.security.oauth2.server.authorization.JdbcOAuth2AuthorizationService$OAuth2AuthorizationRowMapper.parseMap(JdbcOAuth2AuthorizationService.java:441)
at org.springframework.security.oauth2.server.authorization.JdbcOAuth2AuthorizationService$OAuth2AuthorizationRowMapper.mapRow(JdbcOAuth2AuthorizationService.java:370)
at org.springframework.security.oauth2.server.authorization.JdbcOAuth2AuthorizationService$OAuth2AuthorizationRowMapper.mapRow(JdbcOAuth2AuthorizationService.java:308)
at org.springframework.jdbc.core.RowMapperResultSetExtractor.extractData(RowMapperResultSetExtractor.java:94)
at org.springframework.jdbc.core.RowMapperResultSetExtractor.extractData(RowMapperResultSetExtractor.java:61)
at org.springframework.jdbc.core.JdbcTemplate$1.doInPreparedStatement(JdbcTemplate.java:723)
at org.springframework.jdbc.core.JdbcTemplate.execute(JdbcTemplate.java:651)
at org.springframework.jdbc.core.JdbcTemplate.query(JdbcTemplate.java:713)
at org.springframework.jdbc.core.JdbcTemplate.query(JdbcTemplate.java:744)
at org.springframework.jdbc.core.JdbcTemplate.query(JdbcTemplate.java:799)
at org.springframework.security.oauth2.server.authorization.JdbcOAuth2AuthorizationService.findBy(JdbcOAuth2AuthorizationService.java:257)
at org.springframework.security.oauth2.server.authorization.JdbcOAuth2AuthorizationService.findByToken(JdbcOAuth2AuthorizationService.java:238)
at org.springframework.security.oauth2.server.authorization.authentication.OAuth2TokenRevocationAuthenticationProvider.authenticate(OAuth2TokenRevocationAuthenticationProvider.java:63)
at org.springframework.security.authentication.ProviderManager.authenticate(ProviderManager.java:182)
at org.springframework.security.oauth2.server.authorization.web.OAuth2TokenRevocationEndpointFilter.doFilterInternal(OAuth2TokenRevocationEndpointFilter.java:104)
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:119)
The text was updated successfully, but these errors were encountered: