Skip to content

Getting error java.lang.IllegalArgumentException For Authorization Code flow with JDBCUserDetailService, JDBC Registered Client and JDBCAutjorization Service: The class with pk.training.basit.jpa.entity.UserPrincipal and name of pk.training.basit.jpa.entity.UserPrincipal is not in the allowlist. #397

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

Closed
Basit-Mahmood opened this issue Aug 16, 2021 · 8 comments
Assignees
Labels
status: invalid An issue that we don't feel is valid

Comments

@Basit-Mahmood
Copy link

Basit-Mahmood commented Aug 16, 2021

Describe the bug
With JDBCUserDetailService, JdbcRegisteredClientRepository with AuthorizationGrantType.AUTHORIZATION_CODE and JdbcOAuth2AuthorizationConsentService. While fetching the token will result in following error

`java.lang.IllegalArgumentException: The class with pk.training.basit.jpa.entity.UserPrincipal and name of pk.training.basit.jpa.entity.UserPrincipal 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) ~[spring-security-oauth2-authorization-server-0.1.2.jar:0.1.2]
at org.springframework.security.oauth2.server.authorization.JdbcOAuth2AuthorizationService$OAuth2AuthorizationRowMapper.mapRow(JdbcOAuth2AuthorizationService.java:337) ~[spring-security-oauth2-authorization-server-0.1.2.jar:0.1.2]
at org.springframework.security.oauth2.server.authorization.JdbcOAuth2AuthorizationService$OAuth2AuthorizationRowMapper.mapRow(JdbcOAuth2AuthorizationService.java:308) ~[spring-security-oauth2-authorization-server-0.1.2.jar:0.1.2]
at org.springframework.jdbc.core.RowMapperResultSetExtractor.extractData(RowMapperResultSetExtractor.java:94) ~[spring-jdbc-5.3.9.jar:5.3.9]
at org.springframework.jdbc.core.RowMapperResultSetExtractor.extractData(RowMapperResultSetExtractor.java:61) ~[spring-jdbc-5.3.9.jar:5.3.9]
at org.springframework.jdbc.core.JdbcTemplate$1.doInPreparedStatement(JdbcTemplate.java:723) ~[spring-jdbc-5.3.9.jar:5.3.9]
at org.springframework.jdbc.core.JdbcTemplate.execute(JdbcTemplate.java:651) ~[spring-jdbc-5.3.9.jar:5.3.9]
at org.springframework.jdbc.core.JdbcTemplate.query(JdbcTemplate.java:713) ~[spring-jdbc-5.3.9.jar:5.3.9]
at org.springframework.jdbc.core.JdbcTemplate.query(JdbcTemplate.java:744) ~[spring-jdbc-5.3.9.jar:5.3.9]
at org.springframework.jdbc.core.JdbcTemplate.query(JdbcTemplate.java:799) ~[spring-jdbc-5.3.9.jar:5.3.9]
at org.springframework.security.oauth2.server.authorization.JdbcOAuth2AuthorizationService.findBy(JdbcOAuth2AuthorizationService.java:257) ~[spring-security-oauth2-authorization-server-0.1.2.jar:0.1.2]
at org.springframework.security.oauth2.server.authorization.JdbcOAuth2AuthorizationService.findByToken(JdbcOAuth2AuthorizationService.java:244) ~[spring-security-oauth2-authorization-server-0.1.2.jar:0.1.2]
at org.springframework.security.oauth2.server.authorization.authentication.OAuth2AuthorizationCodeAuthenticationProvider.authenticate(OAuth2AuthorizationCodeAuthenticationProvider.java:114) ~[spring-security-oauth2-authorization-server-0.1.2.jar:0.1.2]
at org.springframework.security.authentication.ProviderManager.authenticate(ProviderManager.java:182) ~[spring-security-core-5.5.1.jar:5.5.1]
at org.springframework.security.oauth2.server.authorization.web.OAuth2TokenEndpointFilter.doFilterInternal(OAuth2TokenEndpointFilter.java:164) ~[spring-security-oauth2-authorization-server-0.1.2.jar:0.1.2]`

To Reproduce

  1. Setup a JDBCUserDetail Service.
  2. Setup JdbcRegisteredClientRepository with RegisteredClient having AuthorizationGrantType.AUTHORIZATION_CODE
  3. Setup JdbcOAuth2AuthorizationService
  4. Try to get the token with Authorization Code flow.
  5. The above mentioned error will occur.

Expected behavior
The token response should be generating fine

Sample

Ch1-09-SpringAuthorizationServer-0.1.2.zip

Ch1-08-SpringAuthorizationServer-0.1.1-ResourceServer.zip

Ch1-08-SpringAuthorizationServer-0.1.1-Client.zip

Attached are three projects. All are gradle projects. Should be imported fine in eclipse.

Change the database setting present in Ch1-09-SpringAuthorizationServer-0.1.2/src/main/resources/application.properties file

Run the database scripts present in Ch1-09-SpringAuthorizationServer-0.1.2/src/main/resources/database/scripts. This will create the table and enter the user in table.

All the urls are present in properties file application.properties for all three projects.

