From 2885b0f75f6ba42693e0f2eab0c2f267722d9e42 Mon Sep 17 00:00:00 2001 From: Josh Cummings <3627351+jzheaux@users.noreply.github.com> Date: Wed, 2 Apr 2025 11:16:26 -0600 Subject: [PATCH] Add valueOf This commit adds a static factory for returning a constant ClientAuthenticationMethod or creating a new one when there is no match. Issue gh-16825 --- ...ientRegistrationsBeanDefinitionParser.java | 4 +-- .../core/ClientAuthenticationMethod.java | 26 +++++++++++++++++- .../core/ClientAuthenticationMethodTests.java | 27 ++++++++++++++++++- 3 files changed, 53 insertions(+), 4 deletions(-) diff --git a/config/src/main/java/org/springframework/security/config/oauth2/client/ClientRegistrationsBeanDefinitionParser.java b/config/src/main/java/org/springframework/security/config/oauth2/client/ClientRegistrationsBeanDefinitionParser.java index 80ff475579..c908958f30 100644 --- a/config/src/main/java/org/springframework/security/config/oauth2/client/ClientRegistrationsBeanDefinitionParser.java +++ b/config/src/main/java/org/springframework/security/config/oauth2/client/ClientRegistrationsBeanDefinitionParser.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2020 the original author or authors. + * Copyright 2002-2025 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -125,7 +125,7 @@ public final class ClientRegistrationsBeanDefinitionParser implements BeanDefini getOptionalIfNotEmpty(parserContext, clientRegistrationElt.getAttribute(ATT_CLIENT_SECRET)) .ifPresent(builder::clientSecret); getOptionalIfNotEmpty(parserContext, clientRegistrationElt.getAttribute(ATT_CLIENT_AUTHENTICATION_METHOD)) - .map(ClientAuthenticationMethod::new) + .map(ClientAuthenticationMethod::valueOf) .ifPresent(builder::clientAuthenticationMethod); getOptionalIfNotEmpty(parserContext, clientRegistrationElt.getAttribute(ATT_AUTHORIZATION_GRANT_TYPE)) .map(AuthorizationGrantType::new) diff --git a/oauth2/oauth2-core/src/main/java/org/springframework/security/oauth2/core/ClientAuthenticationMethod.java b/oauth2/oauth2-core/src/main/java/org/springframework/security/oauth2/core/ClientAuthenticationMethod.java index 5dbf88cd85..1e2e2c1ebc 100644 --- a/oauth2/oauth2-core/src/main/java/org/springframework/security/oauth2/core/ClientAuthenticationMethod.java +++ b/oauth2/oauth2-core/src/main/java/org/springframework/security/oauth2/core/ClientAuthenticationMethod.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2024 the original author or authors. + * Copyright 2002-2025 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -18,6 +18,7 @@ package org.springframework.security.oauth2.core; import java.io.Serializable; +import org.springframework.lang.NonNull; import org.springframework.security.core.SpringSecurityCoreVersion; import org.springframework.util.Assert; @@ -92,6 +93,29 @@ public final class ClientAuthenticationMethod implements Serializable { return this.value; } + static ClientAuthenticationMethod[] methods() { + return new ClientAuthenticationMethod[] { CLIENT_SECRET_BASIC, CLIENT_SECRET_POST, CLIENT_SECRET_JWT, + PRIVATE_KEY_JWT, NONE, TLS_CLIENT_AUTH, SELF_SIGNED_TLS_CLIENT_AUTH }; + } + + /** + * A factory to construct a {@link ClientAuthenticationMethod} based on a string, + * returning any constant value that matches. + * @param method the client authentication method + * @return a {@link ClientAuthenticationMethod}; specifically the corresponding + * constant, if any + * @since 6.5 + */ + @NonNull + public static ClientAuthenticationMethod valueOf(String method) { + for (ClientAuthenticationMethod m : methods()) { + if (m.getValue().equals(method)) { + return m; + } + } + return new ClientAuthenticationMethod(method); + } + @Override public boolean equals(Object obj) { if (this == obj) { diff --git a/oauth2/oauth2-core/src/test/java/org/springframework/security/oauth2/core/ClientAuthenticationMethodTests.java b/oauth2/oauth2-core/src/test/java/org/springframework/security/oauth2/core/ClientAuthenticationMethodTests.java index 0e8353e103..c698a6d5dc 100644 --- a/oauth2/oauth2-core/src/test/java/org/springframework/security/oauth2/core/ClientAuthenticationMethodTests.java +++ b/oauth2/oauth2-core/src/test/java/org/springframework/security/oauth2/core/ClientAuthenticationMethodTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2024 the original author or authors. + * Copyright 2002-2025 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -16,7 +16,13 @@ package org.springframework.security.oauth2.core; +import java.util.stream.Stream; + +import org.junit.jupiter.api.DynamicTest; import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.TestFactory; + +import org.springframework.util.StringUtils; import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException; @@ -69,4 +75,23 @@ public class ClientAuthenticationMethodTests { .isEqualTo("self_signed_tls_client_auth"); } + @Test + public void valueOfWhenAnyAuthenticationMethodThenConstructs() { + String string = new String("any"); + ClientAuthenticationMethod method = ClientAuthenticationMethod.valueOf(string); + assertThat(method.getValue()).isSameAs(string); + } + + @TestFactory + Stream valueOfWhenMatchesStaticThenReturnsStatic() { + return Stream.of(ClientAuthenticationMethod.methods()) + .map((method) -> DynamicTest.dynamicTest(testName(method.getValue()), + () -> assertThat(ClientAuthenticationMethod.valueOf(method.getValue())).isSameAs(method))); + } + + String testName(String method) { + String methodName = StringUtils.capitalize(method.replaceAll("_", "")); + return "valueOfWhen" + methodName + "ThenReturnsStatic" + methodName; + } + }