[java-idp-oidc] branch main updated: JOIDC-38 Refactor fetching of remote JWK sets
Henri Mikkonen
henri.mikkonen at iki.fi
Thu Mar 11 15:46:45 UTC 2021
This is an automated email from the git hooks/post-receive script.
hjmikkon pushed a commit to branch main
in repository java-idp-oidc.
View the commit online:
http://git.shibboleth.net/view/?p=java-idp-oidc.git;a=commit;h=ad5e7707c985e6a30bf4cfb65ae9f2a245ae18e8
The following commit(s) were added to refs/heads/main by this push:
new ad5e7707 JOIDC-38 Refactor fetching of remote JWK sets
ad5e7707 is described below
commit ad5e7707c985e6a30bf4cfb65ae9f2a245ae18e8
Author: Henri Mikkonen <henri.mikkonen at iki.fi>
AuthorDate: Thu Mar 11 17:45:39 2021 +0200
JOIDC-38 Refactor fetching of remote JWK sets
https://issues.shibboleth.net/jira/browse/JOIDC-38
- The client information resolvers no longer fetches keys (via RemoteJwkSetCache)
- OIDCClientInformationEncryptionParametersResolver and OIDCClientInformationSignatureValidationParametersResolver
fetch them instead
- Fetching interval is configurable via idp.oidc.jwksuri.fetchInterval property, defaults to 30 mins
---
...entInformationEncryptionParametersResolver.java | 45 +++++++++-
...ationSignatureValidationParametersResolver.java | 38 +++++++-
.../META-INF/net.shibboleth.idp/postconfig.xml | 6 ++
.../idp/flows/oidc/authorize/authorize-beans.xml | 5 +-
.../idp/flows/oidc/token/token-beans.xml | 4 +-
.../idp/flows/oidc/userinfo/token-beans.xml | 1 +
.../oidc/op/conf/clientinfo-resolver-system.xml | 12 +--
.../idp/plugin/oidc/op/conf/oidc.properties | 3 +
...nformationEncryptionParametersResolverTest.java | 81 ++++++++++++-----
...tionSignatureSigningParametersResolverTest.java | 4 +-
...nSignatureValidationParametersResolverTest.java | 100 +++++++++++++++------
11 files changed, 234 insertions(+), 65 deletions(-)
diff --git a/idp-oidc-extension-impl/src/main/java/net/shibboleth/idp/plugin/oidc/op/security/impl/OIDCClientInformationEncryptionParametersResolver.java b/idp-oidc-extension-impl/src/main/java/net/shibboleth/idp/plugin/oidc/op/security/impl/OIDCClientInformationEncryptionParametersResolver.java
index a216a987..2dac699c 100644
--- a/idp-oidc-extension-impl/src/main/java/net/shibboleth/idp/plugin/oidc/op/security/impl/OIDCClientInformationEncryptionParametersResolver.java
+++ b/idp-oidc-extension-impl/src/main/java/net/shibboleth/idp/plugin/oidc/op/security/impl/OIDCClientInformationEncryptionParametersResolver.java
@@ -21,6 +21,8 @@ import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.security.interfaces.ECPrivateKey;
import java.security.interfaces.RSAPrivateKey;
+import java.time.Duration;
+import java.time.Instant;
import java.util.List;
import java.util.function.Predicate;
@@ -30,8 +32,10 @@ import javax.crypto.SecretKey;
import javax.crypto.spec.SecretKeySpec;
import net.shibboleth.idp.plugin.oidc.op.criterion.ClientInformationCriterion;
+import net.shibboleth.oidc.jwk.RemoteJwkSetCache;
import net.shibboleth.oidc.security.credential.BasicJWKCredential;
import net.shibboleth.oidc.security.impl.OIDCDecryptionParameters;
+import net.shibboleth.utilities.java.support.annotation.constraint.Positive;
import net.shibboleth.utilities.java.support.logic.Constraint;
import net.shibboleth.utilities.java.support.resolver.CriteriaSet;
import net.shibboleth.utilities.java.support.resolver.ResolverException;
@@ -93,6 +97,20 @@ public class OIDCClientInformationEncryptionParametersResolver extends BasicEncr
* Whether to create parameters for request object decryption, id token encryption or userinfo response encryption.
*/
private ParameterType target = ParameterType.IDTOKEN_ENCRYPTION;
+
+ /** The cache for remote JWK key sets. */
+ private RemoteJwkSetCache remoteJwkSetCache;
+
+ /** The remote key refresh interval. Default value: 30 minutes. */
+ @Positive
+ private Duration keyFetchInterval = Duration.ofMinutes(30);
+
+ /**
+ * Constructor.
+ */
+ public OIDCClientInformationEncryptionParametersResolver() {
+ super();
+ }
/**
* Whether to create parameters for request object decryption, id token encryption or userinfo response encryption.
@@ -104,6 +122,25 @@ public class OIDCClientInformationEncryptionParametersResolver extends BasicEncr
target = value;
}
+ /**
+ * Set the cache for remote JWK key sets.
+ *
+ * @param jwkSetCache What to set.
+ */
+ public void setRemoteJwkSetCache(final RemoteJwkSetCache jwkSetCache) {
+ remoteJwkSetCache = Constraint.isNotNull(jwkSetCache, "The remote JWK set cache cannot be null");
+ }
+
+ /**
+ * Set the remote key refresh interval.
+ *
+ * @param interval What to set.
+ */
+ public void setKeyFetchInterval(@Positive final Duration interval) {
+ Constraint.isFalse(interval == null || interval.isNegative(), "Remote key refresh must be greater than 0");
+ keyFetchInterval = interval;
+ }
+
/** {@inheritDoc} */
@Override
@Nullable
@@ -236,7 +273,13 @@ public class OIDCClientInformationEncryptionParametersResolver extends BasicEncr
}
// For RSA & EC based encryption we pick one encryption key from client's registration data
if (target != ParameterType.REQUEST_OBJECT_DECRYPTION) {
- final JWKSet keySet = clientInformation.getOIDCMetadata().getJWKSet();
+ final JWKSet keySet;
+ if (clientInformation.getOIDCMetadata().getJWKSetURI() != null) {
+ keySet = remoteJwkSetCache.fetch(clientInformation.getOIDCMetadata().getJWKSetURI(),
+ Instant.now().plus(keyFetchInterval));
+ } else {
+ keySet = clientInformation.getOIDCMetadata().getJWKSet();
+ }
if (keySet == null) {
log.warn("No keyset available");
super.resolveAndPopulateCredentialsAndAlgorithms(params, criteria, whitelistBlacklistPredicate);
diff --git a/idp-oidc-extension-impl/src/main/java/net/shibboleth/idp/plugin/oidc/op/security/impl/OIDCClientInformationSignatureValidationParametersResolver.java b/idp-oidc-extension-impl/src/main/java/net/shibboleth/idp/plugin/oidc/op/security/impl/OIDCClientInformationSignatureValidationParametersResolver.java
index 346385c5..a7113a12 100644
--- a/idp-oidc-extension-impl/src/main/java/net/shibboleth/idp/plugin/oidc/op/security/impl/OIDCClientInformationSignatureValidationParametersResolver.java
+++ b/idp-oidc-extension-impl/src/main/java/net/shibboleth/idp/plugin/oidc/op/security/impl/OIDCClientInformationSignatureValidationParametersResolver.java
@@ -17,6 +17,8 @@
package net.shibboleth.idp.plugin.oidc.op.security.impl;
+import java.time.Duration;
+import java.time.Instant;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
@@ -27,8 +29,10 @@ import javax.annotation.Nullable;
import javax.crypto.spec.SecretKeySpec;
import net.shibboleth.idp.plugin.oidc.op.criterion.ClientInformationCriterion;
+import net.shibboleth.oidc.jwk.RemoteJwkSetCache;
import net.shibboleth.oidc.security.credential.BasicJWKCredential;
import net.shibboleth.oidc.security.impl.OIDCSignatureValidationParameters;
+import net.shibboleth.utilities.java.support.annotation.constraint.Positive;
import net.shibboleth.utilities.java.support.logic.Constraint;
import net.shibboleth.utilities.java.support.resolver.CriteriaSet;
import net.shibboleth.utilities.java.support.resolver.ResolverException;
@@ -83,6 +87,13 @@ public class OIDCClientInformationSignatureValidationParametersResolver
}
private ParameterType target = ParameterType.REQUEST_OBJECT_VALIDATION;
+
+ /** The cache for remote JWK key sets. */
+ private RemoteJwkSetCache remoteJwkSetCache;
+
+ /** The remote key refresh interval. Default value: 30 minutes. */
+ @Positive
+ private Duration keyFetchInterval = Duration.ofMinutes(30);
/**
* Whether to create parameters for request object signature validation or token endpoint jwt validation.
@@ -94,6 +105,25 @@ public class OIDCClientInformationSignatureValidationParametersResolver
target = value;
}
+ /**
+ * Set the cache for remote JWK key sets.
+ *
+ * @param jwkSetCache What to set.
+ */
+ public void setRemoteJwkSetCache(final RemoteJwkSetCache jwkSetCache) {
+ remoteJwkSetCache = Constraint.isNotNull(jwkSetCache, "The remote JWK set cache cannot be null");
+ }
+
+ /**
+ * Set the remote key refresh interval.
+ *
+ * @param interval What to set.
+ */
+ public void setKeyFetchInterval(@Positive final Duration interval) {
+ Constraint.isFalse(interval == null || interval.isNegative(), "Remote key refresh must be greater than 0");
+ keyFetchInterval = interval;
+ }
+
/** {@inheritDoc} */
@Nullable
public SignatureSigningParameters resolveSingle(@Nonnull final CriteriaSet criteria) throws ResolverException {
@@ -198,7 +228,13 @@ public class OIDCClientInformationSignatureValidationParametersResolver
}
}
// For EC&RSA family signature validation we pick all suitable keys from client's registration data
- final JWKSet keySet = clientInformation.getOIDCMetadata().getJWKSet();
+ final JWKSet keySet;
+ if (clientInformation.getOIDCMetadata().getJWKSetURI() != null) {
+ keySet = remoteJwkSetCache.fetch(clientInformation.getOIDCMetadata().getJWKSetURI(),
+ Instant.now().plus(keyFetchInterval));
+ } else {
+ keySet = clientInformation.getOIDCMetadata().getJWKSet();
+ }
if (keySet == null) {
log.debug("No keyset available");
} else {
diff --git a/idp-oidc-extension-impl/src/main/resources/META-INF/net.shibboleth.idp/postconfig.xml b/idp-oidc-extension-impl/src/main/resources/META-INF/net.shibboleth.idp/postconfig.xml
index 5a28b9b0..5cb34564 100644
--- a/idp-oidc-extension-impl/src/main/resources/META-INF/net.shibboleth.idp/postconfig.xml
+++ b/idp-oidc-extension-impl/src/main/resources/META-INF/net.shibboleth.idp/postconfig.xml
@@ -148,5 +148,11 @@
</list>
</constructor-arg>
</bean>
+
+ <bean id="shibboleth.oidc.RemoteJwkSetCache"
+ class="net.shibboleth.oidc.jwk.RemoteJwkSetCache"
+ p:storage-ref="#{'%{idp.oidc.jwk.StorageService:shibboleth.StorageService}'.trim()}"
+ p:httpClient="#{getObject('shibboleth.oidc.NonBrowser.HttpClient') ?: getObject('shibboleth.InternalHttpClient')}"
+ p:httpClientSecurityParameters="#{getObject('shibboleth.oidc.NonBrowser.HttpClientSecurityParameters')}" />
</beans>
diff --git a/idp-oidc-extension-impl/src/main/resources/META-INF/net/shibboleth/idp/flows/oidc/authorize/authorize-beans.xml b/idp-oidc-extension-impl/src/main/resources/META-INF/net/shibboleth/idp/flows/oidc/authorize/authorize-beans.xml
index 4560c92a..47dedfa8 100644
--- a/idp-oidc-extension-impl/src/main/resources/META-INF/net/shibboleth/idp/flows/oidc/authorize/authorize-beans.xml
+++ b/idp-oidc-extension-impl/src/main/resources/META-INF/net/shibboleth/idp/flows/oidc/authorize/authorize-beans.xml
@@ -61,6 +61,7 @@
<bean id="shibboleth.oidc.EncryptionParametersResolverForRequestObjectDecryption"
class="net.shibboleth.idp.plugin.oidc.op.security.impl.OIDCClientInformationEncryptionParametersResolver"
+ p:remoteJwkSetCache-ref="shibboleth.oidc.RemoteJwkSetCache" p:keyFetchInterval="%{idp.oidc.jwksuri.fetchInterval:PT30M}"
p:parameterType="#{T(net.shibboleth.idp.plugin.oidc.op.security.impl.OIDCClientInformationEncryptionParametersResolver.ParameterType).REQUEST_OBJECT_DECRYPTION}" />
<bean id="shibboleth.oidc.DecryptionConfigurationLookup"
@@ -89,6 +90,7 @@
<bean id="shibboleth.oidc.RequestObjectSignatureValidationParametersResolver"
class="net.shibboleth.idp.plugin.oidc.op.security.impl.OIDCClientInformationSignatureValidationParametersResolver"
+ p:remoteJwkSetCache-ref="shibboleth.oidc.RemoteJwkSetCache" p:keyFetchInterval="%{idp.oidc.jwksuri.fetchInterval:PT30M}"
p:parameterType="#{T(net.shibboleth.idp.plugin.oidc.op.security.impl.OIDCClientInformationSignatureValidationParametersResolver.ParameterType).REQUEST_OBJECT_VALIDATION}" />
<bean id="SetRequestObjectToResponseContext"
@@ -145,7 +147,8 @@
</bean>
<bean id="shibboleth.oidc.EncryptionParametersResolver"
- class="net.shibboleth.idp.plugin.oidc.op.security.impl.OIDCClientInformationEncryptionParametersResolver" />
+ class="net.shibboleth.idp.plugin.oidc.op.security.impl.OIDCClientInformationEncryptionParametersResolver"
+ p:remoteJwkSetCache-ref="shibboleth.oidc.RemoteJwkSetCache" p:keyFetchInterval="%{idp.oidc.jwksuri.fetchInterval:PT30M}" />
<bean id="PopulateClientStorageLoadContext"
class="org.opensaml.storage.impl.client.PopulateClientStorageLoadContext" scope="prototype"
diff --git a/idp-oidc-extension-impl/src/main/resources/META-INF/net/shibboleth/idp/flows/oidc/token/token-beans.xml b/idp-oidc-extension-impl/src/main/resources/META-INF/net/shibboleth/idp/flows/oidc/token/token-beans.xml
index 95daf251..095b56db 100644
--- a/idp-oidc-extension-impl/src/main/resources/META-INF/net/shibboleth/idp/flows/oidc/token/token-beans.xml
+++ b/idp-oidc-extension-impl/src/main/resources/META-INF/net/shibboleth/idp/flows/oidc/token/token-beans.xml
@@ -117,7 +117,8 @@
p:encryptionParametersResolver-ref="shibboleth.oidc.EncryptionParametersResolver" />
<bean id="shibboleth.oidc.EncryptionParametersResolver"
- class="net.shibboleth.idp.plugin.oidc.op.security.impl.OIDCClientInformationEncryptionParametersResolver" />
+ class="net.shibboleth.idp.plugin.oidc.op.security.impl.OIDCClientInformationEncryptionParametersResolver"
+ p:remoteJwkSetCache-ref="shibboleth.oidc.RemoteJwkSetCache" p:keyFetchInterval="%{idp.oidc.jwksuri.fetchInterval:PT30M}" />
<bean id="shibboleth.TokenRequestScopeLookupStrategy"
class="net.shibboleth.idp.plugin.oidc.op.profile.context.navigate.TokenRequestScopeLookupFunction"
@@ -235,6 +236,7 @@
<bean id="shibboleth.oidc.TokenEndpointJwtSignatureValidationParametersResolver"
class="net.shibboleth.idp.plugin.oidc.op.security.impl.OIDCClientInformationSignatureValidationParametersResolver"
+ p:remoteJwkSetCache-ref="shibboleth.oidc.RemoteJwkSetCache" p:keyFetchInterval="%{idp.oidc.jwksuri.fetchInterval:PT30M}"
p:parameterType="#{T(net.shibboleth.idp.plugin.oidc.op.security.impl.OIDCClientInformationSignatureValidationParametersResolver.ParameterType).TOKEN_ENDPOINT_JWT_VALIDATION}" />
</beans>
diff --git a/idp-oidc-extension-impl/src/main/resources/META-INF/net/shibboleth/idp/flows/oidc/userinfo/token-beans.xml b/idp-oidc-extension-impl/src/main/resources/META-INF/net/shibboleth/idp/flows/oidc/userinfo/token-beans.xml
index 8dbfcf6f..004c7265 100644
--- a/idp-oidc-extension-impl/src/main/resources/META-INF/net/shibboleth/idp/flows/oidc/userinfo/token-beans.xml
+++ b/idp-oidc-extension-impl/src/main/resources/META-INF/net/shibboleth/idp/flows/oidc/userinfo/token-beans.xml
@@ -85,6 +85,7 @@
<bean id="shibboleth.oidc.EncryptionParametersResolver"
class="net.shibboleth.idp.plugin.oidc.op.security.impl.OIDCClientInformationEncryptionParametersResolver"
+ p:remoteJwkSetCache-ref="shibboleth.oidc.RemoteJwkSetCache" p:keyFetchInterval="%{idp.oidc.jwksuri.fetchInterval:PT30M}"
p:parameterType="#{T(net.shibboleth.idp.plugin.oidc.op.security.impl.OIDCClientInformationEncryptionParametersResolver.ParameterType).USERINFO_ENCRYPTION}" />
<bean id="shibboleth.TokenRequestRequestedClaimsLookupFunction"
diff --git a/idp-oidc-extension-impl/src/main/resources/net/shibboleth/idp/plugin/oidc/op/conf/clientinfo-resolver-system.xml b/idp-oidc-extension-impl/src/main/resources/net/shibboleth/idp/plugin/oidc/op/conf/clientinfo-resolver-system.xml
index 38d0e194..f035db57 100644
--- a/idp-oidc-extension-impl/src/main/resources/net/shibboleth/idp/plugin/oidc/op/conf/clientinfo-resolver-system.xml
+++ b/idp-oidc-extension-impl/src/main/resources/net/shibboleth/idp/plugin/oidc/op/conf/clientinfo-resolver-system.xml
@@ -18,24 +18,16 @@
p:embeddedResolver-ref="shibboleth.oidc.ChainingClientInformationResolver">
</bean>
- <bean id="shibboleth.oidc.RemoteJwkSetCache"
- class="net.shibboleth.oidc.jwk.RemoteJwkSetCache"
- p:storage-ref="#{'%{idp.oidc.jwk.StorageService:shibboleth.StorageService}'.trim()}"
- p:httpClient="#{getObject('shibboleth.oidc.NonBrowser.HttpClient') ?: getObject('shibboleth.InternalHttpClient')}"
- p:httpClientSecurityParameters="#{getObject('shibboleth.oidc.NonBrowser.HttpClientSecurityParameters')}" />
-
<bean id="shibboleth.oidc.ChainingClientInformationResolver"
class="net.shibboleth.oidc.metadata.impl.ChainingClientInformationResolver"
p:id="InternalEmbeddedChainResolver"
p:resolvers="#{getObject('shibboleth.oidc.ClientInformationResolvers')}"/>
<bean id="shibboleth.oidc.FilesystemClientInformationResolver" abstract="true"
- class="net.shibboleth.oidc.metadata.impl.FilesystemClientInformationResolver"
- p:remoteJwkSetCache-ref="shibboleth.oidc.RemoteJwkSetCache" />
+ class="net.shibboleth.oidc.metadata.impl.FilesystemClientInformationResolver"/>
<bean id="shibboleth.oidc.StorageClientInformationResolver" abstract="true"
- class="net.shibboleth.oidc.metadata.impl.StorageServiceClientInformationResolver"
- p:remoteJwkSetCache-ref="shibboleth.oidc.RemoteJwkSetCache"/>
+ class="net.shibboleth.oidc.metadata.impl.StorageServiceClientInformationResolver"/>
<!-- Wildcard import hook for plugins. -->
<import resource="classpath*:/META-INF/net/shibboleth/idp/plugin/oidc/op/service/clientinfo/postconfig.xml" />
diff --git a/idp-oidc-extension-impl/src/main/resources/net/shibboleth/idp/plugin/oidc/op/conf/oidc.properties b/idp-oidc-extension-impl/src/main/resources/net/shibboleth/idp/plugin/oidc/op/conf/oidc.properties
index cbdd8f32..a7dc49dd 100644
--- a/idp-oidc-extension-impl/src/main/resources/net/shibboleth/idp/plugin/oidc/op/conf/oidc.properties
+++ b/idp-oidc-extension-impl/src/main/resources/net/shibboleth/idp/plugin/oidc/op/conf/oidc.properties
@@ -72,3 +72,6 @@ idp.oidc.subject.salt = this_too_should_be_ch4ng3d
# Bean to determine whether SAML metadata should be exploited for trusted OIDC RP resolution
#idp.oidc.metadata.saml = shibboleth.Conditions.TRUE
+
+# Upgrade interval to the remote JWKs
+#idp.oidc.jwksuri.fetchInterval = PT30M
diff --git a/idp-oidc-extension-impl/src/test/java/net/shibboleth/idp/plugin/oidc/op/security/impl/OIDCClientInformationEncryptionParametersResolverTest.java b/idp-oidc-extension-impl/src/test/java/net/shibboleth/idp/plugin/oidc/op/security/impl/OIDCClientInformationEncryptionParametersResolverTest.java
index 744fbf21..5058b3dc 100644
--- a/idp-oidc-extension-impl/src/test/java/net/shibboleth/idp/plugin/oidc/op/security/impl/OIDCClientInformationEncryptionParametersResolverTest.java
+++ b/idp-oidc-extension-impl/src/test/java/net/shibboleth/idp/plugin/oidc/op/security/impl/OIDCClientInformationEncryptionParametersResolverTest.java
@@ -17,12 +17,15 @@
package net.shibboleth.idp.plugin.oidc.op.security.impl;
+import java.net.URI;
+import java.text.ParseException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Date;
import java.util.List;
import org.mockito.Mockito;
+import org.opensaml.core.testing.OpenSAMLInitBaseTestCase;
import org.opensaml.security.credential.Credential;
import org.opensaml.xmlsec.EncryptionConfiguration;
import org.opensaml.xmlsec.EncryptionParameters;
@@ -34,6 +37,7 @@ import org.testng.annotations.Test;
import com.nimbusds.jose.EncryptionMethod;
import com.nimbusds.jose.JWEAlgorithm;
import com.nimbusds.jose.jwk.JWKSet;
+import com.nimbusds.jose.jwk.RSAKey;
import com.nimbusds.oauth2.sdk.auth.Secret;
import com.nimbusds.oauth2.sdk.id.ClientID;
import com.nimbusds.openid.connect.sdk.rp.OIDCClientInformation;
@@ -41,25 +45,39 @@ import com.nimbusds.openid.connect.sdk.rp.OIDCClientMetadata;
import net.shibboleth.idp.plugin.oidc.op.criterion.ClientInformationCriterion;
import net.shibboleth.idp.plugin.oidc.op.profile.spring.factory.BasicJWKCredentialFactoryBean;
-import net.shibboleth.idp.plugin.oidc.op.security.impl.OIDCClientInformationEncryptionParametersResolver;
import net.shibboleth.idp.plugin.oidc.op.security.impl.OIDCClientInformationEncryptionParametersResolver.ParameterType;
+import net.shibboleth.oidc.jwk.RemoteJwkSetCache;
import net.shibboleth.oidc.security.impl.OIDCDecryptionParameters;
import net.shibboleth.utilities.java.support.resolver.CriteriaSet;
-import net.shibboleth.utilities.java.support.resolver.ResolverException;
/**
* Tests for {@link OIDCClientInformationEncryptionParametersResolver}.
*/
-public class OIDCClientInformationEncryptionParametersResolverTest {
+public class OIDCClientInformationEncryptionParametersResolverTest extends OpenSAMLInitBaseTestCase {
private OIDCClientInformationEncryptionParametersResolver resolver;
private CriteriaSet criteria;
private OIDCClientMetadata metaData;
-
+
+ private JWKSet jwkSet;
+
@BeforeMethod
- protected void setUp() throws Exception {
+ protected void setUp() throws ParseException {
+ jwkSet = JWKSet.parse("{\n" + " \"keys\": [\n" + " {\n" + " \"kty\": \"EC\",\n"
+ + " \"d\": \"MeEUizlBfHEfftMzSUYmtltJr87NUn2WZqxKDVPMlxM\",\n" + " \"crv\": \"P-256\",\n"
+ + " \"x\": \"psUf_1U4lV0u2zSRjVepDMyLV4JeLoWNcz3F3C91z4Y\",\n"
+ + " \"y\": \"z29JaoRl_1wgGPEKq7-5qvts9vbEwA7hk5Vg01h8ESc\"\n" + " },\n" + " {\n"
+ + " \"kty\": \"RSA\",\n"
+ + " \"kid\": \"testRsaKey\",\n"
+ + " \"d\": \"RBl-MjdugxTrjVbbWSeArOV7HUiZPX5LWmyB9p3P1OLSSYjK9A42KYPsdcLpa78Den5_fcpLv-1pm8161ATE9Y_O2aIkeg0_IRlM-FLo-KHvtGkEuHcbERPGhrvmsyMsqkVGADhEwvcGsWZ9PZSHo8OK8EsHZWmE2kHN_rG_8n9-ymAvdsHHv5WhyppHtScLWR1UoIQVbnmcw0cauBy-6SYL2pnweWMeI5UDB6eYyeUyA8BuV-_40K0XqJgJ--6zkNdsSrAMbOejfSyAgK7ezCCP-gmS2P3tBLqwJKjCcoDGFihHj6qLUFNWDY5flp3vA02Z8DQKroeAtIN0_PSBIQ\",\n"
+ + " \"e\": \"AQAB\",\n"
+ + " \"n\": \"xC18p5gfcin62WKas_DlmwUE0ySwmgW51gDQhqucBBSyHMvzRXzRY1cYkox4WCLreC3X8YbNgAv9fjkagX35aNyafnJxEd3Cipf6-h_tZ8Ky5mtdKrxpJdGW1mom7Ha8nMAFGmElDtQny2U8pzDUAUvOcOjiI-JRd6WH3wyQtpCtG6YYxhS9SvnvDaNlYN_afPgFdTHt5yn-q854bjF6uG-uZt3J7jf7P6dvqVizDVO9xtCHrjeet4v62yscMZXYi110aMJdtA4nxKGUi9RWCnBoLVRMBei5ZqmsLCozT5KpfVNkjVzZU3vYBKdGw49pIgRqQP-Jx8Sg7JFaaXMBsQ\"\n"
+ + " }" + " ]\n" + "}");
+ }
+
+ protected void initTest(RemoteJwkSetCache remoteJwkSetCache) throws Exception {
resolver = new OIDCClientInformationEncryptionParametersResolver();
// Encryption configuration
List<EncryptionConfiguration> configs = new ArrayList<EncryptionConfiguration>();
@@ -83,31 +101,52 @@ public class OIDCClientInformationEncryptionParametersResolverTest {
metaData.setUserInfoJWEEnc(EncryptionMethod.A128GCM);
metaData.setRequestObjectJWEAlg(JWEAlgorithm.RSA_OAEP_256);
metaData.setRequestObjectJWEEnc(EncryptionMethod.A192GCM);
- JWKSet jwkSet = JWKSet.parse("{\n" + " \"keys\": [\n" + " {\n" + " \"kty\": \"EC\",\n"
- + " \"d\": \"MeEUizlBfHEfftMzSUYmtltJr87NUn2WZqxKDVPMlxM\",\n" + " \"crv\": \"P-256\",\n"
- + " \"x\": \"psUf_1U4lV0u2zSRjVepDMyLV4JeLoWNcz3F3C91z4Y\",\n"
- + " \"y\": \"z29JaoRl_1wgGPEKq7-5qvts9vbEwA7hk5Vg01h8ESc\"\n" + " },\n" + " {\n"
- + " \"kty\": \"RSA\",\n"
- + " \"d\": \"RBl-MjdugxTrjVbbWSeArOV7HUiZPX5LWmyB9p3P1OLSSYjK9A42KYPsdcLpa78Den5_fcpLv-1pm8161ATE9Y_O2aIkeg0_IRlM-FLo-KHvtGkEuHcbERPGhrvmsyMsqkVGADhEwvcGsWZ9PZSHo8OK8EsHZWmE2kHN_rG_8n9-ymAvdsHHv5WhyppHtScLWR1UoIQVbnmcw0cauBy-6SYL2pnweWMeI5UDB6eYyeUyA8BuV-_40K0XqJgJ--6zkNdsSrAMbOejfSyAgK7ezCCP-gmS2P3tBLqwJKjCcoDGFihHj6qLUFNWDY5flp3vA02Z8DQKroeAtIN0_PSBIQ\",\n"
- + " \"e\": \"AQAB\",\n"
- + " \"n\": \"xC18p5gfcin62WKas_DlmwUE0ySwmgW51gDQhqucBBSyHMvzRXzRY1cYkox4WCLreC3X8YbNgAv9fjkagX35aNyafnJxEd3Cipf6-h_tZ8Ky5mtdKrxpJdGW1mom7Ha8nMAFGmElDtQny2U8pzDUAUvOcOjiI-JRd6WH3wyQtpCtG6YYxhS9SvnvDaNlYN_afPgFdTHt5yn-q854bjF6uG-uZt3J7jf7P6dvqVizDVO9xtCHrjeet4v62yscMZXYi110aMJdtA4nxKGUi9RWCnBoLVRMBei5ZqmsLCozT5KpfVNkjVzZU3vYBKdGw49pIgRqQP-Jx8Sg7JFaaXMBsQ\"\n"
- + " }" + " ]\n" + "}");
- metaData.setJWKSet(jwkSet);
+ if (remoteJwkSetCache != null) {
+ resolver.setRemoteJwkSetCache(remoteJwkSetCache);
+ metaData.setJWKSetURI(new URI("https://rp.example.org/jwks"));
+ } else {
+ metaData.setJWKSet(jwkSet);
+ }
OIDCClientInformation clientInformation =
new OIDCClientInformation(new ClientID(), new Date(), metaData, new Secret("abcdefgh"));
criteria.add(new ClientInformationCriterion(clientInformation));
}
@Test
- public void testIdTokenParameters() throws ResolverException {
+ public void testIdTokenParameters() throws Exception {
+ initTest(null);
EncryptionParameters params = resolver.resolveSingle(criteria);
Assert.assertEquals("RSA-OAEP-256", params.getKeyTransportEncryptionAlgorithm());
Assert.assertEquals("A192CBC-HS384", params.getDataEncryptionAlgorithm());
- Assert.assertNotNull(params.getKeyTransportEncryptionCredential().getPublicKey());
+ Assert.assertEquals(((RSAKey) jwkSet.getKeyByKeyId("testRsaKey")).toPublicKey(),
+ params.getKeyTransportEncryptionCredential().getPublicKey());
+ }
+
+ @Test
+ public void testIdTokenParametersRemoteKey() throws Exception {
+ RemoteJwkSetCache remoteJwkSetCache = Mockito.mock(RemoteJwkSetCache.class);
+ Mockito.when(remoteJwkSetCache.fetch(Mockito.any(), Mockito.any())).thenReturn(jwkSet);
+ initTest(remoteJwkSetCache);
+ EncryptionParameters params = resolver.resolveSingle(criteria);
+ Assert.assertEquals("RSA-OAEP-256", params.getKeyTransportEncryptionAlgorithm());
+ Assert.assertEquals("A192CBC-HS384", params.getDataEncryptionAlgorithm());
+ Assert.assertEquals(((RSAKey) jwkSet.getKeyByKeyId("testRsaKey")).toPublicKey(),
+ params.getKeyTransportEncryptionCredential().getPublicKey());
+ }
+
+ @Test
+ public void testIdTokenParametersNoKey() throws Exception {
+ RemoteJwkSetCache remoteJwkSetCache = Mockito.mock(RemoteJwkSetCache.class);
+ Mockito.when(remoteJwkSetCache.fetch(Mockito.any(), Mockito.any())).thenReturn(null);
+ initTest(remoteJwkSetCache);
+ EncryptionParameters params = resolver.resolveSingle(criteria);
+ Assert.assertNotEquals(((RSAKey) jwkSet.getKeyByKeyId("testRsaKey")).toPublicKey(),
+ params.getKeyTransportEncryptionCredential().getPublicKey());
}
@Test
- public void testIdTokenParametersDefaultEnc() throws ResolverException {
+ public void testIdTokenParametersDefaultEnc() throws Exception {
+ initTest(null);
metaData.setIDTokenJWEEnc(null);
EncryptionParameters params = resolver.resolveSingle(criteria);
Assert.assertEquals("RSA-OAEP-256", params.getKeyTransportEncryptionAlgorithm());
@@ -116,7 +155,8 @@ public class OIDCClientInformationEncryptionParametersResolverTest {
}
@Test
- public void testUserInfoParameters() throws ResolverException {
+ public void testUserInfoParameters() throws Exception {
+ initTest(null);
resolver.setParameterType(ParameterType.USERINFO_ENCRYPTION);
EncryptionParameters params = resolver.resolveSingle(criteria);
Assert.assertEquals("A128GCMKW", params.getKeyTransportEncryptionAlgorithm());
@@ -125,7 +165,8 @@ public class OIDCClientInformationEncryptionParametersResolverTest {
}
@Test
- public void testRequesrObjectParameters() throws ResolverException {
+ public void testRequesrObjectParameters() throws Exception {
+ initTest(null);
resolver.setParameterType(ParameterType.REQUEST_OBJECT_DECRYPTION);
EncryptionParameters params = resolver.resolveSingle(criteria);
Assert.assertEquals("RSA-OAEP-256", params.getKeyTransportEncryptionAlgorithm());
diff --git a/idp-oidc-extension-impl/src/test/java/net/shibboleth/idp/plugin/oidc/op/security/impl/OIDCClientInformationSignatureSigningParametersResolverTest.java b/idp-oidc-extension-impl/src/test/java/net/shibboleth/idp/plugin/oidc/op/security/impl/OIDCClientInformationSignatureSigningParametersResolverTest.java
index 262eec96..523e47db 100644
--- a/idp-oidc-extension-impl/src/test/java/net/shibboleth/idp/plugin/oidc/op/security/impl/OIDCClientInformationSignatureSigningParametersResolverTest.java
+++ b/idp-oidc-extension-impl/src/test/java/net/shibboleth/idp/plugin/oidc/op/security/impl/OIDCClientInformationSignatureSigningParametersResolverTest.java
@@ -25,6 +25,7 @@ import java.util.Date;
import java.util.List;
import org.mockito.Mockito;
+import org.opensaml.core.testing.OpenSAMLInitBaseTestCase;
import org.opensaml.security.credential.Credential;
import org.opensaml.xmlsec.SignatureSigningConfiguration;
import org.opensaml.xmlsec.SignatureSigningParameters;
@@ -43,7 +44,6 @@ import com.nimbusds.openid.connect.sdk.rp.OIDCClientMetadata;
import net.shibboleth.idp.plugin.oidc.op.criterion.ClientInformationCriterion;
import net.shibboleth.idp.plugin.oidc.op.profile.spring.factory.BasicJWKCredentialFactoryBean;
-import net.shibboleth.idp.plugin.oidc.op.security.impl.OIDCClientInformationSignatureSigningParametersResolver;
import net.shibboleth.idp.plugin.oidc.op.security.impl.OIDCClientInformationSignatureSigningParametersResolver.ParameterType;
import net.shibboleth.oidc.security.impl.OIDCSignatureValidationParameters;
import net.shibboleth.utilities.java.support.resolver.CriteriaSet;
@@ -52,7 +52,7 @@ import net.shibboleth.utilities.java.support.resolver.ResolverException;
/**
* Tests for {@link OIDCClientInformationSignatureSigningParametersResolver}.
*/
-public class OIDCClientInformationSignatureSigningParametersResolverTest {
+public class OIDCClientInformationSignatureSigningParametersResolverTest extends OpenSAMLInitBaseTestCase {
private OIDCClientInformationSignatureSigningParametersResolver resolver;
diff --git a/idp-oidc-extension-impl/src/test/java/net/shibboleth/idp/plugin/oidc/op/security/impl/OIDCClientInformationSignatureValidationParametersResolverTest.java b/idp-oidc-extension-impl/src/test/java/net/shibboleth/idp/plugin/oidc/op/security/impl/OIDCClientInformationSignatureValidationParametersResolverTest.java
index 8e148065..4045ec34 100644
--- a/idp-oidc-extension-impl/src/test/java/net/shibboleth/idp/plugin/oidc/op/security/impl/OIDCClientInformationSignatureValidationParametersResolverTest.java
+++ b/idp-oidc-extension-impl/src/test/java/net/shibboleth/idp/plugin/oidc/op/security/impl/OIDCClientInformationSignatureValidationParametersResolverTest.java
@@ -17,12 +17,15 @@
package net.shibboleth.idp.plugin.oidc.op.security.impl;
+import java.net.URI;
+import java.text.ParseException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Date;
import java.util.List;
import org.mockito.Mockito;
+import org.opensaml.core.testing.OpenSAMLInitBaseTestCase;
import org.opensaml.xmlsec.SignatureSigningConfiguration;
import org.opensaml.xmlsec.criterion.SignatureSigningConfigurationCriterion;
import org.testng.Assert;
@@ -38,8 +41,8 @@ import com.nimbusds.openid.connect.sdk.rp.OIDCClientInformation;
import com.nimbusds.openid.connect.sdk.rp.OIDCClientMetadata;
import net.shibboleth.idp.plugin.oidc.op.criterion.ClientInformationCriterion;
-import net.shibboleth.idp.plugin.oidc.op.security.impl.OIDCClientInformationSignatureValidationParametersResolver;
import net.shibboleth.idp.plugin.oidc.op.security.impl.OIDCClientInformationSignatureValidationParametersResolver.ParameterType;
+import net.shibboleth.oidc.jwk.RemoteJwkSetCache;
import net.shibboleth.oidc.security.impl.OIDCSignatureValidationParameters;
import net.shibboleth.utilities.java.support.resolver.CriteriaSet;
import net.shibboleth.utilities.java.support.resolver.ResolverException;
@@ -47,7 +50,7 @@ import net.shibboleth.utilities.java.support.resolver.ResolverException;
/**
* Tests for {@link OIDCClientInformationSignatureValidationParametersResolver}.
*/
-public class OIDCClientInformationSignatureValidationParametersResolverTest {
+public class OIDCClientInformationSignatureValidationParametersResolverTest extends OpenSAMLInitBaseTestCase {
private OIDCClientInformationSignatureValidationParametersResolver resolver;
@@ -55,20 +58,11 @@ public class OIDCClientInformationSignatureValidationParametersResolverTest {
private OIDCClientMetadata metaData;
+ private JWKSet jwkSet;
+
@BeforeMethod
- protected void setUp() throws Exception {
- resolver = new OIDCClientInformationSignatureValidationParametersResolver();
- // Signing configuration
- List<SignatureSigningConfiguration> configs = new ArrayList<SignatureSigningConfiguration>();
- SignatureSigningConfiguration signConfig = Mockito.mock(SignatureSigningConfiguration.class);
- Mockito.when(signConfig.getSignatureAlgorithms())
- .thenReturn(Arrays.asList("RS256", "HS256", "HS384", "HS512", "ES256", "ES384", "ES512"));
- configs.add(signConfig);
- criteria = new CriteriaSet(new SignatureSigningConfigurationCriterion(configs));
- metaData = new OIDCClientMetadata();
- metaData.setRequestObjectJWSAlg(JWSAlgorithm.ES256);
- metaData.setTokenEndpointAuthJWSAlg(JWSAlgorithm.ES256);
- JWKSet jwkSet = JWKSet.parse("{\n" + " \"keys\":[\n" + " {\n" + " \"kty\":\"RSA\",\n"
+ protected void setUp() throws ParseException {
+ jwkSet = JWKSet.parse("{\n" + " \"keys\":[\n" + " {\n" + " \"kty\":\"RSA\",\n"
+ " \"e\":\"AQAB\",\n" + " \"use\":\"enc\",\n"
+ " \"kid\":\"testkeyRSAEncryption\",\n"
+ " \"n\":\"47mkdLGrenv7QFkAWv1JryydVjq8HsEVCKz-qRttVe2II1-lQc-4sObf-9X0LtAwdtK0g1_EpRzZNuGaK2nFISr9uZQQ5evNHETgUKE2oKJs3r0wnfgvEZVHV6wXg4B7NRmDBgphExIYndBt__L-tC9_S_isaJOXQ_PAx17621pmxdyg8WEnJx9Azc23vH-Cii0ttMxDLNqUTu-tdgtZ8eo0IX7VPBWAnXVi0bRKHJuuvzJ4B8QqwsZsj8hGrwqNkRMoJVEiz-5M6ACLo-rgGNjtCBJRaezolrHSCc-r-hZbAaBKq0dOPRNPcMtRm8TUdmuRKBY7rXaFi7zGV7XDdw\"\n"
@@ -91,79 +85,127 @@ public class OIDCClientInformationSignatureValidationParametersResolverTest {
+ " \"kid\":\"testkeyES512-2\",\n"
+ " \"x\":\"AQL7ZCkzcAyuUdaqYiCSAf2u2MR_l4rqSppQ8lvEEjmjy7ETiPB77BqeH7glJ6xtkK1YhmHxKDKz0E0zdmqWWVYp\",\n"
+ " \"y\":\"AXI7UFlH-Zy2jEf1XoY3NHblkJDsOK4kiv82fRrKtHAoKM_ud25XNzT3lrfbJ--zZlmWUB7fV2jHR0pbmjOOrEF_\"\n"
- + " }\n" + " ]\n" + "}");
- metaData.setJWKSet(jwkSet);
+ + " }\n" + " ]\n" + "}");
+ }
+
+ protected void initTest(RemoteJwkSetCache remoteJwkSetCache) throws Exception {
+ resolver = new OIDCClientInformationSignatureValidationParametersResolver();
+ // Signing configuration
+ List<SignatureSigningConfiguration> configs = new ArrayList<SignatureSigningConfiguration>();
+ SignatureSigningConfiguration signConfig = Mockito.mock(SignatureSigningConfiguration.class);
+ Mockito.when(signConfig.getSignatureAlgorithms())
+ .thenReturn(Arrays.asList("RS256", "HS256", "HS384", "HS512", "ES256", "ES384", "ES512"));
+ configs.add(signConfig);
+ criteria = new CriteriaSet(new SignatureSigningConfigurationCriterion(configs));
+ metaData = new OIDCClientMetadata();
+ metaData.setRequestObjectJWSAlg(JWSAlgorithm.ES256);
+ metaData.setTokenEndpointAuthJWSAlg(JWSAlgorithm.ES256);
+ if (remoteJwkSetCache != null) {
+ resolver.setRemoteJwkSetCache(remoteJwkSetCache);
+ metaData.setJWKSetURI(new URI("https://rp.example.org/jwks"));
+ } else {
+ metaData.setJWKSet(jwkSet);
+ }
OIDCClientInformation clientInformation =
new OIDCClientInformation(new ClientID(), new Date(), metaData, new Secret("abcdefgh"));
criteria.add(new ClientInformationCriterion(clientInformation));
}
@Test
- public void testRequestObjectParameters() throws ResolverException {
+ public void testRequestObjectParameters() throws Exception {
+ initTest(null);
testSigningValidationES256(ParameterType.REQUEST_OBJECT_VALIDATION);
}
@Test
- public void testRequestObjectParametersES384() throws ResolverException {
+ public void testRequestObjectParametersRemoteKeys() throws Exception {
+ RemoteJwkSetCache remoteJwkSetCache = Mockito.mock(RemoteJwkSetCache.class);
+ Mockito.when(remoteJwkSetCache.fetch(Mockito.any(), Mockito.any())).thenReturn(jwkSet);
+ initTest(remoteJwkSetCache);
+ testSigningValidationES256(ParameterType.REQUEST_OBJECT_VALIDATION);
+ }
+
+ @Test
+ public void testRequestObjectParametersNoKeys() throws Exception {
+ RemoteJwkSetCache remoteJwkSetCache = Mockito.mock(RemoteJwkSetCache.class);
+ Mockito.when(remoteJwkSetCache.fetch(Mockito.any(), Mockito.any())).thenReturn(null);
+ initTest(remoteJwkSetCache);
+ resolver.setParameterType(ParameterType.REQUEST_OBJECT_VALIDATION);
+ Assert.assertNull(resolver.resolveSingle(criteria));
+ }
+
+ @Test
+ public void testRequestObjectParametersES384() throws Exception {
+ initTest(null);
metaData.setRequestObjectJWSAlg(JWSAlgorithm.ES384);
testSigningValidationES384(ParameterType.REQUEST_OBJECT_VALIDATION);
}
@Test
- public void testRequestObjectParametersES512() throws ResolverException {
+ public void testRequestObjectParametersES512() throws Exception {
+ initTest(null);
metaData.setRequestObjectJWSAlg(JWSAlgorithm.ES512);
testSigningValidationES512(ParameterType.REQUEST_OBJECT_VALIDATION);
}
@Test
- public void testRequestObjectParametersHS256() throws ResolverException {
+ public void testRequestObjectParametersHS256() throws Exception {
+ initTest(null);
metaData.setRequestObjectJWSAlg(JWSAlgorithm.HS256);
testSigningValidationHS256(ParameterType.REQUEST_OBJECT_VALIDATION);
}
@Test
- public void testRequestObjectParametersHS384() throws ResolverException {
+ public void testRequestObjectParametersHS384() throws Exception {
+ initTest(null);
metaData.setRequestObjectJWSAlg(JWSAlgorithm.HS384);
testSigningValidationHS384(ParameterType.REQUEST_OBJECT_VALIDATION);
}
@Test
- public void testRequestObjectParametersHS512() throws ResolverException {
+ public void testRequestObjectParametersHS512() throws Exception {
+ initTest(null);
metaData.setRequestObjectJWSAlg(JWSAlgorithm.HS512);
testSigningValidationHS512(ParameterType.REQUEST_OBJECT_VALIDATION);
}
@Test
- public void testTokenEndpointJwtParameters() throws ResolverException {
+ public void testTokenEndpointJwtParameters() throws Exception {
+ initTest(null);
testSigningValidationES256(ParameterType.TOKEN_ENDPOINT_JWT_VALIDATION);
}
@Test
- public void testTokenEndpointJwtParametersES384() throws ResolverException {
+ public void testTokenEndpointJwtParametersES384() throws Exception {
+ initTest(null);
metaData.setTokenEndpointAuthJWSAlg(JWSAlgorithm.ES384);
testSigningValidationES384(ParameterType.TOKEN_ENDPOINT_JWT_VALIDATION);
}
@Test
- public void testTokenEndpointJwtParametersES512() throws ResolverException {
+ public void testTokenEndpointJwtParametersES512() throws Exception {
+ initTest(null);
metaData.setTokenEndpointAuthJWSAlg(JWSAlgorithm.ES512);
testSigningValidationES512(ParameterType.TOKEN_ENDPOINT_JWT_VALIDATION);
}
@Test
- public void testTokenEndpointJwtParametersHS256() throws ResolverException {
+ public void testTokenEndpointJwtParametersHS256() throws Exception {
+ initTest(null);
metaData.setTokenEndpointAuthJWSAlg(JWSAlgorithm.HS256);
testSigningValidationHS256(ParameterType.TOKEN_ENDPOINT_JWT_VALIDATION);
}
@Test
- public void testTokenEndpointJwtParametersHS384() throws ResolverException {
+ public void testTokenEndpointJwtParametersHS384() throws Exception {
+ initTest(null);
metaData.setTokenEndpointAuthJWSAlg(JWSAlgorithm.HS384);
testSigningValidationHS384(ParameterType.TOKEN_ENDPOINT_JWT_VALIDATION);
}
@Test
- public void testTokenEndpointJwtParametersHS512() throws ResolverException {
+ public void testTokenEndpointJwtParametersHS512() throws Exception {
+ initTest(null);
metaData.setTokenEndpointAuthJWSAlg(JWSAlgorithm.HS512);
testSigningValidationHS512(ParameterType.TOKEN_ENDPOINT_JWT_VALIDATION);
}
--
To stop receiving notification emails like this one, please contact
the administrator of this repository.
More information about the commits
mailing list