Skip to content

Commit f369593

Browse files
jzheauxBudlee
andcommitted
Polish to Avoid NPE
Issue gh-5648 Co-authored-by: MattyA <[email protected]>
1 parent 950769f commit f369593

File tree

4 files changed

+80
-29
lines changed

4 files changed

+80
-29
lines changed

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

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
import java.security.interfaces.RSAPublicKey;
2323
import java.text.ParseException;
2424
import java.util.Arrays;
25+
import java.util.Collection;
2526
import java.util.Collections;
2627
import java.util.HashMap;
2728
import java.util.HashSet;
@@ -55,11 +56,13 @@
5556
import org.springframework.http.MediaType;
5657
import org.springframework.http.RequestEntity;
5758
import org.springframework.http.ResponseEntity;
59+
import org.springframework.security.oauth2.core.OAuth2Error;
5860
import org.springframework.security.oauth2.core.OAuth2TokenValidator;
5961
import org.springframework.security.oauth2.core.OAuth2TokenValidatorResult;
6062
import org.springframework.security.oauth2.jose.jws.MacAlgorithm;
6163
import org.springframework.security.oauth2.jose.jws.SignatureAlgorithm;
6264
import org.springframework.util.Assert;
65+
import org.springframework.util.StringUtils;
6366
import org.springframework.web.client.RestOperations;
6467
import org.springframework.web.client.RestTemplate;
6568

