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

2.1.0 oidc login failure #4791

Closed
3 tasks done
Shelby-Jiao opened this issue Mar 13, 2023 · 20 comments
Closed
3 tasks done

2.1.0 oidc login failure #4791

Shelby-Jiao opened this issue Mar 13, 2023 · 20 comments
Labels

Comments

@Shelby-Jiao
Copy link

Shelby-Jiao commented Mar 13, 2023

  • I have checked the discussions
  • I have searched the issues of this repository and believe that this is not a duplicate.
  • I have checked the FAQ of this repository and believe that this is not a duplicate.

Describe the bug
2.1.0 login with oidc, it seems like there're some oidc issues

Expected behavior
portal login with oidc

Screenshots
image

Additional Details & Logs

@Shelby-Jiao Shelby-Jiao changed the title 2.1.0 login failure 2.1.0 oidc login failure Mar 13, 2023
@nobodyiam
Copy link
Member

Please refer the upgrade steps in 2.1.0 release note.

image

@Shelby-Jiao
Copy link
Author

Hi @nobodyiam , thanks for the hint, but the interesting thing is if i disable oidc login just use github,auth in config.profile block portal works fine, such problem only occurs once i enable oidc feature, which confused me a lot

@wood-run
Copy link

Looks like something went wrong when deserializing the oidc info:

Caused by: com.fasterxml.jackson.databind.JsonMappingException: 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 https://github.com/spring-projects/spring-security/issues/4370 for details (through reference chain: org.springframework.security.core.context.SecurityContextImpl["authentication"]->org.springframework.security.oauth2.client.authentication.OAuth2AuthenticationToken["principal"]->org.springframework.security.oauth2.core.oidc.user.DefaultOidcUser["authorities"]->org.springframework.security.oauth2.core.oidc.user.OidcUserAuthority["idToken"]->org.springframework.security.oauth2.core.oidc.OidcIdToken["claims"])

@nobodyiam
Copy link
Member

Hi @nobodyiam , thanks for the hint, but the interesting thing is if i disable oidc login just use github,auth in config.profile block portal works fine, such problem only occurs once i enable oidc feature, which confused me a lot

Did you switch the authentication from default auth to oidc? You may also try to clean the spring sessions to see if it works.

@Shelby-Jiao
Copy link
Author

Shelby-Jiao commented Mar 20, 2023

Hi @nobodyiam , followed the migration step, make sure the authentication is github,oidc and tried to clean the spring sessions before and after deploy portal service to make sure there's no data in those table, unfortunately the issues occurs again. (i'm sure that the first of oidc login is succeed cuz i can see the okta login log)
More detailed thing is we deployed admin and config service with 2 replicasets in separate nodes ( anti-affinity enabled ) and the error log is just as @wood-run said, as below
apollo-portal (19).txt

Thanks in advance!

@nobodyiam
Copy link
Member

I haven't tested with oidc login but it seems related to the spring security version update.
cc @klboke @vdisk-group have you met this error before?

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

@Shelby-Jiao
Copy link
Author

Thanks in advance!

@vdiskg
Copy link
Contributor

vdiskg commented Mar 21, 2023

it seems to be a bug in spring security. the OidcIdToken can not be deserialize when claims contains a value of java.lang.Long, java.lang.Character, java.lang.Short, java.lang.Float, java.lang.Byte

image

@vdiskg
Copy link
Contributor

vdiskg commented Mar 21, 2023

spring-projects/spring-security#12917

@vdiskg
Copy link
Contributor

vdiskg commented Mar 21, 2023

you can try to add an environment variable for disabled the jdbc session to temporarily resolve this

SPRING_SESSION_STORE_TYPE=none

@Shelby-Jiao
Copy link
Author

Hi group, after add the env variable it seems like a workaround, just want to know if there's any config in protal so that we can just use profile/email for display name without uuid? Detail shows as below
image
we do not want to show uuid even if we already had config in protal like
image
@nobodyiam

@zerda
Copy link

zerda commented Apr 13, 2023

We encountered same problem when updating from 2.0.1 to 2.1.0, while portal was integrated with GitLab IdP.

It refers to com.nimbusds.jose.shaded.json.JSONArray in the error message.

The class with com.nimbusds.jose.shaded.json.JSONArray and name of com.nimbusds.jose.shaded.json.JSONArray 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 https://github.com/spring-projects/spring-security/issues/4370 for details

through reference chain: 
org.springframework.security.core.context.SecurityContextImpl["authentication"]
    ->org.springframework.security.oauth2.client.authentication.OAuth2AuthenticationToken["principal"]
    ->org.springframework.security.oauth2.core.oidc.user.DefaultOidcUser["authorities"]
    ->org.springframework.security.oauth2.core.oidc.user.OidcUserAuthority["idToken"]
    ->org.springframework.security.oauth2.core.oidc.OidcIdToken["claims"]

