0

I am trying to compile the federated example with graalvm. After login with a custom oidc provider, the deserialization of the class org.springframework.security.oauth2.core.oidc.user.DefaultOidcUser fails with the following exception.

java.lang.IllegalArgumentException: Cannot construct instance of `org.springframework.security.oauth2.core.oidc.OidcIdToken`, problem: tokenValue cannot be empty
 at [Source: UNKNOWN; byte offset: #UNKNOWN] (through reference chain: org.springframework.security.oauth2.client.authentication.OAuth2AuthenticationToken["principal"]->org.springframework.security.oauth2.core.oidc.user.DefaultOidcUser["idToken"])
    at org.springframework.security.oauth2.server.authorization.JdbcOAuth2AuthorizationService$OAuth2AuthorizationRowMapper.parseMap(JdbcOAuth2AuthorizationService.java:517) ~[na:na]
    at org.springframework.security.oauth2.server.authorization.JdbcOAuth2AuthorizationService$OAuth2AuthorizationRowMapper.mapRow(JdbcOAuth2AuthorizationService.java:380) ~[na:na]
    at org.springframework.security.oauth2.server.authorization.JdbcOAuth2AuthorizationService$OAuth2AuthorizationRowMapper.mapRow(JdbcOAuth2AuthorizationService.java:346) ~[na:na]
    at org.springframework.jdbc.core.RowMapperResultSetExtractor.extractData(RowMapperResultSetExtractor.java:94) ~[na:na]
    at org.springframework.jdbc.core.RowMapperResultSetExtractor.extractData(RowMapperResultSetExtractor.java:61) ~[na:na]
    at org.springframework.jdbc.core.JdbcTemplate$1.doInPreparedStatement(JdbcTemplate.java:723) ~[na:na]
    at org.springframework.jdbc.core.JdbcTemplate.execute(JdbcTemplate.java:651) ~[identity:6.0.10]
    at org.springframework.jdbc.core.JdbcTemplate.query(JdbcTemplate.java:713) ~[identity:6.0.10]
    at org.springframework.jdbc.core.JdbcTemplate.query(JdbcTemplate.java:744) ~[identity:6.0.10]
    at org.springframework.jdbc.core.JdbcTemplate.query(JdbcTemplate.java:799) ~[identity:6.0.10]
    at org.springframework.security.oauth2.server.authorization.JdbcOAuth2AuthorizationService.findBy(JdbcOAuth2AuthorizationService.java:294) ~[na:na]
    at org.springframework.security.oauth2.server.authorization.JdbcOAuth2AuthorizationService.findByToken(JdbcOAuth2AuthorizationService.java:270) ~[na:na]
    at org.springframework.security.oauth2.server.authorization.authentication.CodeVerifierAuthenticator.authenticate(CodeVerifierAuthenticator.java:81) ~[na:na]
    at org.springframework.security.oauth2.server.authorization.authentication.CodeVerifierAuthenticator.authenticateIfAvailable(CodeVerifierAuthenticator.java:70) ~[na:na]
    at org.springframework.security.oauth2.server.authorization.authentication.ClientSecretAuthenticationProvider.authenticate(ClientSecretAuthenticationProvider.java:137) ~[na:na]
    at org.springframework.security.authentication.ProviderManager.authenticate(ProviderManager.java:182) ~[identity:6.1.1]
    at org.springframework.security.oauth2.server.authorization.web.OAuth2ClientAuthenticationFilter.doFilterInternal(OAuth2ClientAuthenticationFilter.java:122) ~[na:na]
    at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:116) ~[identity:6.0.10]
    at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:374) ~[na:na]
    at org.springframework.security.oauth2.server.authorization.web.NimbusJwkSetEndpointFilter.doFilterInternal(NimbusJwkSetEndpointFilter.java:85) ~[na:na]
    at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:116) ~[identity:6.0.10]
    at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:374) ~[na:na]
    at org.springframework.security.oauth2.server.authorization.oidc.web.OidcProviderConfigurationEndpointFilter.doFilterInternal(OidcProviderConfigurationEndpointFilter.java:86) ~[na:na]
    at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:116) ~[identity:6.0.10]
    at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:374) ~[na:na]
    at org.springframework.security.oauth2.server.authorization.web.OAuth2DeviceVerificationEndpointFilter.doFilterInternal(OAuth2DeviceVerificationEndpointFilter.java:139) ~[na:na]
    at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:116) ~[identity:6.0.10]
    at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:374) ~[na:na]
    at org.springframework.security.oauth2.server.authorization.web.OAuth2AuthorizationEndpointFilter.doFilterInternal(OAuth2AuthorizationEndpointFilter.java:157) ~[na:na]
    at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:116) ~[identity:6.0.10]
    at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:374) ~[na:na]
    at org.springframework.security.oauth2.server.authorization.web.OAuth2AuthorizationServerMetadataEndpointFilter.doFilterInternal(OAuth2AuthorizationServerMetadataEndpointFilter.java:84) ~[na:na]
    at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:116) ~[identity:6.0.10]
    at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:374) ~[na:na]
    at org.springframework.security.web.authentication.logout.LogoutFilter.doFilter(LogoutFilter.java:107) ~[na:na]
    at org.springframework.security.web.authentication.logout.LogoutFilter.doFilter(LogoutFilter.java:93) ~[na:na]
    at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:374) ~[na:na]
    at org.springframework.security.oauth2.server.authorization.oidc.web.OidcLogoutEndpointFilter.doFilterInternal(OidcLogoutEndpointFilter.java:117) ~[na:na]
    at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:116) ~[identity:6.0.10]
    at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:374) ~[na:na]
    at org.springframework.security.web.csrf.CsrfFilter.doFilterInternal(CsrfFilter.java:117) ~[na:na]
    at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:116) ~[identity:6.0.10]
    at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:374) ~[na:na]
    at org.springframework.security.web.header.HeaderWriterFilter.doHeadersAfter(HeaderWriterFilter.java:90) ~[na:na]
    at org.springframework.security.web.header.HeaderWriterFilter.doFilterInternal(HeaderWriterFilter.java:75) ~[na:na]
    at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:116) ~[identity:6.0.10]
    at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:374) ~[na:na]
    at org.springframework.security.oauth2.server.authorization.config.annotation.web.configurers.AuthorizationServerContextFilter.doFilterInternal(AuthorizationServerContextFilter.java:61) ~[na:na]
    at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:116) ~[identity:6.0.10]
    at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:374) ~[na:na]
    at org.springframework.security.web.context.SecurityContextHolderFilter.doFilter(SecurityContextHolderFilter.java:82) ~[na:na]
    at org.springframework.security.web.context.SecurityContextHolderFilter.doFilter(SecurityContextHolderFilter.java:69) ~[na:na]
    at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:374) ~[na:na]
    at org.springframework.security.web.context.request.async.WebAsyncManagerIntegrationFilter.doFilterInternal(WebAsyncManagerIntegrationFilter.java:62) ~[na:na]
    at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:116) ~[identity:6.0.10]
    at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:374) ~[na:na]
    at org.springframework.security.web.session.DisableEncodeUrlFilter.doFilterInternal(DisableEncodeUrlFilter.java:42) ~[na:na]
    at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:116) ~[identity:6.0.10]
    at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:374) ~[na:na]
    at org.springframework.security.web.FilterChainProxy.doFilterInternal(FilterChainProxy.java:233) ~[na:na]
    at org.springframework.security.web.FilterChainProxy.doFilter(FilterChainProxy.java:191) ~[na:na]
    at org.springframework.web.filter.DelegatingFilterProxy.invokeDelegate(DelegatingFilterProxy.java:352) ~[identity:6.0.10]
    at org.springframework.web.filter.DelegatingFilterProxy.doFilter(DelegatingFilterProxy.java:268) ~[identity:6.0.10]
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:174) ~[na:na]
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:149) ~[na:na]
    at org.springframework.web.filter.RequestContextFilter.doFilterInternal(RequestContextFilter.java:100) ~[identity:6.0.10]
    at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:116) ~[identity:6.0.10]
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:174) ~[na:na]
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:149) ~[na:na]
    at org.springframework.web.filter.FormContentFilter.doFilterInternal(FormContentFilter.java:93) ~[identity:6.0.10]
    at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:116) ~[identity:6.0.10]
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:174) ~[na:na]
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:149) ~[na:na]
    at org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:201) ~[identity:6.0.10]
    at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:116) ~[identity:6.0.10]
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:174) ~[na:na]
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:149) ~[na:na]
    at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:166) ~[na:na]
    at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:90) ~[na:na]
    at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:482) ~[identity:10.1.10]
    at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:115) ~[na:na]
    at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:93) ~[identity:10.1.10]
    at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:74) ~[na:na]
    at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:341) ~[na:na]
    at org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:391) ~[na:na]
    at org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:63) ~[identity:10.1.10]
    at org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:894) ~[na:na]
    at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1741) ~[na:na]
    at org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:52) ~[identity:10.1.10]
    at org.apache.tomcat.util.threads.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1191) ~[na:na]
    at org.apache.tomcat.util.threads.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:659) ~[na:na]
    at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61) ~[na:na]
    at java.base@17.0.5/java.lang.Thread.run(Thread.java:833) ~[identity:na]
    at org.graalvm.nativeimage.builder/com.oracle.svm.core.thread.PlatformThreads.threadStartRoutine(PlatformThreads.java:775) ~[identity:na]
    at org.graalvm.nativeimage.builder/com.oracle.svm.core.posix.thread.PosixPlatformThreads.pthreadStartRoutine(PosixPlatformThreads.java:203) ~[na:na]