Run all three projects. When Ch1-09-SpringAuthorizationServer-0.1.2 will run. Registered client will enter in database. All projects will run on different ports. After running all the projects. Do the following

  1. Open the url in browser http://127.0.0.1:8080/springauthorizationserverclient-0.1.1
  2. Login with username user1 and password password
  3. Three types will be presented. Authorization Code, Client Credentials and Password.
  4. Click on Password. Proper response will come
  5. Now click on Authorization Code.
  6. In the browser Authorization Server Login page will open. Type username user1 and password password. (Please run the database script for this user as told above)
  7. Error will occur.

In class org.springframework.security.oauth2.server.authorization.authentication.OAuth2AuthorizationCodeAuthenticationProvider at line

OAuth2Authorization authorization = this.authorizationService.findByToken( authorizationCodeAuthentication.getCode(), AUTHORIZATION_CODE_TOKEN_TYPE);

Error generates. After getting the result from database.

Thanks

@Basit-Mahmood Basit-Mahmood added the type: bug A general bug label Aug 16, 2021
@jimrinhealthcare
Copy link

jimrinhealthcare commented Aug 17, 2021

You should be able to add a mixin for your class as follows in your auth server config:

	@Bean
	public OAuth2AuthorizationService authorizationService(JdbcTemplate jdbcTemplate,
			RegisteredClientRepository registeredClientRepository) {
		JdbcOAuth2AuthorizationService service = new JdbcOAuth2AuthorizationService(jdbcTemplate, registeredClientRepository);
		JdbcOAuth2AuthorizationService.OAuth2AuthorizationRowMapper rowMapper = new JdbcOAuth2AuthorizationService.OAuth2AuthorizationRowMapper(registeredClientRepository);
		
		ObjectMapper objectMapper = new ObjectMapper();
		ClassLoader classLoader = JdbcOAuth2AuthorizationService.class.getClassLoader();
		List<Module> securityModules = SecurityJackson2Modules.getModules(classLoader);
		objectMapper.registerModules(securityModules);
		objectMapper.registerModule(new OAuth2AuthorizationServerJackson2Module());
                // You will need to write the Mixin for your class so Jackson can marshall it.
		objectMapper.addMixIn(UserPrincipal .class, UserPrincipalMixin.class);
		rowMapper.setObjectMapper(objectMapper);
		service.setAuthorizationRowMapper(rowMapper);
		return service;
	}

I'd be interested to learn if there's a neater way though.

@jgrandja
Copy link
Collaborator

@jimrinhealthcare Thanks for providing the sample configuration !

@Basit-Mahmood Since pk.training.basit.jpa.entity.UserPrincipal is defined by your application, it needs to be explicitly configured in ObjectMapper. This sample configuration is exactly how you would go about configuring it along with your Mixin class.

@jgrandja jgrandja self-assigned this Aug 20, 2021
@jgrandja jgrandja added status: invalid An issue that we don't feel is valid and removed type: bug A general bug labels Aug 20, 2021
kinsersh added a commit to kinsersh/spring-authorization-server that referenced this issue May 18, 2022
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": "[email protected]",
                "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": "[email protected]"
              }
            }
          },
          {
            "@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": "[email protected]",
          "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": "[email protected]"
        }
      },
      "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": "[email protected]",
              "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": "[email protected]"
            }
          }
        },
        {
          "@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"
    ]
  ]
}
@mdismaeel
Copy link

It is not clear why java.lang.Long is considered duplicate of this issue which is related to JDBCUserDetailService. Can you please let me know, if you are suggesting to write mixins for all JDK classes this way? Why doesn't default typing work for java.lang.Long?

@kubav182
Copy link

kubav182 commented Jan 7, 2025

It is not clear why java.lang.Long is considered duplicate of this issue which is related to JDBCUserDetailService. Can you please let me know, if you are suggesting to write mixins for all JDK classes this way? Why doesn't default typing work for java.lang.Long?

@jgrandja can you please confirm we need to write mixin for Long type? I would not expect this. Or is there another way?

@jgrandja
Copy link
Collaborator

jgrandja commented Jan 7, 2025

@kubav182 I did not provide a response to the comment you are referencing so please do not confuse with the original issue, which is related to pk.training.basit.jpa.entity.UserPrincipal. Please see this comment

@kubav182
Copy link

kubav182 commented Jan 7, 2025

@jgrandja You closed issue #567 as a duplicity of this issue. Thats why I'm asking same as @mdismaeel was asking. Sorry if it was not clear. For me it is not clear why issue about java.lang.Long was closed as duplicity to this issue about pk.training.basit.jpa.entity.UserPrincipal. One would expect the solution is the same, but it sounds strange we need to configure object mapper for classes like java.lang.Long

@jgrandja
Copy link
Collaborator

jgrandja commented Jan 7, 2025

@kubav182 Sorry for the confusion. Please see gh-743 for further context.

@kubav182
Copy link

kubav182 commented Jan 7, 2025

@jgrandja thanks for clarification

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
status: invalid An issue that we don't feel is valid
Projects
None yet
Development

No branches or pull requests

5 participants