Skip to content

Commit 02a948d

Browse files
bbudanorwinch
authored andcommitted
Address reviewer requested changes
Closes gh-17806 Signed-off-by: Bernard Budano <[email protected]>
1 parent 8e3cf96 commit 02a948d

File tree

4 files changed

+44
-15
lines changed

4 files changed

+44
-15
lines changed

docs/modules/ROOT/pages/features/integrations/rest/http-interface.adoc

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ Spring Security's OAuth Support can integrate with `RestClient` and `WebClient`
55

66
[[configuration]]
77
== Configuration
8-
After xref:features/integrations/rest/http-interface.adoc#configuration-restclient[RestClient] or xref:features/integrations/rest/http-interface.adoc#configuration-webclient[WebClient] specific configuration, usage of xref:features/integrations/rest/http-interface.adoc[] only requires adding a xref:features/integrations/rest/http-interface.adoc#client-registration-id[`@ClientRegistrationId`] to methods that require OAuth.
8+
After xref:features/integrations/rest/http-interface.adoc#configuration-restclient[RestClient] or xref:features/integrations/rest/http-interface.adoc#configuration-webclient[WebClient] specific configuration, usage of xref:features/integrations/rest/http-interface.adoc[] only requires adding a xref:features/integrations/rest/http-interface.adoc#client-registration-id[`@ClientRegistrationId`] to methods that require OAuth or their declaring HTTP interface.
99

1010
Since the presence of xref:features/integrations/rest/http-interface.adoc#client-registration-id[`@ClientRegistrationId`] determines if and how the OAuth token will be resolved, it is safe to add Spring Security's OAuth support any configuration.
1111

docs/modules/ROOT/pages/whats-new.adoc

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,7 @@ http.csrf((csrf) -> csrf.spa());
4949
* Added OAuth2 Support for xref:features/integrations/rest/http-interface.adoc[HTTP Interface Integration]
5050
* Added support for custom `JwkSource` in `NimbusJwtDecoder`, allowing usage of Nimbus's `JwkSourceBuilder` API
5151
* Added builder for `NimbusJwtEncoder`, supports specifying an EC or RSA key pair or a secret key
52+
* Added support for `@ClientRegistrationId` at class level, eliminating the need for method level repetition
5253

5354
== SAML 2.0
5455

oauth2/oauth2-client/src/main/java/org/springframework/security/oauth2/client/web/client/ClientRegistrationIdProcessor.java

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -17,12 +17,12 @@
1717
package org.springframework.security.oauth2.client.web.client;
1818

1919
import java.lang.reflect.Method;
20-
import java.util.Optional;
2120

2221
import org.jspecify.annotations.Nullable;
2322

2423
import org.springframework.core.MethodParameter;
25-
import org.springframework.core.annotation.AnnotationUtils;
24+
import org.springframework.security.core.annotation.SecurityAnnotationScanner;
25+
import org.springframework.security.core.annotation.SecurityAnnotationScanners;
2626
import org.springframework.security.oauth2.client.annotation.ClientRegistrationId;
2727
import org.springframework.security.oauth2.client.web.ClientAttributes;
2828
import org.springframework.web.service.invoker.HttpRequestValues;
@@ -38,20 +38,21 @@ public final class ClientRegistrationIdProcessor implements HttpRequestValues.Pr
3838

3939
public static ClientRegistrationIdProcessor DEFAULT_INSTANCE = new ClientRegistrationIdProcessor();
4040

41-
private ClientRegistrationIdProcessor() {
42-
}
41+
private SecurityAnnotationScanner<ClientRegistrationId> securityAnnotationScanner = SecurityAnnotationScanners
42+
.requireUnique(ClientRegistrationId.class);
4343

4444
@Override
4545
public void process(Method method, MethodParameter[] parameters, @Nullable Object[] arguments,
4646
HttpRequestValues.Builder builder) {
47-
ClientRegistrationId registeredId = Optional
48-
.ofNullable(AnnotationUtils.findAnnotation(method, ClientRegistrationId.class))
49-
.orElseGet(() -> AnnotationUtils.findAnnotation(method.getDeclaringClass(), ClientRegistrationId.class));
47+
ClientRegistrationId registeredId = this.securityAnnotationScanner.scan(method, method.getDeclaringClass());
5048

5149
if (registeredId != null) {
5250
String registrationId = registeredId.registrationId();
5351
builder.configureAttributes(ClientAttributes.clientRegistrationId(registrationId));
5452
}
5553
}
5654

55+
private ClientRegistrationIdProcessor() {
56+
}
57+
5758
}

oauth2/oauth2-client/src/test/java/org/springframework/security/oauth2/client/web/client/ClientRegistrationIdProcessorTests.java