I registered Jackson mixins hints for reflection and the actual classes with @RegisterReflectionForBinding

public class HintsRegistration implements RuntimeHintsRegistrar {
    private final BindingReflectionHintsRegistrar bindingRegistrar = new BindingReflectionHintsRegistrar();

    @Override
    public void registerHints(RuntimeHints hints, ClassLoader classLoader) {
        try {
            ReflectionHints reflection = hints.reflection();
            reflection.registerMethod(Callable.class.getMethod("call"), ExecutableMode.INVOKE);
            reflection.registerType(Class.forName("org.springframework.web.servlet.handler.AbstractHandlerMethodMapping$EmptyHandler"), INVOKE_DECLARED_METHODS);
            reflection.registerType(ServletInvocableHandlerMethod.class, DECLARED_FIELDS, INVOKE_DECLARED_CONSTRUCTORS, INVOKE_DECLARED_METHODS);

            // Security Jackson Modules
            reflection.registerType(CoreJackson2Module.class, DECLARED_FIELDS, INVOKE_DECLARED_CONSTRUCTORS, INVOKE_DECLARED_METHODS);
            reflection.registerType(WebJackson2Module.class, DECLARED_FIELDS, INVOKE_DECLARED_CONSTRUCTORS, INVOKE_DECLARED_METHODS);
            reflection.registerType(WebServerJackson2Module.class, DECLARED_FIELDS, INVOKE_DECLARED_CONSTRUCTORS, INVOKE_DECLARED_METHODS);
            reflection.registerType(WebServletJackson2Module.class, DECLARED_FIELDS, INVOKE_DECLARED_CONSTRUCTORS, INVOKE_DECLARED_METHODS);
            reflection.registerType(OAuth2ClientJackson2Module.class, DECLARED_FIELDS, INVOKE_DECLARED_CONSTRUCTORS, INVOKE_DECLARED_METHODS);

            // Jackson Mixins registration
            bindingRegistrar.registerReflectionHints(reflection, Class.forName("org.springframework.security.oauth2.client.jackson2.DefaultOidcUserMixin"));
            bindingRegistrar.registerReflectionHints(reflection, Class.forName("org.springframework.security.oauth2.client.jackson2.OAuth2AccessTokenMixin"));
            bindingRegistrar.registerReflectionHints(reflection, Class.forName("org.springframework.security.oauth2.client.jackson2.OAuth2AuthenticationExceptionMixin"));
            bindingRegistrar.registerReflectionHints(reflection, Class.forName("org.springframework.security.oauth2.client.jackson2.OAuth2AuthenticationTokenMixin"));
            bindingRegistrar.registerReflectionHints(reflection, Class.forName("org.springframework.security.oauth2.client.jackson2.OAuth2AuthorizationRequestMixin"));
            bindingRegistrar.registerReflectionHints(reflection, Class.forName("org.springframework.security.oauth2.client.jackson2.OAuth2AuthorizedClientMixin"));
            bindingRegistrar.registerReflectionHints(reflection, Class.forName("org.springframework.security.oauth2.client.jackson2.OAuth2ErrorMixin"));
            bindingRegistrar.registerReflectionHints(reflection, Class.forName("org.springframework.security.oauth2.client.jackson2.OAuth2RefreshTokenMixin"));
            bindingRegistrar.registerReflectionHints(reflection, Class.forName("org.springframework.security.oauth2.client.jackson2.OAuth2UserAuthorityMixin"));
            bindingRegistrar.registerReflectionHints(reflection, Class.forName("org.springframework.security.oauth2.client.jackson2.OidcIdTokenMixin"));
            bindingRegistrar.registerReflectionHints(reflection, Class.forName("org.springframework.security.oauth2.client.jackson2.OidcUserAuthorityMixin"));
            bindingRegistrar.registerReflectionHints(reflection, Class.forName("org.springframework.security.oauth2.client.jackson2.OidcUserInfoMixin"));
            bindingRegistrar.registerReflectionHints(reflection, Class.forName("org.springframework.security.oauth2.server.authorization.jackson2.OAuth2TokenFormatMixin"));

            // Resources hints
            ResourceHints resources = hints.resources();
            resources.registerPattern("org/springframework/security/oauth2/server/authorization/oauth2-authorization-schema.sql");
            resources.registerPattern("org/springframework/security/oauth2/server/authorization/oauth2-authorization-consent-schema.sql");
            resources.registerPattern("org/springframework/security/oauth2/server/authorization/client/oauth2-registered-client-schema.sql");
        } catch (ClassNotFoundException | NoSuchMethodException e) {
            throw new RuntimeException(e);
        }
    }
}
@Configuration(proxyBeanMethods = false)
public class AuthorizationServerConfig {

        @Bean
    @RegisterReflectionForBinding({
            OAuth2AccessTokenResponse.class,
            DefaultOidcUser.class,
            OAuth2TokenFormat.class,
            OidcIdToken.class,
            OidcUserAuthority.class,
            OAuth2AuthenticationToken.class
    })
    public OAuth2AuthorizationService authorizationService(JdbcTemplate jdbcTemplate,
            RegisteredClientRepository registeredClientRepository) {
        return new JdbcOAuth2AuthorizationService(jdbcTemplate, registeredClientRepository);
    }

}

These configurations fixed a ton of problems, but I'm actually stuck with the exception of tokenValue coming with a null value.

sic-sic
  • 182
  • 1
  • 9
  • Can you apply your additions (mixins, hints, annotations, etc.) to the federated sample of spring-authorization-server on a branch and share it? I'd be happy to take a look. It's possible this needs to be reported as a bug, but I'd want to check first. – Steve Riesenberg Jul 27 '23 at 17:09

0 Answers0