Skip to content

Commit 49f3bf6

Browse files
committed
Merge branch 0.4.x into main
The following commits are merged using the default merge strategy. 8c78a5b Document Authorization Request Validation a9371e9 Document Jwt Client Assertion Validation fcbb5c1 Polish OAuth2AuthorizationCodeGrantTests
2 parents 67305ab + fcbb5c1 commit 49f3bf6

File tree

3 files changed

+122
-5
lines changed

3 files changed

+122
-5
lines changed

docs/src/docs/asciidoc/configuration-model.adoc

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -253,3 +253,55 @@ The supported client authentication methods are `client_secret_basic`, `client_s
253253
* `*AuthenticationManager*` -- An `AuthenticationManager` composed of `JwtClientAssertionAuthenticationProvider`, `ClientSecretAuthenticationProvider`, and `PublicClientAuthenticationProvider`.
254254
* `*AuthenticationSuccessHandler*` -- An internal implementation that associates the "`authenticated`" `OAuth2ClientAuthenticationToken` (current `Authentication`) to the `SecurityContext`.
255255
* `*AuthenticationFailureHandler*` -- An internal implementation that uses the `OAuth2Error` associated with the `OAuth2AuthenticationException` to return the OAuth2 error response.
256+
257+
[[configuring-client-authentication-customizing-jwt-client-assertion-validation]]
258+
=== Customizing Jwt Client Assertion Validation
259+
260+
`JwtClientAssertionDecoderFactory.DEFAULT_JWT_VALIDATOR_FACTORY` is the default factory that provides an `OAuth2TokenValidator<Jwt>` for the specified `RegisteredClient` and is used for validating the `iss`, `sub`, `aud`, `exp` and `nbf` claims of the `Jwt` client assertion.
261+
262+
`JwtClientAssertionDecoderFactory` provides the ability to override the default `Jwt` client assertion validation by supplying a custom factory of type `Function<RegisteredClient, OAuth2TokenValidator<Jwt>>` to `setJwtValidatorFactory()`.
263+
264+
[NOTE]
265+
`JwtClientAssertionDecoderFactory` is the default `JwtDecoderFactory` used by `JwtClientAssertionAuthenticationProvider` that provides a `JwtDecoder` for the specified `RegisteredClient` and is used for authenticating a `Jwt` Bearer Token during OAuth2 client authentication.
266+
267+
A common use case for customizing `JwtClientAssertionDecoderFactory` is to validate additional claims in the `Jwt` client assertion.
268+
269+
The following example shows how to configure `JwtClientAssertionAuthenticationProvider` with a customized `JwtClientAssertionDecoderFactory` that validates an additional claim in the `Jwt` client assertion:
270+
271+
[source,java]
272+
----
273+
@Bean
274+
public SecurityFilterChain authorizationServerSecurityFilterChain(HttpSecurity http) throws Exception {
275+
OAuth2AuthorizationServerConfigurer authorizationServerConfigurer =
276+
new OAuth2AuthorizationServerConfigurer();
277+
http.apply(authorizationServerConfigurer);
278+
279+
authorizationServerConfigurer
280+
.clientAuthentication(clientAuthentication ->
281+
clientAuthentication
282+
.authenticationProviders(configureJwtClientAssertionValidator())
283+
);
284+
285+
return http.build();
286+
}
287+
288+
private Consumer<List<AuthenticationProvider>> configureJwtClientAssertionValidator() {
289+
return (authenticationProviders) ->
290+
authenticationProviders.forEach((authenticationProvider) -> {
291+
if (authenticationProvider instanceof JwtClientAssertionAuthenticationProvider) {
292+
// Customize JwtClientAssertionDecoderFactory
293+
JwtClientAssertionDecoderFactory jwtDecoderFactory = new JwtClientAssertionDecoderFactory();
294+
Function<RegisteredClient, OAuth2TokenValidator<Jwt>> jwtValidatorFactory = (registeredClient) ->
295+
new DelegatingOAuth2TokenValidator<>(
296+
// Use default validators
297+
JwtClientAssertionDecoderFactory.DEFAULT_JWT_VALIDATOR_FACTORY.apply(registeredClient),
298+
// Add custom validator
299+
new JwtClaimValidator<>("claim", "value"::equals));
300+
jwtDecoderFactory.setJwtValidatorFactory(jwtValidatorFactory);
301+
302+
((JwtClientAssertionAuthenticationProvider) authenticationProvider)
303+
.setJwtDecoderFactory(jwtDecoderFactory);
304+
}
305+
});
306+
}
307+
----

docs/src/docs/asciidoc/protocol-endpoints.adoc

Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,76 @@ public SecurityFilterChain authorizationServerSecurityFilterChain(HttpSecurity h
5050
* `*AuthenticationSuccessHandler*` -- An internal implementation that handles an "`authenticated`" `OAuth2AuthorizationCodeRequestAuthenticationToken` and returns the `OAuth2AuthorizationResponse`.
5151
* `*AuthenticationFailureHandler*` -- An internal implementation that uses the `OAuth2Error` associated with the `OAuth2AuthorizationCodeRequestAuthenticationException` and returns the `OAuth2Error` response.
5252

53+
[[oauth2-authorization-endpoint-customizing-authorization-request-validation]]
54+
=== Customizing Authorization Request Validation
55+
56+
`OAuth2AuthorizationCodeRequestAuthenticationValidator` is the default validator used for validating specific OAuth2 authorization request parameters used in the Authorization Code Grant.
57+
The default implementation validates the `redirect_uri` and `scope` parameters.
58+
If validation fails, an `OAuth2AuthorizationCodeRequestAuthenticationException` is thrown.
59+
60+
`OAuth2AuthorizationCodeRequestAuthenticationProvider` provides the ability to override the default authorization request validation by supplying a custom authentication validator of type `Consumer<OAuth2AuthorizationCodeRequestAuthenticationContext>` to `setAuthenticationValidator()`.
61+
62+
[TIP]
63+
`OAuth2AuthorizationCodeRequestAuthenticationContext` holds the `OAuth2AuthorizationCodeRequestAuthenticationToken`, which contains the OAuth2 authorization request parameters.
64+
65+
[IMPORTANT]
66+
If validation fails, the authentication validator *MUST* throw `OAuth2AuthorizationCodeRequestAuthenticationException`.
67+
68+
A common use case during the development life cycle phase is to allow for `localhost` in the `redirect_uri` parameter.
69+
70+
The following example shows how to configure `OAuth2AuthorizationCodeRequestAuthenticationProvider` with a custom authentication validator that allows for `localhost` in the `redirect_uri` parameter:
71+
72+
[source,java]
73+
----
74+
@Bean
75+
public SecurityFilterChain authorizationServerSecurityFilterChain(HttpSecurity http) throws Exception {
76+
OAuth2AuthorizationServerConfigurer authorizationServerConfigurer =
77+
new OAuth2AuthorizationServerConfigurer();
78+
http.apply(authorizationServerConfigurer);
79+
80+
authorizationServerConfigurer
81+
.authorizationEndpoint(authorizationEndpoint ->
82+
authorizationEndpoint
83+
.authenticationProviders(configureAuthenticationValidator())
84+
);
85+
86+
return http.build();
87+
}
88+
89+
private Consumer<List<AuthenticationProvider>> configureAuthenticationValidator() {
90+
return (authenticationProviders) ->
91+
authenticationProviders.forEach((authenticationProvider) -> {
92+
if (authenticationProvider instanceof OAuth2AuthorizationCodeRequestAuthenticationProvider) {
93+
Consumer<OAuth2AuthorizationCodeRequestAuthenticationContext> authenticationValidator =
94+
// Override default redirect_uri validator
95+
new CustomRedirectUriValidator()
96+
// Reuse default scope validator
97+
.andThen(OAuth2AuthorizationCodeRequestAuthenticationValidator.DEFAULT_SCOPE_VALIDATOR);
98+
99+
((OAuth2AuthorizationCodeRequestAuthenticationProvider) authenticationProvider)
100+
.setAuthenticationValidator(authenticationValidator);
101+
}
102+
});
103+
}
104+
105+
static class CustomRedirectUriValidator implements Consumer<OAuth2AuthorizationCodeRequestAuthenticationContext> {
106+
107+
@Override
108+
public void accept(OAuth2AuthorizationCodeRequestAuthenticationContext authenticationContext) {
109+
OAuth2AuthorizationCodeRequestAuthenticationToken authorizationCodeRequestAuthentication =
110+
authenticationContext.getAuthentication();
111+
RegisteredClient registeredClient = authenticationContext.getRegisteredClient();
112+
String requestedRedirectUri = authorizationCodeRequestAuthentication.getRedirectUri();
113+
114+
// Use exact string matching when comparing client redirect URIs against pre-registered URIs
115+
if (!registeredClient.getRedirectUris().contains(requestedRedirectUri)) {
116+
OAuth2Error error = new OAuth2Error(OAuth2ErrorCodes.INVALID_REQUEST);
117+
throw new OAuth2AuthorizationCodeRequestAuthenticationException(error, null);
118+
}
119+
}
120+
}
121+
----
122+
53123
[[oauth2-token-endpoint]]
54124
== OAuth2 Token Endpoint
55125

oauth2-authorization-server/src/test/java/org/springframework/security/oauth2/server/authorization/config/annotation/web/configurers/OAuth2AuthorizationCodeGrantTests.java

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -943,11 +943,6 @@ public SecurityFilterChain authorizationServerSecurityFilterChain(HttpSecurity h
943943
@EnableWebSecurity
944944
@Configuration(proxyBeanMethods = false)
945945
static class AuthorizationServerConfigurationCustomConsentRequest extends AuthorizationServerConfiguration {
946-
@Autowired
947-
private RegisteredClientRepository registeredClientRepository;
948-
949-
@Autowired
950-
private OAuth2AuthorizationService authorizationService;
951946

952947
@Autowired
953948
private OAuth2AuthorizationConsentService authorizationConsentService;

0 commit comments

Comments
 (0)