0

I'm trying to set up a Spring Authorization Server for learning purposes. The login and consent screens work, but after I approve the consent screen and submit the /authorize request, I get the following error:

16:47:19.849 [http-nio-8080-exec-3] ERROR o.a.c.c.C.[.[.[.[dispatcherServlet] - Servlet.service() for servlet [dispatcherServlet] in context with path [] threw exception
java.lang.IllegalArgumentException: The class with dev.gaurav.auth_server.entity.User and name of dev.gaurav.auth_server.entity.User 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
    at org.springframework.security.oauth2.server.authorization.JdbcOAuth2AuthorizationService$OAuth2AuthorizationRowMapper.parseMap(JdbcOAuth2AuthorizationService.java:648)

From what I understand:

  1. Spring Authorization Server creates an OAuth2Authorization object after consent approval.

  2. This object includes my custom User object as part of the principal.

  3. Spring uses Jackson to serialize/deserialize the OAuth2Authorization object to the database.

  4. Jackson refuses to deserialize my User class because Spring Security 6+ has a strict allowlist for security reasons.

So the error happens after consent approval when Spring tries to persist or read the authorization.

My questions:

  • Why it worked with in-memory users but not JPA/JDBC: When I was using InMemoryUserDetailsManager (for example, at the commit "Initialize OAuth 2.0 Authorization Server Project with Spring Boot" in my Git repo), everything worked fine.

    @Bean
    public UserDetailsService userDetailsService() {
        UserDetails userDetails = User.builder()
                .username("user")
                .passwordEncoder(passwordEncoder()::encode)
                .password("password")
                .roles("USER")
                .build();
        return new InMemoryUserDetailsManager(userDetails);
    }
    
  • How can I safely allow my custom User class to be deserialized?

  • Should I use a Mixin, Jackson annotations, or something else (which could also be a suitable choice for development, not just for learning purposes)?

  • Is there a recommended approach to avoid storing the full User object in OAuth2Authorization.?

1
  • 1
    i found your user, its because you have a nested Role class that spring has not whitelisted. You see spring has whitelisted your User because it implements UserDetails, but your Role class, spring knows nothing about, so it refuses to serialize it. You can register your Role class but that is quite tedious. I would instead of having a custom Role, just use Springs Role implementation SimpleGrantedAuthority Commented Sep 12 at 22:20

1 Answer 1

0

When you used InMemoryUserDetailsManager, security stored not the user object itself, but UserDetails which was safe and serialization does not have necessary. However with JPA Auth Server objects that contain OAuth2Authorization use ser via jackson there is a problem that jackson does not trust that class custom user. Consequently leading to 2 approaches, i guess, jackson Mixin like

public abstract class UserMixin {
    @JsonCreator
    public UserMixin(@JsonProperty("username") String username,
                     @JsonProperty("password") String password) {}
}

then in your config class register that Mixin. Second (much easier) add constructor with requered fields, annotated with @JsonCreator and for every parameter @JsonProperty

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.