Skip to content

Commit 27f4dcb

Browse files
Max BatischevMax Batischev
Max Batischev
authored and
Max Batischev
committed
Add JwtValidators append to default
Implemented simplified creation of default OAuth2TokenValidator with additional validators. Closes gh-14831
1 parent e771267 commit 27f4dcb

File tree

5 files changed

+129
-16
lines changed

5 files changed

+129
-16
lines changed

config/src/main/java/org/springframework/security/config/annotation/web/configurers/oauth2/client/DefaultOidcLogoutTokenValidatorFactory.java

+3-5
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2023 the original author or authors.
2+
* Copyright 2002-2024 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -19,17 +19,15 @@
1919
import java.util.function.Function;
2020

2121
import org.springframework.security.oauth2.client.registration.ClientRegistration;
22-
import org.springframework.security.oauth2.core.DelegatingOAuth2TokenValidator;
2322
import org.springframework.security.oauth2.core.OAuth2TokenValidator;
2423
import org.springframework.security.oauth2.jwt.Jwt;
25-
import org.springframework.security.oauth2.jwt.JwtTimestampValidator;
24+
import org.springframework.security.oauth2.jwt.JwtValidators;
2625

2726
final class DefaultOidcLogoutTokenValidatorFactory implements Function<ClientRegistration, OAuth2TokenValidator<Jwt>> {
2827

2928
@Override
3029
public OAuth2TokenValidator<Jwt> apply(ClientRegistration clientRegistration) {
31-
return new DelegatingOAuth2TokenValidator<>(new JwtTimestampValidator(),
32-
new OidcBackChannelLogoutTokenValidator(clientRegistration));
30+
return JwtValidators.createDefaultWithValidators(new OidcBackChannelLogoutTokenValidator(clientRegistration));
3331
}
3432

3533
}

config/src/main/java/org/springframework/security/config/web/server/DefaultOidcLogoutTokenValidatorFactory.java

+3-5
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2023 the original author or authors.
2+
* Copyright 2002-2024 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -19,17 +19,15 @@
1919
import java.util.function.Function;
2020

2121
import org.springframework.security.oauth2.client.registration.ClientRegistration;
22-
import org.springframework.security.oauth2.core.DelegatingOAuth2TokenValidator;
2322
import org.springframework.security.oauth2.core.OAuth2TokenValidator;
2423
import org.springframework.security.oauth2.jwt.Jwt;
25-
import org.springframework.security.oauth2.jwt.JwtTimestampValidator;
24+
import org.springframework.security.oauth2.jwt.JwtValidators;
2625

2726
final class DefaultOidcLogoutTokenValidatorFactory implements Function<ClientRegistration, OAuth2TokenValidator<Jwt>> {
2827

2928
@Override
3029
public OAuth2TokenValidator<Jwt> apply(ClientRegistration clientRegistration) {
31-
return new DelegatingOAuth2TokenValidator<>(new JwtTimestampValidator(),
32-
new OidcBackChannelLogoutTokenValidator(clientRegistration));
30+
return JwtValidators.createDefaultWithValidators(new OidcBackChannelLogoutTokenValidator(clientRegistration));
3331
}
3432

3533
}

oauth2/oauth2-client/src/main/java/org/springframework/security/oauth2/client/oidc/authentication/DefaultOidcIdTokenValidatorFactory.java

+3-5
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2019 the original author or authors.
2+
* Copyright 2002-2024 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -19,10 +19,9 @@
1919
import java.util.function.Function;
2020

2121
import org.springframework.security.oauth2.client.registration.ClientRegistration;
22-
import org.springframework.security.oauth2.core.DelegatingOAuth2TokenValidator;
2322
import org.springframework.security.oauth2.core.OAuth2TokenValidator;
2423
import org.springframework.security.oauth2.jwt.Jwt;
25-
import org.springframework.security.oauth2.jwt.JwtTimestampValidator;
24+
import org.springframework.security.oauth2.jwt.JwtValidators;
2625