Lines changed: 34 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -22,12 +22,14 @@
2222

2323
import org.junit.jupiter.api.Test;
2424

25+
import org.springframework.core.annotation.AnnotationConfigurationException;
2526
import org.springframework.security.oauth2.client.annotation.ClientRegistrationId;
2627
import org.springframework.security.oauth2.client.web.ClientAttributes;
2728
import org.springframework.util.ReflectionUtils;
2829
import org.springframework.web.service.invoker.HttpRequestValues;
2930

3031
import static org.assertj.core.api.Assertions.assertThat;
32+
import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
3133

3234
/**
3335
* Unit tests for {@link ClientRegistrationIdProcessor}.
@@ -56,9 +58,8 @@ void processWhenClientRegistrationIdPresentThenSet() {
5658
@Test
5759
void processWhenMetaClientRegistrationIdPresentThenSet() {
5860
HttpRequestValues.Builder builder = HttpRequestValues.builder();
59-
Method hasMetaClientRegistrationId = ReflectionUtils.findMethod(RestService.class,
60-
"hasMetaClientRegistrationId");
61-
this.processor.process(hasMetaClientRegistrationId, null, null, builder);
61+
Method hasClientRegistrationId = ReflectionUtils.findMethod(RestService.class, "hasMetaClientRegistrationId");
62+
this.processor.process(hasClientRegistrationId, null, null, builder);
6263

6364
String registrationId = ClientAttributes.resolveClientRegistrationId(builder.build().getAttributes());
6465
assertThat(registrationId).isEqualTo(REGISTRATION_ID);
@@ -67,8 +68,8 @@ void processWhenMetaClientRegistrationIdPresentThenSet() {
6768
@Test
6869
void processWhenNoClientRegistrationIdPresentThenNull() {
6970
HttpRequestValues.Builder builder = HttpRequestValues.builder();
70-
Method noClientRegistrationId = ReflectionUtils.findMethod(RestService.class, "noClientRegistrationId");
71-
this.processor.process(noClientRegistrationId, null, null, builder);
71+
Method hasClientRegistrationId = ReflectionUtils.findMethod(RestService.class, "noClientRegistrationId");
72+
this.processor.process(hasClientRegistrationId, null, null, builder);
7273

7374
String registrationId = ClientAttributes.resolveClientRegistrationId(builder.build().getAttributes());
7475
assertThat(registrationId).isNull();
@@ -77,14 +78,24 @@ void processWhenNoClientRegistrationIdPresentThenNull() {
7778
@Test
7879
void processWhenClientRegistrationIdPresentOnDeclaringClassThenSet() {
7980
HttpRequestValues.Builder builder = HttpRequestValues.builder();
80-
Method declaringClassHasClientRegistrationId = ReflectionUtils.findMethod(AnnotatedRestService.class,
81+
Method declaringClassHasClientRegistrationId = ReflectionUtils.findMethod(TypeAnnotatedRestService.class,
8182
"declaringClassHasClientRegistrationId");
8283
this.processor.process(declaringClassHasClientRegistrationId, null, null, builder);
8384

8485
String registrationId = ClientAttributes.resolveClientRegistrationId(builder.build().getAttributes());
8586
assertThat(registrationId).isEqualTo(REGISTRATION_ID);
8687
}
8788

89+
@Test
90+
void processWhenDuplicateClientRegistrationIdPresentOnAggregateServiceThenException() {
91+
HttpRequestValues.Builder builder = HttpRequestValues.builder();
92+
Method shouldFailDueToDuplicateClientRegistrationId = ReflectionUtils.findMethod(AggregateRestService.class,
93+
"shouldFailDueToDuplicateClientRegistrationId");
94+
95+
assertThatExceptionOfType(AnnotationConfigurationException.class).isThrownBy(
96+
() -> this.processor.process(shouldFailDueToDuplicateClientRegistrationId, null, null, builder));
97+
}
98+
8899
interface RestService {
89100

90101
@ClientRegistrationId(REGISTRATION_ID)
@@ -104,10 +115,26 @@ interface RestService {
104115
}
105116

106117
@ClientRegistrationId(REGISTRATION_ID)
107-
interface AnnotatedRestService {
118+
interface TypeAnnotatedRestService {
108119

109120
void declaringClassHasClientRegistrationId();
110121

111122
}
112123

124+
@ClientRegistrationId("a")
125+
interface ARestService {
126+
127+
}
128+
129+
@ClientRegistrationId("b")
130+
interface BRestService {
131+
132+
}
133+
134+
interface AggregateRestService extends ARestService, BRestService {
135+
136+
void shouldFailDueToDuplicateClientRegistrationId();
137+
138+
}
139+
113140
}

0 commit comments

Comments
 (0)