Using SpringSecurity with a non-compliant OAuth provider (Clerk.com)

149 Views Asked by At

I'm having trouble using SpringSecurity with a non-compliant OAuth provider (Clerk.com). When I use Spring Security with a default configuration, it complains that it's "Missing JSON object member with key subject_types_supported". When I check the returned JSON, I see that it is in fact missing the field. Given that, I'm trying to manually override the response object and add the field with a static value using the below bean. But when I try to do that, creating the bean itself throws the missing field exception. Seemingly, it fails before even reaching my custom adapter. I can't figure why it's doing that.

What's the correct way to manually add the field?

//Code adapted from https://github.com/spring-projects/spring-security/issues/5983#issuecomment-1369926906

import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import org.springframework.core.convert.converter.Converter;
import org.springframework.http.converter.FormHttpMessageConverter;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.oauth2.client.endpoint.DefaultAuthorizationCodeTokenResponseClient;
import org.springframework.security.oauth2.client.http.OAuth2ErrorResponseErrorHandler;
import org.springframework.security.oauth2.core.endpoint.DefaultMapOAuth2AccessTokenResponseConverter;
import org.springframework.security.oauth2.core.endpoint.OAuth2AccessTokenResponse;
import org.springframework.security.oauth2.core.http.converter.OAuth2AccessTokenResponseHttpMessageConverter;
import org.springframework.security.web.SecurityFilterChain;
import org.springframework.web.client.RestTemplate;

@Configuration
public class SecurityConfig {
    @Primary
    @Bean
    public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
        System.out.println("Loading custom security filter chain"); // Log to check if bean is loaded
        return http.authorizeHttpRequests(httpReq -> httpReq.anyRequest().authenticated()).oauth2Login(
                oauth2 -> oauth2.tokenEndpoint(token -> token.accessTokenResponseClient(linkedinTokenResponseClient())))
                .build();
    }

    private static DefaultAuthorizationCodeTokenResponseClient linkedinTokenResponseClient() {
        var defaultMapConverter = new DefaultMapOAuth2AccessTokenResponseConverter();
        Converter<Map<String, Object>, OAuth2AccessTokenResponse> linkedinMapConverter = tokenResponse -> {
            var withTokenType = new HashMap<>(tokenResponse);
            withTokenType.put("subject_types_supported", List.of("public"));
            return defaultMapConverter.convert(withTokenType);
        };

        var httpConverter = new OAuth2AccessTokenResponseHttpMessageConverter();
        httpConverter.setAccessTokenResponseConverter(linkedinMapConverter);

        var restOperations = new RestTemplate(List.of(new FormHttpMessageConverter(), httpConverter));
        restOperations.setErrorHandler(new OAuth2ErrorResponseErrorHandler());
        var client = new DefaultAuthorizationCodeTokenResponseClient();
        client.setRestOperations(restOperations);
        return client;
    }
}
0

There are 0 best solutions below