|
@@ -16,11 +16,30 @@
|
|
|
|
|
|
package org.springframework.security.oauth2.jwt;
|
|
|
|
|
|
+import java.net.UnknownHostException;
|
|
|
+import java.security.KeyFactory;
|
|
|
+import java.security.NoSuchAlgorithmException;
|
|
|
+import java.security.interfaces.RSAPublicKey;
|
|
|
+import java.security.spec.EncodedKeySpec;
|
|
|
+import java.security.spec.InvalidKeySpecException;
|
|
|
+import java.security.spec.X509EncodedKeySpec;
|
|
|
+import java.text.ParseException;
|
|
|
+import java.time.Instant;
|
|
|
+import java.util.Base64;
|
|
|
+import java.util.Collections;
|
|
|
+import java.util.Date;
|
|
|
+import java.util.Map;
|
|
|
+import javax.crypto.SecretKey;
|
|
|
+
|
|
|
import com.nimbusds.jose.JWSAlgorithm;
|
|
|
import com.nimbusds.jose.JWSHeader;
|
|
|
import com.nimbusds.jose.JWSSigner;
|
|
|
import com.nimbusds.jose.crypto.MACSigner;
|
|
|
import com.nimbusds.jose.jwk.JWKSet;
|
|
|
+import com.nimbusds.jose.jwk.source.JWKSource;
|
|
|
+import com.nimbusds.jose.proc.JWKSecurityContext;
|
|
|
+import com.nimbusds.jose.proc.JWSKeySelector;
|
|
|
+import com.nimbusds.jose.proc.JWSVerificationKeySelector;
|
|
|
import com.nimbusds.jwt.JWTClaimsSet;
|
|
|
import com.nimbusds.jwt.SignedJWT;
|
|
|
import okhttp3.mockwebserver.MockResponse;
|
|
@@ -29,6 +48,9 @@ import org.junit.After;
|
|
|
import org.junit.Before;
|
|
|
import org.junit.BeforeClass;
|
|
|
import org.junit.Test;
|
|
|
+import reactor.core.publisher.Flux;
|
|
|
+import reactor.core.publisher.Mono;
|
|
|
+
|
|
|
import org.springframework.core.convert.converter.Converter;
|
|
|
import org.springframework.security.oauth2.core.OAuth2Error;
|
|
|
import org.springframework.security.oauth2.core.OAuth2TokenValidator;
|
|
@@ -37,29 +59,19 @@ import org.springframework.security.oauth2.jose.TestKeys;
|
|
|
import org.springframework.security.oauth2.jose.jws.MacAlgorithm;
|
|
|
import org.springframework.security.oauth2.jose.jws.SignatureAlgorithm;
|
|
|
import org.springframework.web.reactive.function.client.WebClient;
|
|
|
-import reactor.core.publisher.Flux;
|
|
|
-import reactor.core.publisher.Mono;
|
|
|
-
|
|
|
-import javax.crypto.SecretKey;
|
|
|
-import java.net.UnknownHostException;
|
|
|
-import java.security.KeyFactory;
|
|
|
-import java.security.NoSuchAlgorithmException;
|
|
|
-import java.security.interfaces.RSAPublicKey;
|
|
|
-import java.security.spec.EncodedKeySpec;
|
|
|
-import java.security.spec.InvalidKeySpecException;
|
|
|
-import java.security.spec.X509EncodedKeySpec;
|
|
|
-import java.text.ParseException;
|
|
|
-import java.time.Instant;
|
|
|
-import java.util.Base64;
|
|
|
-import java.util.Collections;
|
|
|
-import java.util.Date;
|
|
|
-import java.util.Map;
|
|
|
|
|
|
import static org.assertj.core.api.Assertions.assertThat;
|
|
|
import static org.assertj.core.api.Assertions.assertThatCode;
|
|
|
import static org.assertj.core.api.AssertionsForClassTypes.assertThatThrownBy;
|
|
|
-import static org.mockito.Mockito.*;
|
|
|
-import static org.springframework.security.oauth2.jwt.NimbusReactiveJwtDecoder.*;
|
|
|
+import static org.mockito.ArgumentMatchers.any;
|
|
|
+import static org.mockito.Mockito.mock;
|
|
|
+import static org.mockito.Mockito.spy;
|
|
|
+import static org.mockito.Mockito.verify;
|
|
|
+import static org.mockito.Mockito.when;
|
|
|
+import static org.springframework.security.oauth2.jwt.NimbusReactiveJwtDecoder.withJwkSetUri;
|
|
|
+import static org.springframework.security.oauth2.jwt.NimbusReactiveJwtDecoder.withJwkSource;
|
|
|
+import static org.springframework.security.oauth2.jwt.NimbusReactiveJwtDecoder.withPublicKey;
|
|
|
+import static org.springframework.security.oauth2.jwt.NimbusReactiveJwtDecoder.withSecretKey;
|
|
|
|
|
|
/**
|
|
|
* @author Rob Winch
|
|
@@ -363,6 +375,46 @@ public class NimbusReactiveJwtDecoderTests {
|
|
|
.isInstanceOf(JwtException.class);
|
|
|
}
|
|
|
|
|
|
+ @Test
|
|
|
+ public void jwsKeySelectorWhenNoAlgorithmThenReturnsRS256Selector() {
|
|
|
+ JWKSource<JWKSecurityContext> jwkSource = mock(JWKSource.class);
|
|
|
+ JWSKeySelector<JWKSecurityContext> jwsKeySelector =
|
|
|
+ withJwkSetUri(this.jwkSetUri).jwsKeySelector(jwkSource);
|
|
|
+ assertThat(jwsKeySelector instanceof JWSVerificationKeySelector);
|
|
|
+ JWSVerificationKeySelector<JWKSecurityContext> jwsVerificationKeySelector =
|
|
|
+ (JWSVerificationKeySelector<JWKSecurityContext>) jwsKeySelector;
|
|
|
+ assertThat(jwsVerificationKeySelector.getExpectedJWSAlgorithm())
|
|
|
+ .isEqualTo(JWSAlgorithm.RS256);
|
|
|
+ }
|
|
|
+
|
|
|
+ @Test
|
|
|
+ public void jwsKeySelectorWhenOneAlgorithmThenReturnsSingleSelector() {
|
|
|
+ JWKSource<JWKSecurityContext> jwkSource = mock(JWKSource.class);
|
|
|
+ JWSKeySelector<JWKSecurityContext> jwsKeySelector =
|
|
|
+ withJwkSetUri(this.jwkSetUri).jwsAlgorithm(SignatureAlgorithm.RS512)
|
|
|
+ .jwsKeySelector(jwkSource);
|
|
|
+ assertThat(jwsKeySelector instanceof JWSVerificationKeySelector);
|
|
|
+ JWSVerificationKeySelector<JWKSecurityContext> jwsVerificationKeySelector =
|
|
|
+ (JWSVerificationKeySelector<JWKSecurityContext>) jwsKeySelector;
|
|
|
+ assertThat(jwsVerificationKeySelector.getExpectedJWSAlgorithm())
|
|
|
+ .isEqualTo(JWSAlgorithm.RS512);
|
|
|
+ }
|
|
|
+
|
|
|
+ @Test
|
|
|
+ public void jwsKeySelectorWhenMultipleAlgorithmThenReturnsCompositeSelector() {
|
|
|
+ JWKSource<JWKSecurityContext> jwkSource = mock(JWKSource.class);
|
|
|
+ JWSKeySelector<JWKSecurityContext> jwsKeySelector =
|
|
|
+ withJwkSetUri(this.jwkSetUri)
|
|
|
+ .jwsAlgorithm(SignatureAlgorithm.RS256)
|
|
|
+ .jwsAlgorithm(SignatureAlgorithm.RS512)
|
|
|
+ .jwsKeySelector(jwkSource);
|
|
|
+ assertThat(jwsKeySelector instanceof JWSAlgorithmMapJWSKeySelector);
|
|
|
+ JWSAlgorithmMapJWSKeySelector<?> jwsAlgorithmMapKeySelector =
|
|
|
+ (JWSAlgorithmMapJWSKeySelector<?>) jwsKeySelector;
|
|
|
+ assertThat(jwsAlgorithmMapKeySelector.getExpectedJWSAlgorithms())
|
|
|
+ .containsExactlyInAnyOrder(JWSAlgorithm.RS256, JWSAlgorithm.RS512);
|
|
|
+ }
|
|
|
+
|
|
|
private SignedJWT signedJwt(SecretKey secretKey, MacAlgorithm jwsAlgorithm, JWTClaimsSet claimsSet) throws Exception {
|
|
|
SignedJWT signedJWT = new SignedJWT(new JWSHeader(JWSAlgorithm.parse(jwsAlgorithm.getName())), claimsSet);
|
|
|
JWSSigner signer = new MACSigner(secretKey);
|