-
Notifications
You must be signed in to change notification settings - Fork 1.4k
Description
We recently upgraded to Spring Boot 3.3 and Spring Authorization Server 1.3.0. We do an OAuth2 flow with the following configuration:
spring:
security:
oauth2:
client:
registration:
local:
authorization-grant-type: authorization_code
client-id: client
client-secret: secret
redirect-uri: "{baseUrl}/{action}/oauth2/code/{registrationId}"
scope: "openid,profile"
provider:
local:
issuer-uri: http://localhost:8081
user-name-attribute: subWe have not set any client authentication method on this side, but the default is client_secret_basic, which we also use in our authorization server:
@Bean
fun registeredClientRepository(): RegisteredClientRepository {
val registeredClient =
RegisteredClient.withId(UUID.randomUUID().toString())
.clientId("local")
.clientSecret("{noop}secret")
.clientAuthenticationMethod(CLIENT_SECRET_BASIC)
.authorizationGrantType(AUTHORIZATION_CODE)
.redirectUri("http://localhost:8080/login/oauth2/code/aad")
.scope(OPENID)
.scope(PROFILE)
.clientSettings(ClientSettings.builder().requireAuthorizationConsent(false).build())
.build()
return InMemoryRegisteredClientRepository(registeredClient)
}Locally this works all fine, because it runs on http. However, when we deploy our applications on Cloud Foundry, we connect via https. This then creates/adds a x509 certificate to the request coming in on the authorization server, which then triggers X509ClientCertificateAuthenticationConverter. This converter looks for the client_id, but that was never added by OAuth2AuthorizationCodeGrantRequestEntityConverter and thus throws an exception:
// client_id (REQUIRED)
String clientId = parameters.getFirst(OAuth2ParameterNames.CLIENT_ID);
if (!StringUtils.hasText(clientId) || parameters.get(OAuth2ParameterNames.CLIENT_ID).size() != 1) {
throw new OAuth2AuthenticationException(OAuth2ErrorCodes.INVALID_REQUEST);
}if (!ClientAuthenticationMethod.CLIENT_SECRET_BASIC
.equals(clientRegistration.getClientAuthenticationMethod())) {
parameters.add(OAuth2ParameterNames.CLIENT_ID, clientRegistration.getClientId());
}Maybe our set-up is wrong and we should not use client_secret_basic. Hoever, we also tried using client_secret_post, which gave a different error message, because X509ClientCertificateAuthenticationConverter changes the authentication method to tls_client_auth:
ClientAuthenticationMethod clientAuthenticationMethod = clientCertificateChain.length == 1
? ClientAuthenticationMethod.SELF_SIGNED_TLS_CLIENT_AUTH : ClientAuthenticationMethod.TLS_CLIENT_AUTH;It seems like you cannot use another authentication method once you have a certificate and X509ClientCertificateAuthenticationConverter triggers.
We also found a somewhat nasty workaround where we remove the request attribute jakarta.servlet.request.X509Certificate via a filter, this just blocks the inner workings of X509ClientCertificateAuthenticationConverter and won't change the client authentication method.
But of course, we rather don't do that.
I would expect that if I set a client authentication method this would be used, not overwritten by the converter just because there is a (unrelated) certificate passed along.
(Side note, I asked on StackOverflow too, but got no interaction going there.)