GitLab's issued idToken has several claims (such as groups_direct) that are array types, which will be deserialized as com.nimbusds.jose.shaded.json.JSONArray by Spring Security.

{
    "iss": "https://gitlab.example.com",
    "sub": "106",
    "aud": "<REDACTED>",
    "exp": 1681280989,
    "iat": 1681280869,
    "nonce": "uSD5tXSrl_0KSgylHL3uUzYEeKSPltPYov7i588EeDM",
    "auth_time": 1681279017,
    "sub_legacy": "<REDACTED>",
    "email": "foo@bar.com",
    "email_verified": true,
    "groups_direct": [
        "group1/sub-group1",
        "group2"
    ]
}

According to spring-projects/spring-security#12108, because SecurityJackson2Modules lack the JSONArray mixin, deserialization fails while reading from JdbcIndexedSessionRepository.

Here is a unit test that reproduce this issue.

  @Test
  public void testConversionService() {
    // prepare JWT decoder with HS256 alg
    String jwtSecret = "MY_APPLICATION_JWT_SECRET_KEY_DUMMY";
    SecretKey secretKey = new SecretKeySpec(jwtSecret.getBytes(StandardCharsets.UTF_8), "HmacSHA256");
    NimbusJwtDecoder jwtDecoder = NimbusJwtDecoder.withSecretKey(secretKey).build();

    // prepare idToken
    String idToken = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyLCJncm91cHNfZGlyZWN0IjpbImdyb3VwMS9zdWItZ3JvdXAxIiwiZ3JvdXAyIl19.OQDbCoothbZR_2uLTpCb9tD0arxOsK0LB4p0H_2gDHM";
    Jwt jwt = jwtDecoder.decode(idToken);
    OidcIdToken oidcIdToken = new OidcIdToken(idToken, jwt.getIssuedAt(), jwt.getExpiresAt(), jwt.getClaims());

    // test conversion
    ConversionService conversionService = new SpringSessionConfig().springSessionConversionService();
    // serialize oidcIdToken to byte[]
    byte[] serialized = (byte[]) conversionService.convert(oidcIdToken, TypeDescriptor.valueOf(Object.class),
            TypeDescriptor.valueOf(byte[].class));
    // deserialize byte[] to OidcIdToken
    Object deserialized = conversionService.convert(serialized, TypeDescriptor.valueOf(byte[].class),
            TypeDescriptor.valueOf(Object.class));
    Assert.assertTrue(deserialized instanceof OidcIdToken);
  }

@nobodyiam
Copy link
Member

@zerda

Thank you for sharing the comprehensive details. It appears the problem is not associated with the Spring Security update, as I encountered the same errors when executing the following code in version 2.0.1. Do you have any suggestion on how to
solve this issue? cc @klboke

  @Test
  public void testConversionService() {
    // prepare JWT decoder with HS256 alg
    String jwtSecret = "MY_APPLICATION_JWT_SECRET_KEY_DUMMY";
    SecretKey secretKey = new SecretKeySpec(jwtSecret.getBytes(StandardCharsets.UTF_8), "HmacSHA256");
    NimbusJwtDecoder jwtDecoder = NimbusJwtDecoder.withSecretKey(secretKey).build();

    // prepare idToken
    String idToken = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyLCJncm91cHNfZGlyZWN0IjpbImdyb3VwMS9zdWItZ3JvdXAxIiwiZ3JvdXAyIl19.OQDbCoothbZR_2uLTpCb9tD0arxOsK0LB4p0H_2gDHM";
    Jwt jwt = jwtDecoder.decode(idToken);
    OidcIdToken oidcIdToken = new OidcIdToken(idToken, jwt.getIssuedAt(), jwt.getExpiresAt(), jwt.getClaims());

    // test conversion
    ConversionService conversionService = springSessionConversionService();
    // serialize oidcIdToken to byte[]
    byte[] serialized = (byte[]) conversionService.convert(oidcIdToken, TypeDescriptor.valueOf(Object.class),
        TypeDescriptor.valueOf(byte[].class));
    // deserialize byte[] to OidcIdToken
    Object deserialized = conversionService.convert(serialized, TypeDescriptor.valueOf(byte[].class),
        TypeDescriptor.valueOf(Object.class));
    Assert.assertTrue(deserialized instanceof OidcIdToken);
  }

  public ConversionService springSessionConversionService() {
    GenericConversionService conversionService = new GenericConversionService();
    ObjectMapper objectMapper = new ObjectMapper();
    objectMapper.registerModules(SecurityJackson2Modules.getModules(this.getClass().getClassLoader()));

    conversionService.addConverter(Object.class, byte[].class, source -> {
      try {
        return objectMapper.writeValueAsBytes(source);
      } catch (IOException e) {
        throw new RuntimeException(
            "Spring-session JSON serializing error, This is usually caused by the system upgrade, please clear the browser cookies and try again.",
            e);
      }
    });

    conversionService.addConverter(byte[].class, Object.class, source -> {
      try {
        return objectMapper.readValue(source, Object.class);
      } catch (IOException e) {
        throw new RuntimeException(
            "Spring-session JSON deserializing error, This is usually caused by the system upgrade, please clear the browser cookies and try again.",
            e);
      }
    });
    return conversionService;
  }