2726
/**
2827
* @author Joe Grandja
@@ -32,8 +31,7 @@ class DefaultOidcIdTokenValidatorFactory implements Function<ClientRegistration,
3231

3332
@Override
3433
public OAuth2TokenValidator<Jwt> apply(ClientRegistration clientRegistration) {
35-
return new DelegatingOAuth2TokenValidator<>(new JwtTimestampValidator(),
36-
new OidcIdTokenValidator(clientRegistration));
34+
return JwtValidators.createDefaultWithValidators(new OidcIdTokenValidator(clientRegistration));
3735
}
3836

3937
}

oauth2/oauth2-jose/src/main/java/org/springframework/security/oauth2/jwt/JwtValidators.java

+40-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2018 the original author or authors.
2+
* Copyright 2002-2024 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -22,6 +22,8 @@
2222

2323
import org.springframework.security.oauth2.core.DelegatingOAuth2TokenValidator;
2424
import org.springframework.security.oauth2.core.OAuth2TokenValidator;
25+
import org.springframework.util.Assert;
26+
import org.springframework.util.CollectionUtils;
2527

2628
/**
2729
* Provides factory methods for creating {@code OAuth2TokenValidator<Jwt>}
@@ -72,4 +74,41 @@ public static OAuth2TokenValidator<Jwt> createDefault() {
7274
return new DelegatingOAuth2TokenValidator<>(Arrays.asList(new JwtTimestampValidator()));
7375
}
7476

77+
/**
78+
* <p>
79+
* Create a {@link Jwt} default validator with standard validators and additional
80+
* validators.
81+
* </p>
82+
* @param validators additional validators
83+
* @return - a delegating validator containing all standard validators with additional
84+
* validators
85+
* @since 6.3
86+
*/
87+
public static OAuth2TokenValidator<Jwt> createDefaultWithValidators(List<OAuth2TokenValidator<Jwt>> validators) {
88+
Assert.notEmpty(validators, "validators cannot be null or empty");
89+
List<OAuth2TokenValidator<Jwt>> tokenValidators = new ArrayList<>(validators);
90+
JwtTimestampValidator jwtTimestampValidator = CollectionUtils.findValueOfType(tokenValidators,
91+
JwtTimestampValidator.class);
92+
if (jwtTimestampValidator == null) {
93+
tokenValidators.add(new JwtTimestampValidator());
94+
}
95+
return new DelegatingOAuth2TokenValidator<>(tokenValidators);
96+
}
97+
98+
/**
99+
* <p>
100+
* Create a {@link Jwt} default validator with standard validators and additional
101+
* validators.
102+
* </p>
103+
* @param validators additional validators
104+
* @return - a delegating validator containing all standard validators with additional
105+
* validators
106+
* @since 6.3
107+
*/
108+
public static OAuth2TokenValidator<Jwt> createDefaultWithValidators(OAuth2TokenValidator<Jwt>... validators) {
109+
Assert.notEmpty(validators, "validators cannot be null or empty");
110+
List<OAuth2TokenValidator<Jwt>> tokenValidators = new ArrayList<>(Arrays.asList(validators));
111+
return createDefaultWithValidators(tokenValidators);
112+
}
113+
75114
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
/*
2+
* Copyright 2002-2024 the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* https://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package org.springframework.security.oauth2.jwt;
18+
19+
import java.util.Collection;
20+
import java.util.Collections;
21+
import java.util.Objects;
22+
23+
import org.junit.jupiter.api.Test;
24+
25+
import org.springframework.security.oauth2.core.DelegatingOAuth2TokenValidator;
26+
import org.springframework.security.oauth2.core.OAuth2TokenValidator;
27+
import org.springframework.test.util.ReflectionTestUtils;
28+
import org.springframework.util.CollectionUtils;
29+
30+
import static org.assertj.core.api.Assertions.assertThat;
31+
import static org.assertj.core.api.Assertions.assertThatException;
32+
33+
/**
34+
* Tests for {@link JwtValidators}.
35+
*
36+
* @author Max Batischev
37+
*/
38+
public class JwtValidatorsTests {
39+
40+
private static final String ISS_CLAIM = "iss";
41+
42+
@Test
43+
public void createWhenJwtIssuerValidatorIsPresentThenCreateDefaultValidatorWithJwtIssuerValidator() {
44+
OAuth2TokenValidator<Jwt> validator = JwtValidators
45+
.createDefaultWithValidators(new JwtIssuerValidator(ISS_CLAIM));
46+
47+
assertThat(containsByType(validator, JwtIssuerValidator.class)).isTrue();
48+
assertThat(containsByType(validator, JwtTimestampValidator.class)).isTrue();
49+
}
50+
51+
@Test
52+
@SuppressWarnings("unchecked")
53+
public void createWhenJwtTimestampValidatorIsPresentThenCreateDefaultValidatorWithOnlyOneJwtTimestampValidator() {
54+
OAuth2TokenValidator<Jwt> validator = JwtValidators.createDefaultWithValidators(new JwtTimestampValidator());
55+
56+
DelegatingOAuth2TokenValidator<Jwt> delegatingOAuth2TokenValidator = (DelegatingOAuth2TokenValidator<Jwt>) validator;
57+
Collection<OAuth2TokenValidator<Jwt>> tokenValidators = (Collection<OAuth2TokenValidator<Jwt>>) ReflectionTestUtils
58+
.getField(delegatingOAuth2TokenValidator, "tokenValidators");
59+
60+
assertThat(containsByType(validator, JwtTimestampValidator.class)).isTrue();
61+
assertThat(Objects.requireNonNull(tokenValidators).size()).isEqualTo(1);
62+
}
63+
64+
@Test
65+
public void createWhenEmptyValidatorsThenThrowsException() {
66+
assertThatException().isThrownBy(() -> JwtValidators.createDefaultWithValidators(Collections.emptyList()));
67+
}
68+
69+
@SuppressWarnings("unchecked")
70+
private boolean containsByType(OAuth2TokenValidator<Jwt> validator, Class<? extends OAuth2TokenValidator<?>> type) {
71+
DelegatingOAuth2TokenValidator<Jwt> delegatingOAuth2TokenValidator = (DelegatingOAuth2TokenValidator<Jwt>) validator;
72+
Collection<OAuth2TokenValidator<Jwt>> tokenValidators = (Collection<OAuth2TokenValidator<Jwt>>) ReflectionTestUtils
73+
.getField(delegatingOAuth2TokenValidator, "tokenValidators");
74+
75+
OAuth2TokenValidator<?> tokenValidator = CollectionUtils
76+
.findValueOfType(Objects.requireNonNull(tokenValidators), type);
77+
return tokenValidator != null;
78+
}
79+
80+
}

0 commit comments

Comments
 (0)