Remove CryptoKeySource

Closes gh-196
This commit is contained in:
Joe Grandja
2021-01-15 05:57:15 -05:00
parent 4b37606807
commit 12f4001c9d
34 changed files with 1089 additions and 1280 deletions

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2020 the original author or authors.
* Copyright 2020-2021 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -15,11 +15,20 @@
*/
package org.springframework.security.config.annotation.web.configurers.oauth2.server.authorization;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.util.Base64;
import java.util.function.BiConsumer;
import com.nimbusds.jose.jwk.JWKSet;
import com.nimbusds.jose.jwk.source.JWKSource;
import com.nimbusds.jose.proc.SecurityContext;
import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.Rule;
import org.junit.Test;
import org.mockito.ArgumentCaptor;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Import;
@@ -27,16 +36,15 @@ import org.springframework.http.HttpHeaders;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.OAuth2AuthorizationServerConfiguration;
import org.springframework.security.config.test.SpringTestRule;
import org.springframework.security.crypto.key.CryptoKeySource;
import org.springframework.security.crypto.key.StaticKeyGeneratingCryptoKeySource;
import org.springframework.security.oauth2.core.AuthorizationGrantType;
import org.springframework.security.oauth2.core.endpoint.OAuth2AuthorizationResponseType;
import org.springframework.security.oauth2.core.endpoint.OAuth2ParameterNames;
import org.springframework.security.oauth2.core.endpoint.PkceParameterNames;
import org.springframework.security.oauth2.jose.JoseHeader;
import org.springframework.security.oauth2.jose.jws.NimbusJwsEncoder;
import org.springframework.security.oauth2.jose.TestJwks;
import org.springframework.security.oauth2.jwt.JoseHeader;
import org.springframework.security.oauth2.jwt.JwtClaimsSet;
import org.springframework.security.oauth2.jwt.JwtEncoder;
import org.springframework.security.oauth2.jwt.NimbusJwsEncoder;
import org.springframework.security.oauth2.server.authorization.OAuth2Authorization;
import org.springframework.security.oauth2.server.authorization.OAuth2AuthorizationService;
import org.springframework.security.oauth2.server.authorization.TestOAuth2Authorizations;
@@ -54,11 +62,6 @@ import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap;
import org.springframework.util.StringUtils;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.util.Base64;
import java.util.function.BiConsumer;
import static org.assertj.core.api.Assertions.assertThat;
import static org.hamcrest.CoreMatchers.containsString;
import static org.mockito.ArgumentMatchers.any;
@@ -90,7 +93,7 @@ public class OAuth2AuthorizationCodeGrantTests {
private static RegisteredClientRepository registeredClientRepository;
private static OAuth2AuthorizationService authorizationService;
private static CryptoKeySource keySource;
private static JWKSource<SecurityContext> jwkSource;
private static NimbusJwsEncoder jwtEncoder;
private static BiConsumer<JoseHeader.Builder, JwtClaimsSet.Builder> jwtCustomizer;
@@ -104,8 +107,9 @@ public class OAuth2AuthorizationCodeGrantTests {
public static void init() {
registeredClientRepository = mock(RegisteredClientRepository.class);
authorizationService = mock(OAuth2AuthorizationService.class);
keySource = new StaticKeyGeneratingCryptoKeySource();
jwtEncoder = new NimbusJwsEncoder(keySource);
JWKSet jwkSet = new JWKSet(TestJwks.DEFAULT_RSA_JWK);
jwkSource = (jwkSelector, securityContext) -> jwkSelector.select(jwkSet);
jwtEncoder = new NimbusJwsEncoder(jwkSource);
jwtCustomizer = mock(BiConsumer.class);
jwtEncoder.setJwtCustomizer(jwtCustomizer);
}
@@ -298,8 +302,8 @@ public class OAuth2AuthorizationCodeGrantTests {
}
@Bean
CryptoKeySource keySource() {
return keySource;
JWKSource<SecurityContext> jwkSource() {
return jwkSource;
}
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2020 the original author or authors.
* Copyright 2020-2021 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -15,10 +15,18 @@
*/
package org.springframework.security.config.annotation.web.configurers.oauth2.server.authorization;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.util.Base64;
import com.nimbusds.jose.jwk.JWKSet;
import com.nimbusds.jose.jwk.source.JWKSource;
import com.nimbusds.jose.proc.SecurityContext;
import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.Rule;
import org.junit.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Import;
@@ -26,10 +34,9 @@ import org.springframework.http.HttpHeaders;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.OAuth2AuthorizationServerConfiguration;
import org.springframework.security.config.test.SpringTestRule;
import org.springframework.security.crypto.key.CryptoKeySource;
import org.springframework.security.crypto.key.StaticKeyGeneratingCryptoKeySource;
import org.springframework.security.oauth2.core.AuthorizationGrantType;
import org.springframework.security.oauth2.core.endpoint.OAuth2ParameterNames;
import org.springframework.security.oauth2.jose.TestJwks;
import org.springframework.security.oauth2.server.authorization.OAuth2AuthorizationService;
import org.springframework.security.oauth2.server.authorization.client.RegisteredClient;
import org.springframework.security.oauth2.server.authorization.client.RegisteredClientRepository;
@@ -38,10 +45,6 @@ import org.springframework.security.oauth2.server.authorization.web.OAuth2TokenE
import org.springframework.test.web.servlet.MockMvc;
import org.springframework.test.web.servlet.request.MockMvcRequestBuilders;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.util.Base64;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.mock;
@@ -61,7 +64,7 @@ import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.
public class OAuth2ClientCredentialsGrantTests {
private static RegisteredClientRepository registeredClientRepository;
private static OAuth2AuthorizationService authorizationService;
private static CryptoKeySource keySource;
private static JWKSource<SecurityContext> jwkSource;
@Rule
public final SpringTestRule spring = new SpringTestRule();
@@ -73,7 +76,8 @@ public class OAuth2ClientCredentialsGrantTests {
public static void init() {
registeredClientRepository = mock(RegisteredClientRepository.class);
authorizationService = mock(OAuth2AuthorizationService.class);
keySource = new StaticKeyGeneratingCryptoKeySource();
JWKSet jwkSet = new JWKSet(TestJwks.DEFAULT_RSA_JWK);
jwkSource = (jwkSelector, securityContext) -> jwkSelector.select(jwkSet);
}
@Before
@@ -159,8 +163,8 @@ public class OAuth2ClientCredentialsGrantTests {
}
@Bean
CryptoKeySource keySource() {
return keySource;
JWKSource<SecurityContext> jwkSource() {
return jwkSource;
}
}
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2020 the original author or authors.
* Copyright 2020-2021 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -15,10 +15,18 @@
*/
package org.springframework.security.config.annotation.web.configurers.oauth2.server.authorization;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.util.Base64;
import com.nimbusds.jose.jwk.JWKSet;
import com.nimbusds.jose.jwk.source.JWKSource;
import com.nimbusds.jose.proc.SecurityContext;
import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.Rule;
import org.junit.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Import;
@@ -26,10 +34,9 @@ import org.springframework.http.HttpHeaders;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.OAuth2AuthorizationServerConfiguration;
import org.springframework.security.config.test.SpringTestRule;
import org.springframework.security.crypto.key.CryptoKeySource;
import org.springframework.security.crypto.key.StaticKeyGeneratingCryptoKeySource;
import org.springframework.security.oauth2.core.AuthorizationGrantType;
import org.springframework.security.oauth2.core.endpoint.OAuth2ParameterNames;
import org.springframework.security.oauth2.jose.TestJwks;
import org.springframework.security.oauth2.server.authorization.OAuth2Authorization;
import org.springframework.security.oauth2.server.authorization.OAuth2AuthorizationService;
import org.springframework.security.oauth2.server.authorization.TestOAuth2Authorizations;
@@ -42,10 +49,6 @@ import org.springframework.test.web.servlet.MockMvc;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.util.Base64;
import static org.hamcrest.CoreMatchers.containsString;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.eq;
@@ -67,7 +70,7 @@ import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.
public class OAuth2RefreshTokenGrantTests {
private static RegisteredClientRepository registeredClientRepository;
private static OAuth2AuthorizationService authorizationService;
private static CryptoKeySource keySource;
private static JWKSource<SecurityContext> jwkSource;
@Rule
public final SpringTestRule spring = new SpringTestRule();
@@ -79,7 +82,8 @@ public class OAuth2RefreshTokenGrantTests {
public static void init() {
registeredClientRepository = mock(RegisteredClientRepository.class);
authorizationService = mock(OAuth2AuthorizationService.class);
keySource = new StaticKeyGeneratingCryptoKeySource();
JWKSet jwkSet = new JWKSet(TestJwks.DEFAULT_RSA_JWK);
jwkSource = (jwkSelector, securityContext) -> jwkSelector.select(jwkSet);
}
@Before
@@ -153,8 +157,8 @@ public class OAuth2RefreshTokenGrantTests {
}
@Bean
CryptoKeySource keySource() {
return keySource;
JWKSource<SecurityContext> jwkSource() {
return jwkSource;
}
}
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2020 the original author or authors.
* Copyright 2020-2021 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -15,11 +15,19 @@
*/
package org.springframework.security.config.annotation.web.configurers.oauth2.server.authorization;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.util.Base64;
import com.nimbusds.jose.jwk.JWKSet;
import com.nimbusds.jose.jwk.source.JWKSource;
import com.nimbusds.jose.proc.SecurityContext;
import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.Rule;
import org.junit.Test;
import org.mockito.ArgumentCaptor;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Import;
@@ -27,12 +35,11 @@ import org.springframework.http.HttpHeaders;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.OAuth2AuthorizationServerConfiguration;
import org.springframework.security.config.test.SpringTestRule;
import org.springframework.security.crypto.key.CryptoKeySource;
import org.springframework.security.crypto.key.StaticKeyGeneratingCryptoKeySource;
import org.springframework.security.oauth2.core.AbstractOAuth2Token;
import org.springframework.security.oauth2.core.OAuth2AccessToken;
import org.springframework.security.oauth2.core.OAuth2RefreshToken;
import org.springframework.security.oauth2.core.endpoint.OAuth2ParameterNames2;
import org.springframework.security.oauth2.jose.TestJwks;
import org.springframework.security.oauth2.server.authorization.OAuth2Authorization;
import org.springframework.security.oauth2.server.authorization.OAuth2AuthorizationService;
import org.springframework.security.oauth2.server.authorization.TestOAuth2Authorizations;
@@ -46,10 +53,6 @@ import org.springframework.test.web.servlet.request.MockMvcRequestBuilders;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.util.Base64;
import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.mock;
@@ -66,7 +69,7 @@ import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.
public class OAuth2TokenRevocationTests {
private static RegisteredClientRepository registeredClientRepository;
private static OAuth2AuthorizationService authorizationService;
private static CryptoKeySource keySource;
private static JWKSource<SecurityContext> jwkSource;
@Rule
public final SpringTestRule spring = new SpringTestRule();
@@ -78,7 +81,8 @@ public class OAuth2TokenRevocationTests {
public static void init() {
registeredClientRepository = mock(RegisteredClientRepository.class);
authorizationService = mock(OAuth2AuthorizationService.class);
keySource = new StaticKeyGeneratingCryptoKeySource();
JWKSet jwkSet = new JWKSet(TestJwks.DEFAULT_RSA_JWK);
jwkSource = (jwkSelector, securityContext) -> jwkSelector.select(jwkSet);
}
@Before
@@ -181,8 +185,8 @@ public class OAuth2TokenRevocationTests {
}
@Bean
CryptoKeySource keySource() {
return keySource;
JWKSource<SecurityContext> jwkSource() {
return jwkSource;
}
}
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2020 the original author or authors.
* Copyright 2020-2021 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -15,11 +15,19 @@
*/
package org.springframework.security.config.annotation.web.configurers.oauth2.server.authorization;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.util.Base64;
import com.nimbusds.jose.jwk.JWKSet;
import com.nimbusds.jose.jwk.source.JWKSource;
import com.nimbusds.jose.proc.SecurityContext;
import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.Rule;
import org.junit.Test;
import org.mockito.ArgumentCaptor;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Import;
@@ -27,12 +35,11 @@ import org.springframework.http.HttpHeaders;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.OAuth2AuthorizationServerConfiguration;
import org.springframework.security.config.test.SpringTestRule;
import org.springframework.security.crypto.key.CryptoKeySource;
import org.springframework.security.crypto.key.StaticKeyGeneratingCryptoKeySource;
import org.springframework.security.oauth2.core.AuthorizationGrantType;
import org.springframework.security.oauth2.core.endpoint.OAuth2AuthorizationResponseType;
import org.springframework.security.oauth2.core.endpoint.OAuth2ParameterNames;
import org.springframework.security.oauth2.core.oidc.OidcScopes;
import org.springframework.security.oauth2.jose.TestJwks;
import org.springframework.security.oauth2.server.authorization.OAuth2Authorization;
import org.springframework.security.oauth2.server.authorization.OAuth2AuthorizationService;
import org.springframework.security.oauth2.server.authorization.TokenType;
@@ -40,20 +47,16 @@ import org.springframework.security.oauth2.server.authorization.client.Registere
import org.springframework.security.oauth2.server.authorization.client.RegisteredClientRepository;
import org.springframework.security.oauth2.server.authorization.client.TestRegisteredClients;
import org.springframework.security.oauth2.server.authorization.config.ProviderSettings;
import org.springframework.security.oauth2.server.authorization.oidc.web.OidcProviderConfigurationEndpointFilter;
import org.springframework.security.oauth2.server.authorization.token.OAuth2AuthorizationCode;
import org.springframework.security.oauth2.server.authorization.web.OAuth2AuthorizationEndpointFilter;
import org.springframework.security.oauth2.server.authorization.web.OAuth2TokenEndpointFilter;
import org.springframework.security.oauth2.server.authorization.oidc.web.OidcProviderConfigurationEndpointFilter;
import org.springframework.test.web.servlet.MockMvc;
import org.springframework.test.web.servlet.MvcResult;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap;
import org.springframework.util.StringUtils;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.util.Base64;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatThrownBy;
import static org.hamcrest.CoreMatchers.containsString;
@@ -80,7 +83,7 @@ public class OidcTests {
private static final String issuerUrl = "https://example.com/issuer1";
private static RegisteredClientRepository registeredClientRepository;
private static OAuth2AuthorizationService authorizationService;
private static CryptoKeySource keySource;
private static JWKSource<SecurityContext> jwkSource;
@Rule
public final SpringTestRule spring = new SpringTestRule();
@@ -92,7 +95,8 @@ public class OidcTests {
public static void init() {
registeredClientRepository = mock(RegisteredClientRepository.class);
authorizationService = mock(OAuth2AuthorizationService.class);
keySource = new StaticKeyGeneratingCryptoKeySource();
JWKSet jwkSet = new JWKSet(TestJwks.DEFAULT_RSA_JWK);
jwkSource = (jwkSelector, securityContext) -> jwkSelector.select(jwkSet);
}
@Before
@@ -224,8 +228,8 @@ public class OidcTests {
}
@Bean
CryptoKeySource keySource() {
return keySource;
JWKSource<SecurityContext> jwkSource() {
return jwkSource;
}
}

View File

@@ -1,113 +0,0 @@
/*
* Copyright 2020 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.security.crypto.key;
import org.junit.BeforeClass;
import org.junit.Test;
import javax.crypto.SecretKey;
import java.security.KeyPair;
import java.util.HashMap;
import java.util.Map;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatThrownBy;
import static org.springframework.security.crypto.key.KeyGeneratorUtils.generateRsaKey;
import static org.springframework.security.crypto.key.KeyGeneratorUtils.generateSecretKey;
/**
* Tests for {@link CryptoKey}.
*
* @author Joe Grandja
*/
public class CryptoKeyTests {
private static SecretKey secretKey;
private static KeyPair rsaKeyPair;
@BeforeClass
public static void init() {
secretKey = generateSecretKey();
rsaKeyPair = generateRsaKey();
}
@Test
public void symmetricWhenSecretKeyNullThenThrowIllegalArgumentException() {
assertThatThrownBy(() -> CryptoKey.symmetric(null))
.isInstanceOf(IllegalArgumentException.class)
.hasMessage("key cannot be null");
}
@Test
public void metadataWhenNameNullThenThrowIllegalArgumentException() {
assertThatThrownBy(() -> CryptoKey.symmetric(secretKey).metadata(null, "value"))
.isInstanceOf(IllegalArgumentException.class)
.hasMessage("name cannot be empty");
}
@Test
public void metadataWhenValueNullThenThrowIllegalArgumentException() {
assertThatThrownBy(() -> CryptoKey.symmetric(secretKey).metadata("name", null))
.isInstanceOf(IllegalArgumentException.class)
.hasMessage("value cannot be null");
}
@Test
public void symmetricWhenAllAttributesProvidedThenAllAttributesAreSet() {
Map<String, Object> keyMetadata = new HashMap<>();
keyMetadata.put("name1", "value1");
keyMetadata.put("name2", "value2");
SymmetricKey symmetricKey = CryptoKey.symmetric(secretKey)
.id("id")
.metadata(metadata -> metadata.putAll(keyMetadata))
.build();
assertThat(symmetricKey.getKey()).isEqualTo(secretKey);
assertThat(symmetricKey.getId()).isEqualTo("id");
assertThat(symmetricKey.getMetadata()).isEqualTo(keyMetadata);
}
@Test
public void asymmetricWhenPrivateKeyNullThenThrowIllegalArgumentException() {
assertThatThrownBy(() -> CryptoKey.asymmetric(null, rsaKeyPair.getPublic()))
.isInstanceOf(IllegalArgumentException.class)
.hasMessage("key cannot be null");
}
@Test
public void asymmetricWhenPublicKeyNullThenThrowIllegalArgumentException() {
assertThatThrownBy(() -> CryptoKey.asymmetric(rsaKeyPair.getPrivate(), null))
.isInstanceOf(IllegalArgumentException.class)
.hasMessage("publicKey cannot be null");
}
@Test
public void asymmetricWhenAllAttributesProvidedThenAllAttributesAreSet() {
Map<String, Object> keyMetadata = new HashMap<>();
keyMetadata.put("name1", "value1");
keyMetadata.put("name2", "value2");
AsymmetricKey asymmetricKey = CryptoKey.asymmetric(rsaKeyPair.getPrivate(), rsaKeyPair.getPublic())
.id("id")
.metadata(metadata -> metadata.putAll(keyMetadata))
.build();
assertThat(asymmetricKey.getKey()).isEqualTo(rsaKeyPair.getPrivate());
assertThat(asymmetricKey.getPublicKey()).isEqualTo(rsaKeyPair.getPublic());
assertThat(asymmetricKey.getId()).isEqualTo("id");
assertThat(asymmetricKey.getMetadata()).isEqualTo(keyMetadata);
}
}

View File

@@ -1,42 +0,0 @@
/*
* Copyright 2020 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.security.crypto.key;
import java.security.KeyPair;
import static org.springframework.security.crypto.key.KeyGeneratorUtils.generateEcKey;
import static org.springframework.security.crypto.key.KeyGeneratorUtils.generateRsaKey;
import static org.springframework.security.crypto.key.KeyGeneratorUtils.generateSecretKey;
/**
* @author Joe Grandja
*/
public class TestCryptoKeys {
public static SymmetricKey.Builder secretKey() {
return CryptoKey.symmetric(generateSecretKey());
}
public static AsymmetricKey.Builder rsaKey() {
KeyPair rsaKeyPair = generateRsaKey();
return CryptoKey.asymmetric(rsaKeyPair.getPrivate(), rsaKeyPair.getPublic());
}
public static AsymmetricKey.Builder ecKey() {
KeyPair ecKeyPair = generateEcKey();
return CryptoKey.asymmetric(ecKeyPair.getPrivate(), ecKeyPair.getPublic());
}
}

View File

@@ -0,0 +1,89 @@
/*
* Copyright 2020-2021 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.security.oauth2.jose;
import java.security.interfaces.ECPrivateKey;
import java.security.interfaces.ECPublicKey;
import java.security.interfaces.RSAPrivateKey;
import java.security.interfaces.RSAPublicKey;
import javax.crypto.SecretKey;
import com.nimbusds.jose.jwk.Curve;
import com.nimbusds.jose.jwk.ECKey;
import com.nimbusds.jose.jwk.KeyUse;
import com.nimbusds.jose.jwk.OctetSequenceKey;
import com.nimbusds.jose.jwk.RSAKey;
/**
* @author Joe Grandja
*/
public final class TestJwks {
// @formatter:off
public static final RSAKey DEFAULT_RSA_JWK =
jwk(
TestKeys.DEFAULT_PUBLIC_KEY,
TestKeys.DEFAULT_PRIVATE_KEY
).build();
// @formatter:on
// @formatter:off
public static final ECKey DEFAULT_EC_JWK =
jwk(
(ECPublicKey) TestKeys.DEFAULT_EC_KEY_PAIR.getPublic(),
(ECPrivateKey) TestKeys.DEFAULT_EC_KEY_PAIR.getPrivate()
).build();
// @formatter:on
// @formatter:off
public static final OctetSequenceKey DEFAULT_SECRET_JWK =
jwk(
TestKeys.DEFAULT_SECRET_KEY
).build();
// @formatter:on
private TestJwks() {
}
public static RSAKey.Builder jwk(RSAPublicKey publicKey, RSAPrivateKey privateKey) {
// @formatter:off
return new RSAKey.Builder(publicKey)
.privateKey(privateKey)
.keyUse(KeyUse.SIGNATURE)
.keyID("rsa-jwk-kid");
// @formatter:on
}
public static ECKey.Builder jwk(ECPublicKey publicKey, ECPrivateKey privateKey) {
// @formatter:off
Curve curve = Curve.forECParameterSpec(publicKey.getParams());
return new ECKey.Builder(curve, publicKey)
.privateKey(privateKey)
.keyUse(KeyUse.SIGNATURE)
.keyID("ec-jwk-kid");
// @formatter:on
}
public static OctetSequenceKey.Builder jwk(SecretKey secretKey) {
// @formatter:off
return new OctetSequenceKey.Builder(secretKey)
.keyUse(KeyUse.SIGNATURE)
.keyID("secret-jwk-kid");
// @formatter:on
}
}

View File

@@ -0,0 +1,154 @@
/*
* Copyright 2002-2021 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.security.oauth2.jose;
import java.math.BigInteger;
import java.security.KeyFactory;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.NoSuchAlgorithmException;
import java.security.interfaces.RSAPrivateKey;
import java.security.interfaces.RSAPublicKey;
import java.security.spec.ECFieldFp;
import java.security.spec.ECParameterSpec;
import java.security.spec.ECPoint;
import java.security.spec.EllipticCurve;
import java.security.spec.InvalidKeySpecException;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
import java.util.Base64;
import javax.crypto.SecretKey;
import javax.crypto.spec.SecretKeySpec;
/**
* TODO
* This class is a straight copy from Spring Security.
* It should be removed when merging this codebase into Spring Security.
*
* @author Joe Grandja
* @since 5.2
*/
public final class TestKeys {
public static final KeyFactory kf;
static {
try {
kf = KeyFactory.getInstance("RSA");
}
catch (NoSuchAlgorithmException ex) {
throw new IllegalStateException(ex);
}
}
public static final String DEFAULT_ENCODED_SECRET_KEY = "bCzY/M48bbkwBEWjmNSIEPfwApcvXOnkCxORBEbPr+4=";
public static final SecretKey DEFAULT_SECRET_KEY = new SecretKeySpec(
Base64.getDecoder().decode(DEFAULT_ENCODED_SECRET_KEY), "AES");
// @formatter:off
public static final String DEFAULT_RSA_PUBLIC_KEY = "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA3FlqJr5TRskIQIgdE3Dd"
+ "7D9lboWdcTUT8a+fJR7MAvQm7XXNoYkm3v7MQL1NYtDvL2l8CAnc0WdSTINU6IRv"
+ "c5Kqo2Q4csNX9SHOmEfzoROjQqahEcve1jBXluoCXdYuYpx4/1tfRgG6ii4Uhxh6"
+ "iI8qNMJQX+fLfqhbfYfxBQVRPywBkAbIP4x1EAsbC6FSNmkhCxiMNqEgxaIpY8C2"
+ "kJdJ/ZIV+WW4noDdzpKqHcwmB8FsrumlVY/DNVvUSDIipiq9PbP4H99TXN1o746o"
+ "RaNa07rq1hoCgMSSy+85SagCoxlmyE+D+of9SsMY8Ol9t0rdzpobBuhyJ/o5dfvj"
+ "KwIDAQAB";
// @formatter:on
public static final RSAPublicKey DEFAULT_PUBLIC_KEY;
static {
X509EncodedKeySpec spec = new X509EncodedKeySpec(Base64.getDecoder().decode(DEFAULT_RSA_PUBLIC_KEY));
try {
DEFAULT_PUBLIC_KEY = (RSAPublicKey) kf.generatePublic(spec);
}
catch (InvalidKeySpecException ex) {
throw new IllegalArgumentException(ex);
}
}
// @formatter:off
public static final String DEFAULT_RSA_PRIVATE_KEY = "MIIEvwIBADANBgkqhkiG9w0BAQEFAASCBKkwggSlAgEAAoIBAQDcWWomvlNGyQhA"
+ "iB0TcN3sP2VuhZ1xNRPxr58lHswC9Cbtdc2hiSbe/sxAvU1i0O8vaXwICdzRZ1JM"
+ "g1TohG9zkqqjZDhyw1f1Ic6YR/OhE6NCpqERy97WMFeW6gJd1i5inHj/W19GAbqK"
+ "LhSHGHqIjyo0wlBf58t+qFt9h/EFBVE/LAGQBsg/jHUQCxsLoVI2aSELGIw2oSDF"
+ "oiljwLaQl0n9khX5ZbiegN3OkqodzCYHwWyu6aVVj8M1W9RIMiKmKr09s/gf31Nc"
+ "3WjvjqhFo1rTuurWGgKAxJLL7zlJqAKjGWbIT4P6h/1Kwxjw6X23St3OmhsG6HIn"
+ "+jl1++MrAgMBAAECggEBAMf820wop3pyUOwI3aLcaH7YFx5VZMzvqJdNlvpg1jbE"
+ "E2Sn66b1zPLNfOIxLcBG8x8r9Ody1Bi2Vsqc0/5o3KKfdgHvnxAB3Z3dPh2WCDek"
+ "lCOVClEVoLzziTuuTdGO5/CWJXdWHcVzIjPxmK34eJXioiLaTYqN3XKqKMdpD0ZG"
+ "mtNTGvGf+9fQ4i94t0WqIxpMpGt7NM4RHy3+Onggev0zLiDANC23mWrTsUgect/7"
+ "62TYg8g1bKwLAb9wCBT+BiOuCc2wrArRLOJgUkj/F4/gtrR9ima34SvWUyoUaKA0"
+ "bi4YBX9l8oJwFGHbU9uFGEMnH0T/V0KtIB7qetReywkCgYEA9cFyfBIQrYISV/OA"
+ "+Z0bo3vh2aL0QgKrSXZ924cLt7itQAHNZ2ya+e3JRlTczi5mnWfjPWZ6eJB/8MlH"
+ "Gpn12o/POEkU+XjZZSPe1RWGt5g0S3lWqyx9toCS9ACXcN9tGbaqcFSVI73zVTRA"
+ "8J9grR0fbGn7jaTlTX2tnlOTQ60CgYEA5YjYpEq4L8UUMFkuj+BsS3u0oEBnzuHd"
+ "I9LEHmN+CMPosvabQu5wkJXLuqo2TxRnAznsA8R3pCLkdPGoWMCiWRAsCn979TdY"
+ "QbqO2qvBAD2Q19GtY7lIu6C35/enQWzJUMQE3WW0OvjLzZ0l/9mA2FBRR+3F9A1d"
+ "rBdnmv0c3TcCgYEAi2i+ggVZcqPbtgrLOk5WVGo9F1GqUBvlgNn30WWNTx4zIaEk"
+ "HSxtyaOLTxtq2odV7Kr3LGiKxwPpn/T+Ief+oIp92YcTn+VfJVGw4Z3BezqbR8lA"
+ "Uf/+HF5ZfpMrVXtZD4Igs3I33Duv4sCuqhEvLWTc44pHifVloozNxYfRfU0CgYBN"
+ "HXa7a6cJ1Yp829l62QlJKtx6Ymj95oAnQu5Ez2ROiZMqXRO4nucOjGUP55Orac1a"
+ "FiGm+mC/skFS0MWgW8evaHGDbWU180wheQ35hW6oKAb7myRHtr4q20ouEtQMdQIF"
+ "snV39G1iyqeeAsf7dxWElydXpRi2b68i3BIgzhzebQKBgQCdUQuTsqV9y/JFpu6H"
+ "c5TVvhG/ubfBspI5DhQqIGijnVBzFT//UfIYMSKJo75qqBEyP2EJSmCsunWsAFsM"
+ "TszuiGTkrKcZy9G0wJqPztZZl2F2+bJgnA6nBEV7g5PA4Af+QSmaIhRwqGDAuROR"
+ "47jndeyIaMTNETEmOnms+as17g==";
// @formatter:on
public static final RSAPrivateKey DEFAULT_PRIVATE_KEY;
static {
PKCS8EncodedKeySpec spec = new PKCS8EncodedKeySpec(Base64.getDecoder().decode(DEFAULT_RSA_PRIVATE_KEY));
try {
DEFAULT_PRIVATE_KEY = (RSAPrivateKey) kf.generatePrivate(spec);
}
catch (InvalidKeySpecException ex) {
throw new IllegalArgumentException(ex);
}
}
public static final KeyPair DEFAULT_RSA_KEY_PAIR = new KeyPair(DEFAULT_PUBLIC_KEY, DEFAULT_PRIVATE_KEY);
public static final KeyPair DEFAULT_EC_KEY_PAIR = generateEcKeyPair();
static KeyPair generateEcKeyPair() {
EllipticCurve ellipticCurve = new EllipticCurve(
new ECFieldFp(new BigInteger(
"115792089210356248762697446949407573530086143415290314195533631308867097853951")),
new BigInteger("115792089210356248762697446949407573530086143415290314195533631308867097853948"),
new BigInteger("41058363725152142129326129780047268409114441015993725554835256314039467401291"));
ECPoint ecPoint = new ECPoint(
new BigInteger("48439561293906451759052585252797914202762949526041747995844080717082404635286"),
new BigInteger("36134250956749795798585127919587881956611106672985015071877198253568414405109"));
ECParameterSpec ecParameterSpec = new ECParameterSpec(ellipticCurve, ecPoint,
new BigInteger("115792089210356248762697446949407573529996955224135760342422259061068512044369"), 1);
KeyPair keyPair;
try {
KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("EC");
keyPairGenerator.initialize(ecParameterSpec);
keyPair = keyPairGenerator.generateKeyPair();
}
catch (Exception ex) {
throw new IllegalStateException(ex);
}
return keyPair;
}
private TestKeys() {
}
}

View File

@@ -1,177 +0,0 @@
/*
* Copyright 2020 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.security.oauth2.jose.jws;
import org.junit.Before;
import org.junit.Test;
import org.springframework.security.crypto.key.AsymmetricKey;
import org.springframework.security.crypto.key.CryptoKeySource;
import org.springframework.security.crypto.key.TestCryptoKeys;
import org.springframework.security.oauth2.jose.JoseHeader;
import org.springframework.security.oauth2.jose.JoseHeaderNames;
import org.springframework.security.oauth2.jose.TestJoseHeaders;
import org.springframework.security.oauth2.jwt.Jwt;
import org.springframework.security.oauth2.jwt.JwtClaimsSet;
import org.springframework.security.oauth2.jwt.JwtEncodingException;
import org.springframework.security.oauth2.jwt.NimbusJwtDecoder;
import org.springframework.security.oauth2.jwt.TestJwtClaimsSets;
import java.security.interfaces.RSAPublicKey;
import java.util.Collections;
import java.util.LinkedHashSet;
import java.util.function.BiConsumer;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import static org.assertj.core.api.Assertions.assertThatThrownBy;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
/**
* Tests for {@link NimbusJwsEncoder}.
*
* @author Joe Grandja
*/
public class NimbusJwsEncoderTests {
private CryptoKeySource keySource;
private NimbusJwsEncoder jwtEncoder;
@Before
public void setUp() {
this.keySource = mock(CryptoKeySource.class);
this.jwtEncoder = new NimbusJwsEncoder(this.keySource);
}
@Test
public void constructorWhenKeySourceNullThenThrowIllegalArgumentException() {
assertThatThrownBy(() -> new NimbusJwsEncoder(null))
.isInstanceOf(IllegalArgumentException.class)
.hasMessage("keySource cannot be null");
}
@Test
public void setJwtCustomizerWhenNullThenThrowIllegalArgumentException() {
assertThatThrownBy(() -> this.jwtEncoder.setJwtCustomizer(null))
.isInstanceOf(IllegalArgumentException.class)
.hasMessage("jwtCustomizer cannot be null");
}
@Test
public void encodeWhenHeadersNullThenThrowIllegalArgumentException() {
JwtClaimsSet jwtClaimsSet = TestJwtClaimsSets.jwtClaimsSet().build();
assertThatThrownBy(() -> this.jwtEncoder.encode(null, jwtClaimsSet))
.isInstanceOf(IllegalArgumentException.class)
.hasMessage("headers cannot be null");
}
@Test
public void encodeWhenClaimsNullThenThrowIllegalArgumentException() {
JoseHeader joseHeader = TestJoseHeaders.joseHeader().build();
assertThatThrownBy(() -> this.jwtEncoder.encode(joseHeader, null))
.isInstanceOf(IllegalArgumentException.class)
.hasMessage("claims cannot be null");
}
@Test
public void encodeWhenUnsupportedKeyThenThrowJwtEncodingException() {
JoseHeader joseHeader = TestJoseHeaders.joseHeader().build();
JwtClaimsSet jwtClaimsSet = TestJwtClaimsSets.jwtClaimsSet().build();
assertThatThrownBy(() -> this.jwtEncoder.encode(joseHeader, jwtClaimsSet))
.isInstanceOf(JwtEncodingException.class)
.hasMessageContaining("Unsupported key for algorithm 'RS256'");
}
@Test
public void encodeWhenUnsupportedKeyAlgorithmThenThrowJwtEncodingException() {
JoseHeader joseHeader = TestJoseHeaders.joseHeader(SignatureAlgorithm.ES256).build();
JwtClaimsSet jwtClaimsSet = TestJwtClaimsSets.jwtClaimsSet().build();
assertThatThrownBy(() -> this.jwtEncoder.encode(joseHeader, jwtClaimsSet))
.isInstanceOf(JwtEncodingException.class)
.hasMessageContaining("Unsupported key for algorithm 'ES256'");
}
@Test
public void encodeWhenUnsupportedKeyTypeThenThrowJwtEncodingException() {
AsymmetricKey ecKey = TestCryptoKeys.ecKey().build();
when(this.keySource.getKeys()).thenReturn(Collections.singleton(ecKey));
JoseHeader joseHeader = TestJoseHeaders.joseHeader(SignatureAlgorithm.ES256).build();
JwtClaimsSet jwtClaimsSet = TestJwtClaimsSets.jwtClaimsSet().build();
assertThatThrownBy(() -> this.jwtEncoder.encode(joseHeader, jwtClaimsSet))
.isInstanceOf(JwtEncodingException.class)
.hasMessageContaining("Unsupported key type 'EC'");
}
@Test
public void encodeWhenSuccessThenDecodes() {
AsymmetricKey rsaKey = TestCryptoKeys.rsaKey().build();
when(this.keySource.getKeys()).thenReturn(Collections.singleton(rsaKey));
JoseHeader joseHeader = TestJoseHeaders.joseHeader()
.headers(headers -> headers.remove(JoseHeaderNames.CRIT))
.build();
JwtClaimsSet jwtClaimsSet = TestJwtClaimsSets.jwtClaimsSet().build();
Jwt jws = this.jwtEncoder.encode(joseHeader, jwtClaimsSet);
NimbusJwtDecoder jwtDecoder = NimbusJwtDecoder.withPublicKey((RSAPublicKey) rsaKey.getPublicKey()).build();
jwtDecoder.decode(jws.getTokenValue());
}
@Test
public void encodeWhenCustomizerSetThenCalled() {
AsymmetricKey rsaKey = TestCryptoKeys.rsaKey().build();
when(this.keySource.getKeys()).thenReturn(Collections.singleton(rsaKey));
JoseHeader joseHeader = TestJoseHeaders.joseHeader()
.headers(headers -> headers.remove(JoseHeaderNames.CRIT))
.build();
JwtClaimsSet jwtClaimsSet = TestJwtClaimsSets.jwtClaimsSet().build();
BiConsumer<JoseHeader.Builder, JwtClaimsSet.Builder> jwtCustomizer = mock(BiConsumer.class);
this.jwtEncoder.setJwtCustomizer(jwtCustomizer);
this.jwtEncoder.encode(joseHeader, jwtClaimsSet);
verify(jwtCustomizer).accept(any(JoseHeader.Builder.class), any(JwtClaimsSet.Builder.class));
}
@Test
public void encodeWhenMultipleActiveKeysThenUseFirst() {
AsymmetricKey rsaKey1 = TestCryptoKeys.rsaKey().build();
AsymmetricKey rsaKey2 = TestCryptoKeys.rsaKey().build();
when(this.keySource.getKeys()).thenReturn(
Stream.of(rsaKey1, rsaKey2)
.collect(Collectors.toCollection(LinkedHashSet::new)));
JoseHeader joseHeader = TestJoseHeaders.joseHeader()
.headers(headers -> headers.remove(JoseHeaderNames.CRIT))
.build();
JwtClaimsSet jwtClaimsSet = TestJwtClaimsSets.jwtClaimsSet().build();
Jwt jws = this.jwtEncoder.encode(joseHeader, jwtClaimsSet);
NimbusJwtDecoder jwtDecoder = NimbusJwtDecoder.withPublicKey((RSAPublicKey) rsaKey1.getPublicKey()).build();
jwtDecoder.decode(jws.getTokenValue());
}
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2020 the original author or authors.
* Copyright 2020-2021 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -13,9 +13,10 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.security.oauth2.jose;
package org.springframework.security.oauth2.jwt;
import org.junit.Test;
import org.springframework.security.oauth2.jose.jws.SignatureAlgorithm;
import static org.assertj.core.api.Assertions.assertThat;
@@ -40,14 +41,13 @@ public class JoseHeaderTests {
JoseHeader expectedJoseHeader = TestJoseHeaders.joseHeader().build();
JoseHeader joseHeader = JoseHeader.withAlgorithm(expectedJoseHeader.getJwsAlgorithm())
.jwkSetUri(expectedJoseHeader.getJwkSetUri())
.jwkSetUri(expectedJoseHeader.getJwkSetUri().toExternalForm())
.jwk(expectedJoseHeader.getJwk())
.keyId(expectedJoseHeader.getKeyId())
.x509Uri(expectedJoseHeader.getX509Uri())
.x509Uri(expectedJoseHeader.getX509Uri().toExternalForm())
.x509CertificateChain(expectedJoseHeader.getX509CertificateChain())
.x509SHA1Thumbprint(expectedJoseHeader.getX509SHA1Thumbprint())
.x509SHA256Thumbprint(expectedJoseHeader.getX509SHA256Thumbprint())
.critical(expectedJoseHeader.getCritical())
.type(expectedJoseHeader.getType())
.contentType(expectedJoseHeader.getContentType())
.headers(headers -> headers.put("custom-header-name", "custom-header-value"))

View File

@@ -0,0 +1,291 @@
/*
* Copyright 2020-2021 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.security.oauth2.jwt;
import java.security.interfaces.ECPrivateKey;
import java.security.interfaces.ECPublicKey;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.function.BiConsumer;
import com.nimbusds.jose.KeySourceException;
import com.nimbusds.jose.jwk.ECKey;
import com.nimbusds.jose.jwk.JWK;
import com.nimbusds.jose.jwk.JWKSelector;
import com.nimbusds.jose.jwk.JWKSet;
import com.nimbusds.jose.jwk.KeyUse;
import com.nimbusds.jose.jwk.OctetSequenceKey;
import com.nimbusds.jose.jwk.RSAKey;
import com.nimbusds.jose.jwk.source.JWKSource;
import com.nimbusds.jose.proc.SecurityContext;
import org.junit.Before;
import org.junit.Test;
import org.mockito.invocation.InvocationOnMock;
import org.mockito.stubbing.Answer;
import org.springframework.security.oauth2.jose.TestJwks;
import org.springframework.security.oauth2.jose.TestKeys;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.BDDMockito.given;
import static org.mockito.BDDMockito.willAnswer;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.verify;
/**
* Tests for {@link NimbusJwsEncoder}.
*
* @author Joe Grandja
*/
public class NimbusJwsEncoderTests {
private JWKSource<SecurityContext> jwkSource;
private NimbusJwsEncoder jwsEncoder;
@Before
public void setUp() {
this.jwkSource = mock(JWKSource.class);
this.jwsEncoder = new NimbusJwsEncoder(this.jwkSource);
}
@Test
public void constructorWhenJwkSourceNullThenThrowIllegalArgumentException() {
assertThatIllegalArgumentException().isThrownBy(() -> new NimbusJwsEncoder(null))
.withMessage("jwkSource cannot be null");
}
@Test
public void setJwtCustomizerWhenNullThenThrowIllegalArgumentException() {
assertThatIllegalArgumentException().isThrownBy(() -> this.jwsEncoder.setJwtCustomizer(null))
.withMessage("jwtCustomizer cannot be null");
}
@Test
public void encodeWhenHeadersNullThenThrowIllegalArgumentException() {
JwtClaimsSet jwtClaimsSet = TestJwtClaimsSets.jwtClaimsSet().build();
assertThatIllegalArgumentException().isThrownBy(() -> this.jwsEncoder.encode(null, jwtClaimsSet))
.withMessage("headers cannot be null");
}
@Test
public void encodeWhenClaimsNullThenThrowIllegalArgumentException() {
JoseHeader joseHeader = TestJoseHeaders.joseHeader().build();
assertThatIllegalArgumentException().isThrownBy(() -> this.jwsEncoder.encode(joseHeader, null))
.withMessage("claims cannot be null");
}
@Test
public void encodeWhenCustomizerSetThenCalled() throws Exception {
RSAKey rsaJwk = TestJwks.DEFAULT_RSA_JWK;
given(this.jwkSource.get(any(), any())).willReturn(Collections.singletonList(rsaJwk));
BiConsumer<JoseHeader.Builder, JwtClaimsSet.Builder> jwtCustomizer = mock(BiConsumer.class);
this.jwsEncoder.setJwtCustomizer(jwtCustomizer);
JoseHeader joseHeader = TestJoseHeaders.joseHeader().build();
JwtClaimsSet jwtClaimsSet = TestJwtClaimsSets.jwtClaimsSet().build();
this.jwsEncoder.encode(joseHeader, jwtClaimsSet);
verify(jwtCustomizer).accept(any(JoseHeader.Builder.class), any(JwtClaimsSet.Builder.class));
}
@Test
public void encodeWhenJwkSelectFailedThenThrowJwtEncodingException() throws Exception {
given(this.jwkSource.get(any(), any())).willThrow(new KeySourceException("key source error"));
JoseHeader joseHeader = TestJoseHeaders.joseHeader().build();
JwtClaimsSet jwtClaimsSet = TestJwtClaimsSets.jwtClaimsSet().build();
assertThatExceptionOfType(JwtEncodingException.class)
.isThrownBy(() -> this.jwsEncoder.encode(joseHeader, jwtClaimsSet))
.withMessageContaining("Failed to select a JWK signing key -> key source error");
}
@Test
public void encodeWhenJwkMultipleSelectedThenThrowJwtEncodingException() throws Exception {
RSAKey rsaJwk = TestJwks.DEFAULT_RSA_JWK;
given(this.jwkSource.get(any(), any())).willReturn(Arrays.asList(rsaJwk, rsaJwk));
JoseHeader joseHeader = TestJoseHeaders.joseHeader().build();
JwtClaimsSet jwtClaimsSet = TestJwtClaimsSets.jwtClaimsSet().build();
assertThatExceptionOfType(JwtEncodingException.class)
.isThrownBy(() -> this.jwsEncoder.encode(joseHeader, jwtClaimsSet))
.withMessageContaining("Found multiple JWK signing keys for algorithm 'RS256'");
}
@Test
public void encodeWhenJwkSelectEmptyThenThrowJwtEncodingException() {
JoseHeader joseHeader = TestJoseHeaders.joseHeader().build();
JwtClaimsSet jwtClaimsSet = TestJwtClaimsSets.jwtClaimsSet().build();
assertThatExceptionOfType(JwtEncodingException.class)
.isThrownBy(() -> this.jwsEncoder.encode(joseHeader, jwtClaimsSet))
.withMessageContaining("Failed to select a JWK signing key");
}
@Test
public void encodeWhenJwkKidNullThenThrowJwtEncodingException() throws Exception {
// @formatter:off
RSAKey rsaJwk = TestJwks.jwk(TestKeys.DEFAULT_PUBLIC_KEY, TestKeys.DEFAULT_PRIVATE_KEY)
.keyID(null)
.build();
// @formatter:on
given(this.jwkSource.get(any(), any())).willReturn(Collections.singletonList(rsaJwk));
JoseHeader joseHeader = TestJoseHeaders.joseHeader().build();
JwtClaimsSet jwtClaimsSet = TestJwtClaimsSets.jwtClaimsSet().build();
assertThatExceptionOfType(JwtEncodingException.class)
.isThrownBy(() -> this.jwsEncoder.encode(joseHeader, jwtClaimsSet))
.withMessageContaining("The \"kid\" (key ID) from the selected JWK cannot be empty");
}
@Test
public void encodeWhenJwkUseEncryptionThenThrowJwtEncodingException() throws Exception {
// @formatter:off
RSAKey rsaJwk = TestJwks.jwk(TestKeys.DEFAULT_PUBLIC_KEY, TestKeys.DEFAULT_PRIVATE_KEY)
.keyUse(KeyUse.ENCRYPTION)
.build();
// @formatter:on
given(this.jwkSource.get(any(), any())).willReturn(Collections.singletonList(rsaJwk));
JoseHeader joseHeader = TestJoseHeaders.joseHeader().build();
JwtClaimsSet jwtClaimsSet = TestJwtClaimsSets.jwtClaimsSet().build();
assertThatExceptionOfType(JwtEncodingException.class)
.isThrownBy(() -> this.jwsEncoder.encode(joseHeader, jwtClaimsSet)).withMessageContaining(
"Failed to create a JWS Signer -> The JWK use must be sig (signature) or unspecified");
}
@Test
public void encodeWhenSuccessThenDecodes() throws Exception {
RSAKey rsaJwk = TestJwks.DEFAULT_RSA_JWK;
given(this.jwkSource.get(any(), any())).willReturn(Collections.singletonList(rsaJwk));
JoseHeader joseHeader = TestJoseHeaders.joseHeader().build();
JwtClaimsSet jwtClaimsSet = TestJwtClaimsSets.jwtClaimsSet().build();
Jwt encodedJws = this.jwsEncoder.encode(joseHeader, jwtClaimsSet);
// Assert headers/claims were added
assertThat(encodedJws.getHeaders().get(JoseHeaderNames.TYP)).isEqualTo("JWT");
assertThat(encodedJws.getHeaders().get(JoseHeaderNames.KID)).isEqualTo(rsaJwk.getKeyID());
assertThat(encodedJws.getId()).isNotNull();
NimbusJwtDecoder jwtDecoder = NimbusJwtDecoder.withPublicKey(rsaJwk.toRSAPublicKey()).build();
jwtDecoder.decode(encodedJws.getTokenValue());
}
@Test
public void encodeWhenKeysRotatedThenNewKeyUsed() throws Exception {
TestJWKSource jwkSource = new TestJWKSource();
JWKSource<SecurityContext> jwkSourceDelegate = spy(new JWKSource<SecurityContext>() {
@Override
public List<JWK> get(JWKSelector jwkSelector, SecurityContext context) {
return jwkSource.get(jwkSelector, context);
}
});
NimbusJwsEncoder jwsEncoder = new NimbusJwsEncoder(jwkSourceDelegate);
JwkListResultCaptor jwkListResultCaptor = new JwkListResultCaptor();
willAnswer(jwkListResultCaptor).given(jwkSourceDelegate).get(any(), any());
JoseHeader joseHeader = TestJoseHeaders.joseHeader().build();
JwtClaimsSet jwtClaimsSet = TestJwtClaimsSets.jwtClaimsSet().build();
Jwt encodedJws = jwsEncoder.encode(joseHeader, jwtClaimsSet);
JWK jwk1 = jwkListResultCaptor.getResult().get(0);
NimbusJwtDecoder jwtDecoder = NimbusJwtDecoder.withPublicKey(((RSAKey) jwk1).toRSAPublicKey()).build();
jwtDecoder.decode(encodedJws.getTokenValue());
jwkSource.rotate(); // Trigger key rotation
encodedJws = jwsEncoder.encode(joseHeader, jwtClaimsSet);
JWK jwk2 = jwkListResultCaptor.getResult().get(0);
jwtDecoder = NimbusJwtDecoder.withPublicKey(((RSAKey) jwk2).toRSAPublicKey()).build();
jwtDecoder.decode(encodedJws.getTokenValue());
assertThat(jwk1.getKeyID()).isNotEqualTo(jwk2.getKeyID());
}
private static final class JwkListResultCaptor implements Answer<List<JWK>> {
private List<JWK> result;
private List<JWK> getResult() {
return this.result;
}
@SuppressWarnings("unchecked")
@Override
public List<JWK> answer(InvocationOnMock invocationOnMock) throws Throwable {
this.result = (List<JWK>) invocationOnMock.callRealMethod();
return this.result;
}
}
private static final class TestJWKSource implements JWKSource<SecurityContext> {
private int keyId = 1000;
private JWKSet jwkSet;
private TestJWKSource() {
init();
}
@Override
public List<JWK> get(JWKSelector jwkSelector, SecurityContext context) {
return jwkSelector.select(this.jwkSet);
}
private void init() {
// @formatter:off
RSAKey rsaJwk = TestJwks.jwk(TestKeys.DEFAULT_PUBLIC_KEY, TestKeys.DEFAULT_PRIVATE_KEY)
.keyID("rsa-jwk-" + this.keyId++)
.build();
ECKey ecJwk = TestJwks.jwk((ECPublicKey) TestKeys.DEFAULT_EC_KEY_PAIR.getPublic(), (ECPrivateKey) TestKeys.DEFAULT_EC_KEY_PAIR.getPrivate())
.keyID("ec-jwk-" + this.keyId++)
.build();
OctetSequenceKey secretJwk = TestJwks.jwk(TestKeys.DEFAULT_SECRET_KEY)
.keyID("secret-jwk-" + this.keyId++)
.build();
// @formatter:on
this.jwkSet = new JWKSet(Arrays.asList(rsaJwk, ecJwk, secretJwk));
}
private void rotate() {
init();
}
}
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2020 the original author or authors.
* Copyright 2020-2021 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -13,38 +13,40 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.security.oauth2.jose;
import org.springframework.security.oauth2.jose.jws.SignatureAlgorithm;
package org.springframework.security.oauth2.jwt;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import java.util.UUID;
import org.springframework.security.oauth2.jose.jws.SignatureAlgorithm;
/**
* @author Joe Grandja
*/
public class TestJoseHeaders {
public final class TestJoseHeaders {
private TestJoseHeaders() {
}
public static JoseHeader.Builder joseHeader() {
return joseHeader(SignatureAlgorithm.RS256);
}
public static JoseHeader.Builder joseHeader(SignatureAlgorithm signatureAlgorithm) {
// @formatter:off
return JoseHeader.withAlgorithm(signatureAlgorithm)
.jwkSetUri("https://provider.com/oauth2/jwks")
.jwk(rsaJwk())
.keyId(UUID.randomUUID().toString())
.keyId("keyId")
.x509Uri("https://provider.com/oauth2/x509")
.x509CertificateChain(Arrays.asList("x509Cert1", "x509Cert2"))
.x509SHA1Thumbprint("x509SHA1Thumbprint")
.x509SHA256Thumbprint("x509SHA256Thumbprint")
.critical(Collections.singleton("custom-header-name"))
.type("JWT")
.contentType("jwt-content-type")
.header("custom-header-name", "custom-header-value");
// @formatter:on
}
private static Map<String, Object> rsaJwk() {

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2020 the original author or authors.
* Copyright 2020-2021 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -18,18 +18,21 @@ package org.springframework.security.oauth2.jwt;
import java.time.Instant;
import java.time.temporal.ChronoUnit;
import java.util.Collections;
import java.util.UUID;
/**
* @author Joe Grandja
*/
public class TestJwtClaimsSets {
public final class TestJwtClaimsSets {
private TestJwtClaimsSets() {
}
public static JwtClaimsSet.Builder jwtClaimsSet() {
String issuer = "https://provider.com";
Instant issuedAt = Instant.now();
Instant expiresAt = issuedAt.plus(1, ChronoUnit.HOURS);
// @formatter:off
return JwtClaimsSet.builder()
.issuer(issuer)
.subject("subject")
@@ -37,7 +40,8 @@ public class TestJwtClaimsSets {
.issuedAt(issuedAt)
.notBefore(issuedAt)
.expiresAt(expiresAt)
.id(UUID.randomUUID().toString())
.id("jti")
.claim("custom-claim-name", "custom-claim-value");
// @formatter:on
}
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2020 the original author or authors.
* Copyright 2020-2021 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -28,7 +28,7 @@ import org.springframework.security.oauth2.core.endpoint.OAuth2ParameterNames;
import org.springframework.security.oauth2.core.oidc.OidcIdToken;
import org.springframework.security.oauth2.core.oidc.OidcScopes;
import org.springframework.security.oauth2.core.oidc.endpoint.OidcParameterNames;
import org.springframework.security.oauth2.jose.JoseHeaderNames;
import org.springframework.security.oauth2.jwt.JoseHeaderNames;
import org.springframework.security.oauth2.jose.jws.SignatureAlgorithm;
import org.springframework.security.oauth2.jwt.Jwt;
import org.springframework.security.oauth2.jwt.JwtClaimsSet;

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2020 the original author or authors.
* Copyright 2020-2021 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -23,7 +23,7 @@ import org.springframework.security.oauth2.core.AuthorizationGrantType;
import org.springframework.security.oauth2.core.ClientAuthenticationMethod;
import org.springframework.security.oauth2.core.OAuth2AuthenticationException;
import org.springframework.security.oauth2.core.OAuth2ErrorCodes;
import org.springframework.security.oauth2.jose.JoseHeaderNames;
import org.springframework.security.oauth2.jwt.JoseHeaderNames;
import org.springframework.security.oauth2.jose.jws.SignatureAlgorithm;
import org.springframework.security.oauth2.jwt.Jwt;
import org.springframework.security.oauth2.jwt.JwtEncoder;

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2020 the original author or authors.
* Copyright 2020-2021 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -25,7 +25,7 @@ import org.springframework.security.oauth2.core.OAuth2AuthenticationException;
import org.springframework.security.oauth2.core.OAuth2ErrorCodes;
import org.springframework.security.oauth2.core.OAuth2RefreshToken;
import org.springframework.security.oauth2.core.OAuth2RefreshToken2;
import org.springframework.security.oauth2.jose.JoseHeaderNames;
import org.springframework.security.oauth2.jwt.JoseHeaderNames;
import org.springframework.security.oauth2.jose.jws.SignatureAlgorithm;
import org.springframework.security.oauth2.jwt.Jwt;
import org.springframework.security.oauth2.jwt.JwtEncoder;

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2020 the original author or authors.
* Copyright 2020-2021 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -15,62 +15,61 @@
*/
package org.springframework.security.oauth2.server.authorization.web;
import com.nimbusds.jose.JWSAlgorithm;
import com.nimbusds.jose.jwk.ECKey;
import com.nimbusds.jose.jwk.JWKSet;
import com.nimbusds.jose.jwk.KeyUse;
import com.nimbusds.jose.jwk.RSAKey;
import org.junit.Before;
import org.junit.Test;
import org.springframework.http.MediaType;
import org.springframework.mock.web.MockHttpServletRequest;
import org.springframework.mock.web.MockHttpServletResponse;
import org.springframework.security.crypto.key.AsymmetricKey;
import org.springframework.security.crypto.key.CryptoKeySource;
import org.springframework.security.crypto.key.SymmetricKey;
import org.springframework.security.crypto.key.TestCryptoKeys;
import java.util.Arrays;
import java.util.Collections;
import javax.servlet.FilterChain;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.Collections;
import java.util.HashSet;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import com.nimbusds.jose.jwk.ECKey;
import com.nimbusds.jose.jwk.JWKSet;
import com.nimbusds.jose.jwk.KeyUse;
import com.nimbusds.jose.jwk.OctetSequenceKey;
import com.nimbusds.jose.jwk.RSAKey;
import com.nimbusds.jose.jwk.source.JWKSource;
import com.nimbusds.jose.proc.SecurityContext;
import org.junit.Before;
import org.junit.Test;
import org.springframework.http.MediaType;
import org.springframework.mock.web.MockHttpServletRequest;
import org.springframework.mock.web.MockHttpServletResponse;
import org.springframework.security.oauth2.jose.TestJwks;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatThrownBy;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.BDDMockito.given;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.verifyNoInteractions;
import static org.mockito.Mockito.when;
/**
* Tests for {@link JwkSetEndpointFilter}.
* Tests for {@link NimbusJwkSetEndpointFilter}.
*
* @author Joe Grandja
*/
public class JwkSetEndpointFilterTests {
private CryptoKeySource keySource;
private JwkSetEndpointFilter filter;
public class NimbusJwkSetEndpointFilterTests {
private JWKSource<SecurityContext> jwkSource;
private NimbusJwkSetEndpointFilter filter;
@Before
public void setUp() {
this.keySource = mock(CryptoKeySource.class);
this.filter = new JwkSetEndpointFilter(this.keySource);
this.jwkSource = mock(JWKSource.class);
this.filter = new NimbusJwkSetEndpointFilter(this.jwkSource);
}
@Test
public void constructorWhenKeySourceNullThenThrowIllegalArgumentException() {
assertThatThrownBy(() -> new JwkSetEndpointFilter(null))
public void constructorWhenJwkSourceNullThenThrowIllegalArgumentException() {
assertThatThrownBy(() -> new NimbusJwkSetEndpointFilter(null))
.isInstanceOf(IllegalArgumentException.class)
.hasMessage("keySource cannot be null");
.hasMessage("jwkSource cannot be null");
}
@Test
public void constructorWhenJwkSetEndpointUriNullThenThrowIllegalArgumentException() {
assertThatThrownBy(() -> new JwkSetEndpointFilter(this.keySource, null))
assertThatThrownBy(() -> new NimbusJwkSetEndpointFilter(this.jwkSource, null))
.isInstanceOf(IllegalArgumentException.class)
.hasMessage("jwkSetEndpointUri cannot be empty");
}
@@ -90,7 +89,7 @@ public class JwkSetEndpointFilterTests {
@Test
public void doFilterWhenJwkSetRequestPostThenNotProcessed() throws Exception {
String requestUri = JwkSetEndpointFilter.DEFAULT_JWK_SET_ENDPOINT_URI;
String requestUri = NimbusJwkSetEndpointFilter.DEFAULT_JWK_SET_ENDPOINT_URI;
MockHttpServletRequest request = new MockHttpServletRequest("POST", requestUri);
request.setServletPath(requestUri);
MockHttpServletResponse response = new MockHttpServletResponse();
@@ -103,12 +102,11 @@ public class JwkSetEndpointFilterTests {
@Test
public void doFilterWhenAsymmetricKeysThenJwkSetResponse() throws Exception {
AsymmetricKey rsaKey = TestCryptoKeys.rsaKey().build();
AsymmetricKey ecKey = TestCryptoKeys.ecKey().build();
when(this.keySource.getKeys()).thenReturn(
Stream.of(rsaKey, ecKey).collect(Collectors.toSet()));
RSAKey rsaJwk = TestJwks.DEFAULT_RSA_JWK;
ECKey ecJwk = TestJwks.DEFAULT_EC_JWK;
given(this.jwkSource.get(any(), any())).willReturn(Arrays.asList(rsaJwk, ecJwk));
String requestUri = JwkSetEndpointFilter.DEFAULT_JWK_SET_ENDPOINT_URI;
String requestUri = NimbusJwkSetEndpointFilter.DEFAULT_JWK_SET_ENDPOINT_URI;
MockHttpServletRequest request = new MockHttpServletRequest("GET", requestUri);
request.setServletPath(requestUri);
MockHttpServletResponse response = new MockHttpServletResponse();
@@ -123,29 +121,25 @@ public class JwkSetEndpointFilterTests {
JWKSet jwkSet = JWKSet.parse(response.getContentAsString());
assertThat(jwkSet.getKeys()).hasSize(2);
RSAKey rsaJwk = (RSAKey) jwkSet.getKeyByKeyId(rsaKey.getId());
assertThat(rsaJwk).isNotNull();
assertThat(rsaJwk.toRSAPublicKey()).isEqualTo(rsaKey.getPublicKey());
assertThat(rsaJwk.toRSAPrivateKey()).isNull();
assertThat(rsaJwk.getKeyUse()).isEqualTo(KeyUse.SIGNATURE);
assertThat(rsaJwk.getAlgorithm()).isEqualTo(JWSAlgorithm.RS256);
RSAKey rsaJwkResult = (RSAKey) jwkSet.getKeyByKeyId(rsaJwk.getKeyID());
assertThat(rsaJwkResult).isNotNull();
assertThat(rsaJwkResult.toRSAPublicKey()).isEqualTo(rsaJwk.toRSAPublicKey());
assertThat(rsaJwkResult.toRSAPrivateKey()).isNull();
assertThat(rsaJwkResult.getKeyUse()).isEqualTo(KeyUse.SIGNATURE);
ECKey ecJwk = (ECKey) jwkSet.getKeyByKeyId(ecKey.getId());
assertThat(ecJwk).isNotNull();
assertThat(ecJwk.toECPublicKey()).isEqualTo(ecKey.getPublicKey());
assertThat(ecJwk.toECPublicKey()).isEqualTo(ecKey.getPublicKey());
assertThat(ecJwk.toECPrivateKey()).isNull();
assertThat(ecJwk.getKeyUse()).isEqualTo(KeyUse.SIGNATURE);
assertThat(ecJwk.getAlgorithm()).isEqualTo(JWSAlgorithm.ES256);
ECKey ecJwkResult = (ECKey) jwkSet.getKeyByKeyId(ecJwk.getKeyID());
assertThat(ecJwkResult).isNotNull();
assertThat(ecJwkResult.toECPublicKey()).isEqualTo(ecJwk.toECPublicKey());
assertThat(ecJwkResult.toECPrivateKey()).isNull();
assertThat(ecJwkResult.getKeyUse()).isEqualTo(KeyUse.SIGNATURE);
}
@Test
public void doFilterWhenSymmetricKeysThenJwkSetResponseEmpty() throws Exception {
SymmetricKey secretKey = TestCryptoKeys.secretKey().build();
when(this.keySource.getKeys()).thenReturn(
new HashSet<>(Collections.singleton(secretKey)));
OctetSequenceKey secretJwk = TestJwks.DEFAULT_SECRET_JWK;
given(this.jwkSource.get(any(), any())).willReturn(Collections.singletonList(secretJwk));
String requestUri = JwkSetEndpointFilter.DEFAULT_JWK_SET_ENDPOINT_URI;
String requestUri = NimbusJwkSetEndpointFilter.DEFAULT_JWK_SET_ENDPOINT_URI;
MockHttpServletRequest request = new MockHttpServletRequest("GET", requestUri);
request.setServletPath(requestUri);
MockHttpServletResponse response = new MockHttpServletResponse();