@stale
Copy link

stale bot commented May 16, 2023

This issue has been automatically marked as stale because it has not had activity in the last 30 days. It will be closed in 7 days unless it is tagged "help wanted" or other activity occurs. Thank you for your contributions.

@stale stale bot added the stale label May 16, 2023
@stale
Copy link

stale bot commented May 23, 2023

This issue has been automatically closed because it has not had activity in the last 7 days. If this issue is still valid, please ping a maintainer and ask them to label it as "help wanted". Thank you for your contributions.

@stale stale bot closed this as completed May 23, 2023
@Shelby-Jiao
Copy link
Author

any updates on it?

@nobodyiam nobodyiam reopened this May 25, 2023
@stale stale bot removed the stale label May 25, 2023
@stale
Copy link

stale bot commented Jun 24, 2023

This issue has been automatically marked as stale because it has not had activity in the last 30 days. It will be closed in 7 days unless it is tagged "help wanted" or other activity occurs. Thank you for your contributions.

@stale stale bot added the stale label Jun 24, 2023
@stale
Copy link

stale bot commented Jul 1, 2023

This issue has been automatically closed because it has not had activity in the last 7 days. If this issue is still valid, please ping a maintainer and ask them to label it as "help wanted". Thank you for your contributions.

@stale stale bot closed this as completed Jul 1, 2023
@ThuWangzw
Copy link

After setting SPRING_SESSION_STORE_TYPE=none, I received a new error. Any idea on this problem?
image

@kyleli666
Copy link

kyleli666 commented Jan 12, 2024

@zerda

Thank you for sharing the comprehensive details. It appears the problem is not associated with the Spring Security update, as I encountered the same errors when executing the following code in version 2.0.1. Do you have any suggestion on how to solve this issue? cc @klboke

  @Test
  public void testConversionService() {
    // prepare JWT decoder with HS256 alg
    String jwtSecret = "MY_APPLICATION_JWT_SECRET_KEY_DUMMY";
    SecretKey secretKey = new SecretKeySpec(jwtSecret.getBytes(StandardCharsets.UTF_8), "HmacSHA256");
    NimbusJwtDecoder jwtDecoder = NimbusJwtDecoder.withSecretKey(secretKey).build();

    // prepare idToken
    String idToken = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyLCJncm91cHNfZGlyZWN0IjpbImdyb3VwMS9zdWItZ3JvdXAxIiwiZ3JvdXAyIl19.OQDbCoothbZR_2uLTpCb9tD0arxOsK0LB4p0H_2gDHM";
    Jwt jwt = jwtDecoder.decode(idToken);
    OidcIdToken oidcIdToken = new OidcIdToken(idToken, jwt.getIssuedAt(), jwt.getExpiresAt(), jwt.getClaims());

    // test conversion
    ConversionService conversionService = springSessionConversionService();
    // serialize oidcIdToken to byte[]
    byte[] serialized = (byte[]) conversionService.convert(oidcIdToken, TypeDescriptor.valueOf(Object.class),
        TypeDescriptor.valueOf(byte[].class));
    // deserialize byte[] to OidcIdToken
    Object deserialized = conversionService.convert(serialized, TypeDescriptor.valueOf(byte[].class),
        TypeDescriptor.valueOf(Object.class));
    Assert.assertTrue(deserialized instanceof OidcIdToken);
  }

  public ConversionService springSessionConversionService() {
    GenericConversionService conversionService = new GenericConversionService();
    ObjectMapper objectMapper = new ObjectMapper();
    objectMapper.registerModules(SecurityJackson2Modules.getModules(this.getClass().getClassLoader()));

    conversionService.addConverter(Object.class, byte[].class, source -> {
      try {
        return objectMapper.writeValueAsBytes(source);
      } catch (IOException e) {
        throw new RuntimeException(
            "Spring-session JSON serializing error, This is usually caused by the system upgrade, please clear the browser cookies and try again.",
            e);
      }
    });

    conversionService.addConverter(byte[].class, Object.class, source -> {
      try {
        return objectMapper.readValue(source, Object.class);
      } catch (IOException e) {
        throw new RuntimeException(
            "Spring-session JSON deserializing error, This is usually caused by the system upgrade, please clear the browser cookies and try again.",
            e);
      }
    });
    return conversionService;
  }

Hi, is this problem solved in 2.2.0? AWS Cognito also gives the claim "groups" as an array, which I'd like to use it with Apollo.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

7 participants