spring-security icon indicating copy to clipboard operation
spring-security copied to clipboard

Support OAuth2 client authentication using X.509 certificate

Open jgrandja opened this issue 8 years ago • 8 comments

The client should have the ability to authenticate with the Authorization Server using X.509 certificate.

See RFC 8705 OAuth 2.0 Mutual-TLS Client Authentication and Certificate-Bound Access Tokens

jgrandja avatar Aug 16 '17 10:08 jgrandja

Hello @jgrandja, I have been talking to some security experts(OpenID/OAuth2 spec writers) and got the feedback that using MTLS is the most desirable form of client authentication.

https://tools.ietf.org/html/draft-ietf-oauth-mtls-03

Was wondering if this is still in your radar.
Thanks!

myspri avatar Oct 30 '17 03:10 myspri

@myspri Apologize for the delayed response. Yes, we are still planning on implementing this feature. However, we have not scheduled it as of yet.

jgrandja avatar Dec 11 '17 16:12 jgrandja

Note that the spec has became the standard RFC 8705, "OAuth 2.0 Mutual-TLS Client Authentication and Certificate-Bound Access Tokens".

In the other hand, there are already some open source implementations like the one from IdentityServer4 (see https://github.com/IdentityServer/IdentityServer4/tree/master/samples/Clients/src/ConsoleMTLSClient).

hablutzel1 avatar May 18 '20 22:05 hablutzel1

Any updates on if this has been scheduled?

maskedpirate avatar Jul 07 '20 16:07 maskedpirate

@maskedpirate No updates. Would you be interested in submitting a pull request?

rwinch avatar Jul 08 '20 14:07 rwinch

any update !!!

praveenbommali avatar Jul 12 '20 16:07 praveenbommali

I'd love to hear an update on this. I'm interested in running in OpenShift w/ their internal OAuth server. From looking at their oauth-proxy sidecar, I believe OpenShift's OAuth server is expecting a k8s service account client crt as the auth method.

greghall76 avatar Jun 27 '22 19:06 greghall76

No updates at this time.

rwinch avatar Aug 11 '22 15:08 rwinch

I think I got it to work in Spring Boot 3

All feedback are welcome!

You need to set

spring.security.oauth2.client.registration.keycloak.client-authentication-method = none

so you send client_id in request body, otherwise will the Authorization Server never know from which client the request comes from.

Then add custom truststore and keystore for accessTokenResponseClient. The solution is quite long since Apache HttpComponents HttpClient, ignores standard Java truststore (-Djavax.net.ssl.trustStore) and keystore (-Djavax.net.ssl.keyStore). Otherwise we would be done by only setting client-authentication-method = none

` @Bean public SecurityFilterChain filterChain(HttpSecurity http) throws Exception { http // ... .oauth2Client(oauth2Client -> oauth2Client // .authorizationCodeGrant(authorizationCodeGrant -> authorizationCodeGrant // .accessTokenResponseClient(this.accessTokenResponseClient()))); return http.build(); }

private OAuth2AccessTokenResponseClient<OAuth2AuthorizationCodeGrantRequest> accessTokenResponseClient() {
    DefaultAuthorizationCodeTokenResponseClient accessTokenResponseClient = new DefaultAuthorizationCodeTokenResponseClient();

    // org.springframework.security.oauth2.client.endpoint.DefaultAuthorizationCodeTokenResponseClient
    RestTemplate restTemplate = new RestTemplate(
            Arrays.asList(new FormHttpMessageConverter(), new OAuth2AccessTokenResponseHttpMessageConverter()));
    restTemplate.setErrorHandler(new OAuth2ErrorResponseErrorHandler());
    try {
        // https://github.com/apache/httpcomponents-client/blob/5.2.x/httpclient5/src/test/java/org/apache/hc/client5/http/examples/ClientCustomSSL.java
        SSLContext sslContext = new SSLContextBuilder() //
                .loadKeyMaterial(Path.of(keyStore), keyStorePassword.toCharArray(), keyStorePassword.toCharArray()) //
                .loadTrustMaterial(Path.of(trustStore), trustStorePassword.toCharArray()) //
                .build();

        final SSLConnectionSocketFactory sslSocketFactory = SSLConnectionSocketFactoryBuilder.create() //
                .setSslContext(sslContext) //
                .build();

        final HttpClientConnectionManager cm = PoolingHttpClientConnectionManagerBuilder.create() //
                .setSSLSocketFactory(sslSocketFactory) //
                .build();

        CloseableHttpClient httpClient = HttpClients.custom() //
                .setConnectionManager(cm) //
                .build();

        // "uses https://hc.apache.org/httpcomponents-client-ga Apache HttpComponents HttpClient to create requests"
        ClientHttpRequestFactory requestFactory = new HttpComponentsClientHttpRequestFactory(httpClient);
        restTemplate.setRequestFactory(requestFactory);
    } catch (Exception e) {
        e.printStackTrace();
    }
    accessTokenResponseClient.setRestOperations(restTemplate);
    return accessTokenResponseClient;
}

`

Complete example https://github.com/magnuskkarlsson/spring-boot-3-oauth2-login-keycloak-mtls

magnuskkarlsson avatar Aug 23 '23 10:08 magnuskkarlsson

I concluded wrong about Apache HttpClient v5 and org.springframework.security.oauth2.client.endpoint.DefaultAuthorizationCodeTokenResponseClient

It does not ignore Java truststore (-Djavax.net.ssl.trustStore) and keystore (-Djavax.net.ssl.keyStore) and hence all that is required for mTLS Access Token Request in Authorization Code Flow are:

spring.security.oauth2.client.registration.keycloak.client-authentication-method = none and java -Djavax.net.ssl.trustStore -Djavax.net.ssl.keyStore ... -jar myjar.jar

magnuskkarlsson avatar Aug 25 '23 18:08 magnuskkarlsson

Closing. Please see comment for update.

jgrandja avatar Apr 23 '24 18:04 jgrandja