Spring OAuth2 Making `state` param at least 32 characters long

Viewed 1088

I am attempting to authorize against an external identity provider. Everything seems setup fine, but I keep getting a validation error with my identity provider because the state parameter automatically tacked onto my authorization request is not long enough:

For example: &state=uYG5DC

The requirements of my IDP say that this state param must be at least 32-characters long. How can I programmatically increase the size of this auto-generated number?

Even if I could generate this number myself, it is not possible to override with other methods I have seen suggested. The following attempt fails because my manual setting of ?state=abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz is superceded by the autogenerated param placed after it during the actual request:

@Bean public OAuth2ProtectedResourceDetails loginGovOpenId() { AuthorizationCodeResourceDetails details = new AuthorizationCodeResourceDetails() { @Override public String getUserAuthorizationUri() { return super.getUserAuthorizationUri() + "?state=abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz"; } }; details.setClientId(clientId); details.setAccessTokenUri(accessTokenUri); details.setUserAuthorizationUri(userAuthorizationUri); details.setScope(Arrays.asList("openid", "email")); details.setPreEstablishedRedirectUri(redirectUri); details.setUseCurrentUri(true); return details; }

The 6-character setting seems to be set here, is there a way to override this? https://github.com/spring-projects/spring-security-oauth/blob/master/spring-security-oauth2/src/main/java/org/springframework/security/oauth2/common/util/RandomValueStringGenerator.java

1 Answers

With the help of this post: spring security StateKeyGenerator custom instance

I was able to come up with a working solution.

In my configuration class marked with these annotations:

@Configuration @EnableOAuth2Client

I configured the following beans:

    @Bean
public OAuth2ProtectedResourceDetails loginGovOpenId() {
    AuthorizationCodeResourceDetails details = new AuthorizationCodeResourceDetails();
    AuthorizationCodeResourceDetails details = new 
    details.setClientId(clientId);
    details.setClientSecret(clientSecret);
    details.setAccessTokenUri(accessTokenUri);
    details.setUserAuthorizationUri(userAuthorizationUri);
    details.setScope(Arrays.asList("openid", "email"));
    details.setPreEstablishedRedirectUri(redirectUri);
    details.setUseCurrentUri(true);
    return details;
}

@Bean
public StateKeyGenerator stateKeyGenerator() {
    return new CustomStateKeyGenerator();
}

@Bean
public AccessTokenProvider accessTokenProvider() {
    AuthorizationCodeAccessTokenProvider accessTokenProvider = new AuthorizationCodeAccessTokenProvider();
    accessTokenProvider.setStateKeyGenerator(stateKeyGenerator());
    return accessTokenProvider;
}

@Bean
public OAuth2RestTemplate loginGovOpenIdTemplate(final OAuth2ClientContext clientContext) {
    final OAuth2RestTemplate template = new OAuth2RestTemplate(loginGovOpenId(), clientContext);
    template.setAccessTokenProvider(accessTokenProvider());
    return template;
}

Where my CustomStateKeyGenerator implementation class looks as follows:

public class CustomStateKeyGenerator implements StateKeyGenerator {

  // login.gov requires state to be at least 32-characters long
  private static int length = 32;
  private RandomValueStringGenerator generator = new RandomValueStringGenerator(length);

  @Override
  public String generateKey(OAuth2ProtectedResourceDetails resource) {
      return generator.generate();
  }
}
Related