@@ -167,9 +170,17 @@ private Jwt createJwt(String token, JWT parsedJwt) {
167170
private Jwt validateJwt(Jwt jwt){
168171
OAuth2TokenValidatorResult result = this.jwtValidator.validate(jwt);
169172
if (result.hasErrors()) {
170-
String description = result.getErrors().iterator().next().getDescription();
173+
Collection<OAuth2Error> errors = result.getErrors();
174+
String validationErrorString = "Unable to validate Jwt";
175+
for (OAuth2Error oAuth2Error : errors) {
176+
if (!StringUtils.isEmpty(oAuth2Error.getDescription())) {
177+
validationErrorString = String.format(
178+
DECODING_ERROR_MESSAGE_TEMPLATE, oAuth2Error.getDescription());
179+
break;
180+
}
181+
}
171182
throw new JwtValidationException(
172-
String.format(DECODING_ERROR_MESSAGE_TEMPLATE, description),
183+
validationErrorString,
173184
result.getErrors());
174185
}
175186

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

Lines changed: 35 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -15,17 +15,6 @@
1515
*/
1616
package org.springframework.security.oauth2.jwt;
1717

18-
import java.security.interfaces.RSAPublicKey;
19-
import java.util.Collections;
20-
import java.util.HashMap;
21-
import java.util.HashSet;
22-
import java.util.LinkedHashMap;
23-
import java.util.Map;
24-
import java.util.Set;
25-
import java.util.function.Consumer;
26-
import java.util.function.Function;
27-
import javax.crypto.SecretKey;
28-
2918
import com.nimbusds.jose.Header;
3019
import com.nimbusds.jose.JOSEException;
3120
import com.nimbusds.jose.JWSAlgorithm;
@@ -47,28 +36,41 @@
4736
import com.nimbusds.jwt.SignedJWT;
4837
import com.nimbusds.jwt.proc.DefaultJWTProcessor;
4938
import com.nimbusds.jwt.proc.JWTProcessor;
50-
import reactor.core.publisher.Flux;
51-
import reactor.core.publisher.Mono;
52-
5339
import org.springframework.core.convert.converter.Converter;
40+
import org.springframework.security.oauth2.core.OAuth2Error;
5441
import org.springframework.security.oauth2.core.OAuth2TokenValidator;
5542
import org.springframework.security.oauth2.core.OAuth2TokenValidatorResult;
5643
import org.springframework.security.oauth2.jose.jws.JwsAlgorithm;
5744
import org.springframework.security.oauth2.jose.jws.MacAlgorithm;
5845
import org.springframework.security.oauth2.jose.jws.SignatureAlgorithm;
5946
import org.springframework.util.Assert;
47+
import org.springframework.util.StringUtils;
6048
import org.springframework.web.reactive.function.client.WebClient;
49+
import reactor.core.publisher.Flux;
50+
import reactor.core.publisher.Mono;
51+
52+
import javax.crypto.SecretKey;
53+
import java.security.interfaces.RSAPublicKey;
54+
import java.util.Collection;
55+
import java.util.Collections;
56+
import java.util.HashMap;
57+
import java.util.HashSet;
58+
import java.util.LinkedHashMap;
59+
import java.util.Map;
60+
import java.util.Set;
61+
import java.util.function.Consumer;
62+
import java.util.function.Function;
6163

6264
/**
63-
* An implementation of a {@link ReactiveJwtDecoder} that &quot;decodes&quot; a
64-
* JSON Web Token (JWT) and additionally verifies it's digital signature if the JWT is a
65-
* JSON Web Signature (JWS).
66-
*
67-
* <p>
68-
* <b>NOTE:</b> This implementation uses the Nimbus JOSE + JWT SDK internally.
69-
*
70-
* @author Rob Winch
71-
* @author Joe Grandja
65+
* An implementation of a {@link ReactiveJwtDecoder} that &quot;decodes&quot; a
66+
* JSON Web Token (JWT) and additionally verifies it's digital signature if the JWT is a
67+
* JSON Web Signature (JWS).
68+
*
69+
* <p>
70+
* <b>NOTE:</b> This implementation uses the Nimbus JOSE + JWT SDK internally.
71+
*
72+
* @author Rob Winch
73+
* @author Joe Grandja
7274
* @since 5.1
7375
* @see ReactiveJwtDecoder
7476
* @see <a target="_blank" href="https://tools.ietf.org/html/rfc7519">JSON Web Token (JWT)</a>
@@ -178,10 +180,16 @@ private Jwt createJwt(JWT parsedJwt, JWTClaimsSet jwtClaimsSet) {
178180

179181
private Jwt validateJwt(Jwt jwt) {
180182
OAuth2TokenValidatorResult result = this.jwtValidator.validate(jwt);
181-
182-
if ( result.hasErrors() ) {
183-
String message = result.getErrors().iterator().next().getDescription();
184-
throw new JwtValidationException(message, result.getErrors());
183+
if (result.hasErrors()) {
184+
Collection<OAuth2Error> errors = result.getErrors();
185+
String validationErrorString = "Unable to validate Jwt";
186+
for (OAuth2Error oAuth2Error : errors) {
187+
if (!StringUtils.isEmpty(oAuth2Error.getDescription())) {
188+
validationErrorString = oAuth2Error.getDescription();
189+
break;
190+
}
191+
}
192+
throw new JwtValidationException(validationErrorString, errors);
185193
}
186194

187195
return jwt;

oauth2/oauth2-jose/src/test/java/org/springframework/security/oauth2/jwt/NimbusJwtDecoderTests.java

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -193,6 +193,22 @@ public void decodeWhenJwtValidationHasTwoErrorsThenJwtExceptionMessageShowsFirst
193193
.hasFieldOrPropertyWithValue("errors", Arrays.asList(firstFailure, secondFailure));
194194
}
195195

196+
@Test
197+
public void decodeWhenReadingErrorPickTheFirstErrorMessage() {
198+
OAuth2TokenValidator<Jwt> jwtValidator = mock(OAuth2TokenValidator.class);
199+
this.jwtDecoder.setJwtValidator(jwtValidator);
200+
201+
OAuth2Error errorEmpty = new OAuth2Error("mock-error", "", "mock-uri");
202+
OAuth2Error error = new OAuth2Error("mock-error", "mock-description", "mock-uri");
203+
OAuth2Error error2 = new OAuth2Error("mock-error-second", "mock-description-second", "mock-uri-second");
204+
OAuth2TokenValidatorResult result = OAuth2TokenValidatorResult.failure(errorEmpty, error, error2);
205+
when(jwtValidator.validate(any(Jwt.class))).thenReturn(result);
206+
207+
Assertions.assertThatCode(() -> this.jwtDecoder.decode(SIGNED_JWT))
208+
.isInstanceOf(JwtValidationException.class)
209+
.hasMessageContaining("mock-description");
210+
}
211+
196212
@Test
197213
public void decodeWhenUsingSignedJwtThenReturnsClaimsGivenByClaimSetConverter() {
198214
Converter<Map<String, Object>, Map<String, Object>> claimSetConverter = mock(Converter.class);

oauth2/oauth2-jose/src/test/java/org/springframework/security/oauth2/jwt/NimbusReactiveJwtDecoderTests.java

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -221,6 +221,22 @@ public void decodeWhenUsingCustomValidatorThenValidatorIsInvoked() {
221221
.hasMessageContaining("mock-description");
222222
}
223223

224+
@Test
225+
public void decodeWhenReadingErrorPickTheFirstErrorMessage() {
226+
OAuth2TokenValidator<Jwt> jwtValidator = mock(OAuth2TokenValidator.class);
227+
this.decoder.setJwtValidator(jwtValidator);
228+
229+
OAuth2Error errorEmpty = new OAuth2Error("mock-error", "", "mock-uri");
230+
OAuth2Error error = new OAuth2Error("mock-error", "mock-description", "mock-uri");
231+
OAuth2Error error2 = new OAuth2Error("mock-error-second", "mock-description-second", "mock-uri-second");
232+
OAuth2TokenValidatorResult result = OAuth2TokenValidatorResult.failure(errorEmpty, error, error2);
233+
when(jwtValidator.validate(any(Jwt.class))).thenReturn(result);
234+
235+
assertThatCode(() -> this.decoder.decode(this.messageReadToken).block())
236+
.isInstanceOf(JwtValidationException.class)
237+
.hasMessageContaining("mock-description");
238+
}
239+
224240
@Test
225241
public void decodeWhenUsingSignedJwtThenReturnsClaimsGivenByClaimSetConverter() {
226242
Converter<Map<String, Object>, Map<String, Object>> claimSetConverter = mock(Converter.class);

0 commit comments

Comments
 (0)