[java-oidc-common] 01/03: JCOMOIDC-62 - Create new credential type for client_secret
Phil Smart
philip.smart at jisc.ac.uk
Fri Jan 27 15:14:58 UTC 2023
This is an automated email from the git hooks/post-receive script.
philsmart pushed a commit to branch dev/JCOMOIDC-62
in repository java-oidc-common.
View the commit online:
http://git.shibboleth.net/view/?p=java-oidc-common.git;a=commit;h=f45f0b248d937da1517fafb1ef10b8a4c8a52909
commit f45f0b248d937da1517fafb1ef10b8a4c8a52909
Author: Phil Smart <philip.smart at jisc.ac.uk>
AuthorDate: Mon Jan 23 13:30:46 2023 +0000
JCOMOIDC-62 - Create new credential type for client_secret
- Change to a simple client secret credential
- Modify touch points and call sites to be compatible
- Modify encryption, decryption, and signature classes to use the new
credential type
- Add new 'alg' and 'enc' criteria to the encryption params resolver.
- Add new 'alg' and 'enc' criteria to the JWE decrypter.
- Modify the client secret resolver to derive the correct key for the
given algorithm inputs
https://shibboleth.atlassian.net/browse/JCOMOIDC-62
---
.../oidc/security}/CredentialConversionUtil.java | 2 +-
.../credential/BasicNimbusSecretCredential.java | 1 +
.../credential/ClientSecretCredential.java | 72 ++++
.../credential/DefaultClientSecretCredential.java | 111 ++++++
.../security/credential}/JWKCredentialSupport.java | 26 +-
.../credential/NimbusSecretCredential.java | 3 +
...n.java => ClientSecretCredentialCriterion.java} | 17 +-
.../BasicClientSecretCredentialFactoryBean.java | 60 +++
.../impl/BasicJOSEObjectCredentialResolver.java | 2 +-
.../impl/BasicJWKCredentialFactoryBean.java | 2 +-
.../ClientSecretCriterionCredentialResolver.java | 129 +++++++
.../impl/CriterionCredentialResolver.java | 69 ----
.../impl/DataEncryptionAlgorithmCriterion.java | 82 ++++
.../impl/KeyManagmentAlgorithmCriterion.java | 82 ++++
.../impl/LocalJOSEObjectCredentialResolver.java | 4 +-
.../impl/ProviderMetadataCredentialResolver.java | 2 +
.../impl/BaseJWTSignatureSecurityHandler.java | 8 +-
.../security/impl/BaseSignedJWTTrustEngine.java | 5 +-
.../shibboleth/oidc/security/impl/DecryptJWE.java | 4 +-
.../oidc/security/impl/EncryptJWTHandler.java | 1 +
...CTokenDecrypter.java => JWETokenDecrypter.java} | 105 +++---
.../oidc/security/impl/SignJWTHandler.java | 8 +-
.../impl/DefaultEncryptionParametersResolver.java | 420 +++++++++++++--------
...lientSecretCriterionCredentialResolverTest.java | 227 +++++++++++
.../oidc/security/impl/EncryptJWTHandlerTest.java | 6 +-
.../impl/ExplicitKeySignedJWTTrustEngineTest.java | 3 +-
...crypterTest.java => JWETokenDecrypterTest.java} | 220 ++++++-----
.../oidc/security/impl/SignJWTHandlerTest.java | 6 +-
.../oidc/security/impl/TestCredentialHelper.java | 44 +--
.../DefaultEncryptionParametersResolverTest.java | 160 ++++----
.../impl/ClientInformationNodeProcessor.java | 2 +-
.../ext/impl/provider/InlineJwksProvider.java | 2 +-
.../config/OIDCAuthorizationConfiguration.java | 16 +-
.../impl/FormOutboundKeySetResponseMessage.java | 2 +-
.../impl/PopulateJWTDecryptionParameters.java | 13 +-
.../impl/PopulateJWTEncryptionParameters.java | 39 +-
...pulateJWTSignatureSigningParametersHandler.java | 10 +-
37 files changed, 1403 insertions(+), 562 deletions(-)
diff --git a/oidc-common-crypto-impl/src/main/java/net/shibboleth/oidc/security/impl/CredentialConversionUtil.java b/oidc-common-crypto-api/src/main/java/net/shibboleth/oidc/security/CredentialConversionUtil.java
similarity index 99%
rename from oidc-common-crypto-impl/src/main/java/net/shibboleth/oidc/security/impl/CredentialConversionUtil.java
rename to oidc-common-crypto-api/src/main/java/net/shibboleth/oidc/security/CredentialConversionUtil.java
index 24c8859..02608a1 100644
--- a/oidc-common-crypto-impl/src/main/java/net/shibboleth/oidc/security/impl/CredentialConversionUtil.java
+++ b/oidc-common-crypto-api/src/main/java/net/shibboleth/oidc/security/CredentialConversionUtil.java
@@ -15,7 +15,7 @@
* limitations under the License.
*/
-package net.shibboleth.oidc.security.impl;
+package net.shibboleth.oidc.security;
import java.security.interfaces.ECPublicKey;
import java.security.interfaces.RSAPublicKey;
diff --git a/oidc-common-crypto-api/src/main/java/net/shibboleth/oidc/security/credential/BasicNimbusSecretCredential.java b/oidc-common-crypto-api/src/main/java/net/shibboleth/oidc/security/credential/BasicNimbusSecretCredential.java
index a6f3dcf..b3e5b07 100644
--- a/oidc-common-crypto-api/src/main/java/net/shibboleth/oidc/security/credential/BasicNimbusSecretCredential.java
+++ b/oidc-common-crypto-api/src/main/java/net/shibboleth/oidc/security/credential/BasicNimbusSecretCredential.java
@@ -25,6 +25,7 @@ import com.nimbusds.oauth2.sdk.auth.Secret;
/**
* A basic implementation of {@link NimbusSecretCredential}.
*/
+ at Deprecated(since = "2.2.0", forRemoval=true)
public class BasicNimbusSecretCredential extends AbstractCredential implements NimbusSecretCredential {
/** The client secret. */
diff --git a/oidc-common-crypto-api/src/main/java/net/shibboleth/oidc/security/credential/ClientSecretCredential.java b/oidc-common-crypto-api/src/main/java/net/shibboleth/oidc/security/credential/ClientSecretCredential.java
new file mode 100644
index 0000000..b7f1c0f
--- /dev/null
+++ b/oidc-common-crypto-api/src/main/java/net/shibboleth/oidc/security/credential/ClientSecretCredential.java
@@ -0,0 +1,72 @@
+/*
+ * Licensed to the University Corporation for Advanced Internet Development,
+ * Inc. (UCAID) under one or more contributor license agreements. See the
+ * NOTICE file distributed with this work for additional information regarding
+ * copyright ownership. The UCAID licenses this file to You 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
+ *
+ * http://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 net.shibboleth.oidc.security.credential;
+
+import javax.annotation.Nonnull;
+
+import org.opensaml.security.credential.Credential;
+
+import com.nimbusds.jose.EncryptionMethod;
+import com.nimbusds.jose.JOSEException;
+import com.nimbusds.jose.JWEAlgorithm;
+
+/**
+ * Credential wrapping a client_secret. Contains methods to convert the client_secret into suitable keys used for
+ * signing and encryption.
+ *
+ * <p>Note, despite its name, this is not an opensaml {@link Credential} type.</p>
+ */
+public interface ClientSecretCredential {
+
+ /**
+ * Get the client_secret as a UTF-8 encoded String.
+ *
+ * @return The client_secret.
+ */
+ @Nonnull String getSecret();
+
+ /**
+ * Get the client_secret as UTF-8 bytes.
+ *
+ * @return the client_secret in bytes
+ */
+ @Nonnull byte[] getSecretAsBytes();
+
+ /**
+ * Create a MAC singing key from the client_secret. The MAC key used is the octets of the UTF-8 representation of
+ * the client_secret value.
+ *
+ * @return a MAC signing key
+ */
+ @Nonnull JWKCredential toSigningCredential();
+
+ /**
+ * Create a symmetric encryption key derived from the client_secret and compatible with the key management mode and
+ * encryption algorithm specified.
+ *
+ * @param alg the key management mode
+ * @param enc the encryption algorithm
+ *
+ * @return a JWKCredential compatible with the 'alg' and 'enc' input
+ *
+ * @throws JOSEException if a key can not be derived
+ */
+ @Nonnull JWKCredential toEncryptionCredential(@Nonnull final JWEAlgorithm alg, @Nonnull final EncryptionMethod enc)
+ throws JOSEException;
+
+}
\ No newline at end of file
diff --git a/oidc-common-crypto-api/src/main/java/net/shibboleth/oidc/security/credential/DefaultClientSecretCredential.java b/oidc-common-crypto-api/src/main/java/net/shibboleth/oidc/security/credential/DefaultClientSecretCredential.java
new file mode 100644
index 0000000..5d3a560
--- /dev/null
+++ b/oidc-common-crypto-api/src/main/java/net/shibboleth/oidc/security/credential/DefaultClientSecretCredential.java
@@ -0,0 +1,111 @@
+/*
+ * Licensed to the University Corporation for Advanced Internet Development,
+ * Inc. (UCAID) under one or more contributor license agreements. See the
+ * NOTICE file distributed with this work for additional information regarding
+ * copyright ownership. The UCAID licenses this file to You 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
+ *
+ * http://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 net.shibboleth.oidc.security.credential;
+
+import java.nio.charset.StandardCharsets;
+
+import javax.annotation.Nonnull;
+import javax.annotation.concurrent.ThreadSafe;
+import javax.crypto.SecretKey;
+import javax.crypto.spec.SecretKeySpec;
+
+import org.opensaml.security.credential.UsageType;
+
+import com.nimbusds.jose.EncryptionMethod;
+import com.nimbusds.jose.JOSEException;
+import com.nimbusds.jose.JWEAlgorithm;
+import com.nimbusds.jose.util.StandardCharset;
+
+import net.shibboleth.utilities.java.support.annotation.constraint.NotEmpty;
+import net.shibboleth.utilities.java.support.annotation.constraint.NotLive;
+import net.shibboleth.utilities.java.support.logic.Constraint;
+
+/**
+ * A basic implementation of {@link ClientSecretCredential}.
+ */
+ at ThreadSafe
+public class DefaultClientSecretCredential implements ClientSecretCredential {
+
+ /** Default client_secret keyname.*/
+ @Nonnull private static final String DEFAULT_SECRET_KEY_NAME = "client_secret_credential";
+
+ /** The client_secret. */
+ @Nonnull private final byte[] clientSecret;
+
+ /** The chosen client_secret keyname.*/
+ @Nonnull @NotEmpty private final String secretKeyName;
+
+ /**
+ *
+ * Constructor.
+ *
+ * @param secret the client_secret
+ */
+ public DefaultClientSecretCredential(@Nonnull final String secret) {
+ Constraint.isNotEmpty(secret, "Secret can not be null or empty");
+ clientSecret = secret.getBytes(StandardCharset.UTF_8);
+ secretKeyName = DEFAULT_SECRET_KEY_NAME;
+ }
+
+ /**
+ *
+ * Constructor.
+ *
+ * @param secret the client_secret
+ * @param keyName the keyname to use when creating a {@link JWKCredential}
+ */
+ public DefaultClientSecretCredential(@Nonnull final String secret, @Nonnull final String keyName) {
+ Constraint.isNotEmpty(secret, "Secret can not be null or empty");
+ clientSecret = secret.getBytes(StandardCharset.UTF_8);
+ secretKeyName = Constraint.isNotEmpty(keyName, "Secret keyname can not be null or empty");
+ }
+
+ @Override
+ @Nonnull public String getSecret() {
+ return new String(clientSecret, StandardCharsets.UTF_8);
+ }
+
+ @Override
+ @NotLive @Nonnull public byte[] getSecretAsBytes(){
+ return clientSecret.clone();
+ }
+
+ @Override
+ @Nonnull public JWKCredential toSigningCredential() {
+ final BasicExpiringJWKCredential jwkCredential = new BasicExpiringJWKCredential();
+ jwkCredential.getKeyNames().add(secretKeyName);
+ jwkCredential.setKid(secretKeyName);
+ jwkCredential.setSecretKey(new SecretKeySpec(getSecretAsBytes(), "NONE"));
+ jwkCredential.setUsageType(UsageType.SIGNING);
+ return jwkCredential;
+ }
+
+ @Override
+ public JWKCredential toEncryptionCredential(final JWEAlgorithm alg, final EncryptionMethod enc)
+ throws JOSEException {
+ // Derive key using the algorithm and enc method
+ final SecretKey key = JWKCredentialSupport.generateSymmetricKey(clientSecret, alg, enc);
+ final BasicExpiringJWKCredential jwkCredential = new BasicExpiringJWKCredential();
+ jwkCredential.getKeyNames().add(secretKeyName);
+ jwkCredential.setKid(secretKeyName);
+ jwkCredential.setUsageType(UsageType.ENCRYPTION);
+ jwkCredential.setSecretKey(key);
+ return jwkCredential;
+ }
+
+}
\ No newline at end of file
diff --git a/oidc-common-crypto-impl/src/main/java/net/shibboleth/oidc/security/credential/impl/JWKCredentialSupport.java b/oidc-common-crypto-api/src/main/java/net/shibboleth/oidc/security/credential/JWKCredentialSupport.java
similarity index 81%
rename from oidc-common-crypto-impl/src/main/java/net/shibboleth/oidc/security/credential/impl/JWKCredentialSupport.java
rename to oidc-common-crypto-api/src/main/java/net/shibboleth/oidc/security/credential/JWKCredentialSupport.java
index faefa2c..ba7d702 100644
--- a/oidc-common-crypto-impl/src/main/java/net/shibboleth/oidc/security/credential/impl/JWKCredentialSupport.java
+++ b/oidc-common-crypto-api/src/main/java/net/shibboleth/oidc/security/credential/JWKCredentialSupport.java
@@ -15,7 +15,7 @@
* limitations under the License.
*/
-package net.shibboleth.oidc.security.credential.impl;
+package net.shibboleth.oidc.security.credential;
import javax.annotation.Nullable;
import javax.crypto.SecretKey;
@@ -27,8 +27,8 @@ import com.nimbusds.jose.util.StandardCharset;
import com.nimbusds.oauth2.sdk.auth.Secret;
import com.nimbusds.oauth2.sdk.jose.SecretKeyDerivation;
-import net.shibboleth.oidc.security.credential.JWKCredential;
-import net.shibboleth.oidc.security.impl.CredentialConversionUtil;
+import net.shibboleth.oidc.security.CredentialConversionUtil;
+
/** Provide JWK specific credential support.*/
public final class JWKCredentialSupport {
@@ -60,8 +60,7 @@ public final class JWKCredentialSupport {
//build a new credential so the old is left in its original state
return CredentialConversionUtil.copySymmetricCredentialWithNewSecret(
credential, "derived-"+CredentialConversionUtil.resolveKid(credential), derivedKey);
- }
-
+ }
/**
* Generate symmetric key from client_secret using the algorithms supplied.
@@ -80,5 +79,22 @@ public final class JWKCredentialSupport {
return SecretKeyDerivation.deriveSecretKey(
new Secret(new String(clientSecret, StandardCharset.UTF_8)), alg, enc);
}
+
+ /**
+ * Generate symmetric key from client_secret using the algorithms supplied.
+ *
+ * @param clientSecret client secret to derive a key from
+ * @param alg the key management mode or key transport algorithm
+ * @param enc the content encryption algorithm
+ *
+ * @return key derived from client secret.
+
+ * @throws JOSEException on error
+ */
+ public static final SecretKey generateSymmetricKey(final Secret clientSecret, final JWEAlgorithm alg,
+ final EncryptionMethod enc) throws JOSEException {
+
+ return SecretKeyDerivation.deriveSecretKey(clientSecret, alg, enc);
+ }
}
diff --git a/oidc-common-crypto-api/src/main/java/net/shibboleth/oidc/security/credential/NimbusSecretCredential.java b/oidc-common-crypto-api/src/main/java/net/shibboleth/oidc/security/credential/NimbusSecretCredential.java
index b91627d..24a72c3 100644
--- a/oidc-common-crypto-api/src/main/java/net/shibboleth/oidc/security/credential/NimbusSecretCredential.java
+++ b/oidc-common-crypto-api/src/main/java/net/shibboleth/oidc/security/credential/NimbusSecretCredential.java
@@ -25,7 +25,10 @@ import com.nimbusds.oauth2.sdk.auth.Secret;
/**
* Credential wrapping {@link Secret}.
+ *
+ * @deprecated use {@link ClientSecretCredential}
*/
+ at Deprecated
public interface NimbusSecretCredential extends Credential {
/**
diff --git a/oidc-common-crypto-api/src/main/java/net/shibboleth/oidc/security/jose/criterion/StaticCredentialCriterion.java b/oidc-common-crypto-api/src/main/java/net/shibboleth/oidc/security/jose/criterion/ClientSecretCredentialCriterion.java
similarity index 78%
rename from oidc-common-crypto-api/src/main/java/net/shibboleth/oidc/security/jose/criterion/StaticCredentialCriterion.java
rename to oidc-common-crypto-api/src/main/java/net/shibboleth/oidc/security/jose/criterion/ClientSecretCredentialCriterion.java
index d83982c..e537c5a 100644
--- a/oidc-common-crypto-api/src/main/java/net/shibboleth/oidc/security/jose/criterion/StaticCredentialCriterion.java
+++ b/oidc-common-crypto-api/src/main/java/net/shibboleth/oidc/security/jose/criterion/ClientSecretCredentialCriterion.java
@@ -19,8 +19,7 @@ package net.shibboleth.oidc.security.jose.criterion;
import javax.annotation.Nonnull;
-import org.opensaml.security.credential.Credential;
-
+import net.shibboleth.oidc.security.credential.ClientSecretCredential;
import net.shibboleth.utilities.java.support.logic.Constraint;
import net.shibboleth.utilities.java.support.resolver.Criterion;
@@ -29,10 +28,10 @@ import net.shibboleth.utilities.java.support.resolver.Criterion;
*
* @since 2.2.0
*/
-public class StaticCredentialCriterion implements Criterion {
+public class ClientSecretCredentialCriterion implements Criterion {
/** The credential to hold.*/
- @Nonnull private final Credential credential;
+ @Nonnull private final ClientSecretCredential credential;
/**
*
@@ -40,7 +39,7 @@ public class StaticCredentialCriterion implements Criterion {
*
* @param cred the credential to hold.
*/
- public StaticCredentialCriterion(@Nonnull final Credential cred) {
+ public ClientSecretCredentialCriterion(@Nonnull final ClientSecretCredential cred) {
credential = Constraint.isNotNull(cred, "Credential can not be null");
}
@@ -49,7 +48,7 @@ public class StaticCredentialCriterion implements Criterion {
*
* @return the credential
*/
- @Nonnull public Credential getCredential() {
+ @Nonnull public ClientSecretCredential getCredential() {
return credential;
}
@@ -57,7 +56,7 @@ public class StaticCredentialCriterion implements Criterion {
@Override
public String toString() {
final StringBuilder builder = new StringBuilder();
- builder.append("StaticCredentialCriterion [credential=");
+ builder.append("ClientSecretCredentialCriterion [credential=");
builder.append(credential);
builder.append("]");
return builder.toString();
@@ -80,8 +79,8 @@ public class StaticCredentialCriterion implements Criterion {
return false;
}
- if (obj instanceof StaticCredentialCriterion) {
- return credential.equals(((StaticCredentialCriterion) obj).credential);
+ if (obj instanceof ClientSecretCredentialCriterion) {
+ return credential.equals(((ClientSecretCredentialCriterion) obj).credential);
}
return false;
diff --git a/oidc-common-crypto-impl/src/main/java/net/shibboleth/oidc/security/credential/impl/BasicClientSecretCredentialFactoryBean.java b/oidc-common-crypto-impl/src/main/java/net/shibboleth/oidc/security/credential/impl/BasicClientSecretCredentialFactoryBean.java
new file mode 100644
index 0000000..46bd2d6
--- /dev/null
+++ b/oidc-common-crypto-impl/src/main/java/net/shibboleth/oidc/security/credential/impl/BasicClientSecretCredentialFactoryBean.java
@@ -0,0 +1,60 @@
+/*
+ * Licensed to the University Corporation for Advanced Internet Development,
+ * Inc. (UCAID) under one or more contributor license agreements. See the
+ * NOTICE file distributed with this work for additional information regarding
+ * copyright ownership. The UCAID licenses this file to You 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
+ *
+ * http://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 net.shibboleth.oidc.security.credential.impl;
+
+import javax.annotation.Nonnull;
+import javax.annotation.Nullable;
+
+import net.shibboleth.ext.spring.factory.AbstractComponentAwareFactoryBean;
+import net.shibboleth.oidc.security.credential.ClientSecretCredential;
+import net.shibboleth.oidc.security.credential.DefaultClientSecretCredential;
+import net.shibboleth.utilities.java.support.annotation.constraint.NotEmpty;
+import net.shibboleth.utilities.java.support.logic.Constraint;
+
+/**
+ * Factory to generate a {@link ClientSecretCredential} from a client_secret string.
+ */
+public class BasicClientSecretCredentialFactoryBean
+ extends AbstractComponentAwareFactoryBean<DefaultClientSecretCredential> {
+
+ /** The secret to use when creating a BasicJWKCredential.*/
+ @Nullable private String secret;
+
+ /**
+ * Set the secret to use.
+ *
+ * @param secretIn the secret
+ */
+ public void setSecret(@Nonnull @NotEmpty final String secretIn) {
+ secret = Constraint.isNotEmpty(secretIn, "Secret can not be null or empty");
+ }
+
+ @Override
+ protected DefaultClientSecretCredential doCreateInstance() throws Exception {
+ if (secret == null) {
+ throw new Exception("Nimbus secret can not be null");
+ }
+ return new DefaultClientSecretCredential(secret);
+ }
+
+ @Override
+ public Class<?> getObjectType() {
+ return DefaultClientSecretCredential.class;
+ }
+
+}
diff --git a/oidc-common-crypto-impl/src/main/java/net/shibboleth/oidc/security/credential/impl/BasicJOSEObjectCredentialResolver.java b/oidc-common-crypto-impl/src/main/java/net/shibboleth/oidc/security/credential/impl/BasicJOSEObjectCredentialResolver.java
index 2426844..f409a9c 100644
--- a/oidc-common-crypto-impl/src/main/java/net/shibboleth/oidc/security/credential/impl/BasicJOSEObjectCredentialResolver.java
+++ b/oidc-common-crypto-impl/src/main/java/net/shibboleth/oidc/security/credential/impl/BasicJOSEObjectCredentialResolver.java
@@ -41,9 +41,9 @@ import com.nimbusds.jose.jwk.JWKSet;
import com.nimbusds.jose.jwk.KeyType;
import com.nimbusds.jose.jwk.RSAKey;
+import net.shibboleth.oidc.security.CredentialConversionUtil;
import net.shibboleth.oidc.security.credential.BasicJWKCredential;
import net.shibboleth.oidc.security.credential.JOSEObjectCredentialResolver;
-import net.shibboleth.oidc.security.impl.CredentialConversionUtil;
import net.shibboleth.oidc.security.jose.criterion.JOSEObjectCriterion;
import net.shibboleth.oidc.security.jose.criterion.KeyIdCriterion;
import net.shibboleth.utilities.java.support.annotation.constraint.NonnullElements;
diff --git a/oidc-common-crypto-impl/src/main/java/net/shibboleth/oidc/security/credential/impl/BasicJWKCredentialFactoryBean.java b/oidc-common-crypto-impl/src/main/java/net/shibboleth/oidc/security/credential/impl/BasicJWKCredentialFactoryBean.java
index da46e52..d59a0ac 100644
--- a/oidc-common-crypto-impl/src/main/java/net/shibboleth/oidc/security/credential/impl/BasicJWKCredentialFactoryBean.java
+++ b/oidc-common-crypto-impl/src/main/java/net/shibboleth/oidc/security/credential/impl/BasicJWKCredentialFactoryBean.java
@@ -38,8 +38,8 @@ import com.nimbusds.jose.jwk.KeyType;
import com.nimbusds.jose.jwk.OctetSequenceKey;
import net.shibboleth.idp.profile.spring.factory.AbstractCredentialFactoryBean;
+import net.shibboleth.oidc.security.CredentialConversionUtil;
import net.shibboleth.oidc.security.credential.BasicJWKCredential;
-import net.shibboleth.oidc.security.impl.CredentialConversionUtil;
import net.shibboleth.utilities.java.support.annotation.constraint.NotEmpty;
import net.shibboleth.utilities.java.support.logic.Constraint;
diff --git a/oidc-common-crypto-impl/src/main/java/net/shibboleth/oidc/security/credential/impl/ClientSecretCriterionCredentialResolver.java b/oidc-common-crypto-impl/src/main/java/net/shibboleth/oidc/security/credential/impl/ClientSecretCriterionCredentialResolver.java
new file mode 100644
index 0000000..9d5dd84
--- /dev/null
+++ b/oidc-common-crypto-impl/src/main/java/net/shibboleth/oidc/security/credential/impl/ClientSecretCriterionCredentialResolver.java
@@ -0,0 +1,129 @@
+/*
+ * Licensed to the University Corporation for Advanced Internet Development,
+ * Inc. (UCAID) under one or more contributor license agreements. See the
+ * NOTICE file distributed with this work for additional information regarding
+ * copyright ownership. The UCAID licenses this file to You 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
+ *
+ * http://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 net.shibboleth.oidc.security.credential.impl;
+
+import java.util.Collections;
+import java.util.List;
+
+import javax.annotation.Nonnull;
+
+import org.opensaml.security.credential.Credential;
+import org.opensaml.security.credential.UsageType;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.nimbusds.jose.EncryptionMethod;
+import com.nimbusds.jose.JOSEException;
+import com.nimbusds.jose.JWEAlgorithm;
+
+import net.shibboleth.oidc.security.credential.ClientSecretCredential;
+import net.shibboleth.oidc.security.jose.criterion.ClientSecretCredentialCriterion;
+import net.shibboleth.utilities.java.support.annotation.ParameterName;
+import net.shibboleth.utilities.java.support.logic.Constraint;
+import net.shibboleth.utilities.java.support.resolver.CriteriaSet;
+import net.shibboleth.utilities.java.support.resolver.ResolverException;
+
+/**
+ * Extracts a credential held inside the {@link ClientSecretCredentialCriterion} from the given criteria set.
+ * Supports credential filter via evaluable criterion.
+ *
+ * <p>Only supports symmetric key algorithms. Request for assymetric key algorithms are ignored.</p>
+ *
+ * <p>A different key credential is derived for different usage types. MAC ('signing') keys are generated directly off
+ * the UTF-8 octets of the client_secret. Encryption/Decryption keys are generated specifically for the key management
+ * mode and encryption algorithm pulled out of the criteria set —and as such, if these criteria do not exist, resolution
+ * for encryption keys will fail.</p>
+ */
+public class ClientSecretCriterionCredentialResolver extends BasicJOSEObjectCredentialResolver {
+
+ /** Class logger. */
+ @Nonnull private final Logger log = LoggerFactory.getLogger(ClientSecretCriterionCredentialResolver.class);
+
+ /** The pre-determined usage type of the credential that is returned from the client_secret.*/
+ @Nonnull private final UsageType forUsageType;
+
+ /**
+ *
+ * Constructor.
+ *
+ * @param usage the usage type of the returned credential
+ */
+ public ClientSecretCriterionCredentialResolver(@Nonnull @ParameterName(name="usage") final UsageType usage) {
+ forUsageType = Constraint.isNotNull(usage, "Usage can not be null");
+ }
+
+ @Override
+ @Nonnull protected Iterable<Credential> resolveFromSource(@Nonnull final CriteriaSet criteriaSet)
+ throws ResolverException {
+ Constraint.isNotNull(criteriaSet, "CriteriaSet was null");
+
+ if (criteriaSet.contains(ClientSecretCredentialCriterion.class)) {
+ final ClientSecretCredentialCriterion credentialCriterion = criteriaSet.get(ClientSecretCredentialCriterion.class);
+ final ClientSecretCredential secretCred = credentialCriterion.getCredential();
+ log.debug("Found client secret credential");
+ if (forUsageType == UsageType.SIGNING) {
+ // Create a signing credential
+ final Credential signingCred = secretCred.toSigningCredential();
+ log.debug("Derived signing credential '{}'", signingCred.getKeyNames());
+
+ return List.of(signingCred);
+
+ } else if (forUsageType == UsageType.ENCRYPTION) {
+ // Create an encryption credential suitable for the algorithms specified
+ final KeyManagmentAlgorithmCriterion alg = criteriaSet.get(KeyManagmentAlgorithmCriterion.class);
+ if (alg == null) {
+ throw new ResolverException(
+ "Credential criteria set did not contain an instance of KeyManagmentAlgorithmCriterion");
+ }
+ // Technically the encryption method is only relevant to key derivation for the Direct Encryption mode
+ final DataEncryptionAlgorithmCriterion enc = criteriaSet.get(DataEncryptionAlgorithmCriterion.class);
+ if (enc == null) {
+ throw new ResolverException(
+ "Credential criteria set did not contain an instance of DataEncryptionAlgorithmCriterion");
+ }
+
+ // Can only derive symmetric key credentials, ignore if not
+ if (JWEAlgorithm.Family.SYMMETRIC.contains(JWEAlgorithm.parse(alg.getAlgorithm()))) {
+ try {
+ final Credential derivedCred = secretCred.toEncryptionCredential(JWEAlgorithm.parse(alg.getAlgorithm()),
+ EncryptionMethod.parse(enc.getEncAlgorithm()));
+
+ log.debug("Derived encryption credential '{}' from 'alg={}' and 'enc={}'", derivedCred.getKeyNames()
+ ,alg.getAlgorithm(), enc.getEncAlgorithm());
+ return List.of(derivedCred);
+
+ } catch (final JOSEException e) {
+ log.warn("Unable to derive symmetric encryption key from client_secret using 'alg={}' and 'enc={}'",
+ alg.getAlgorithm(), enc.getEncAlgorithm());
+ }
+ throw new ResolverException("Unable to create encryption key from client_secret");
+ } else {
+ log.trace("Asymmetric key requested, client_secret not appropriate");
+ return Collections.emptyList();
+ }
+ } else {
+ throw new ResolverException("Unable to create key from client_secret, incompatible usage type");
+ }
+ } else {
+ log.debug("Criteria did not contain a StaticClientSecretCredentialCriterion");
+ return Collections.emptyList();
+ }
+ }
+
+
+}
diff --git a/oidc-common-crypto-impl/src/main/java/net/shibboleth/oidc/security/credential/impl/CriterionCredentialResolver.java b/oidc-common-crypto-impl/src/main/java/net/shibboleth/oidc/security/credential/impl/CriterionCredentialResolver.java
deleted file mode 100644
index 160513f..0000000
--- a/oidc-common-crypto-impl/src/main/java/net/shibboleth/oidc/security/credential/impl/CriterionCredentialResolver.java
+++ /dev/null
@@ -1,69 +0,0 @@
-/*
- * Licensed to the University Corporation for Advanced Internet Development,
- * Inc. (UCAID) under one or more contributor license agreements. See the
- * NOTICE file distributed with this work for additional information regarding
- * copyright ownership. The UCAID licenses this file to You 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
- *
- * http://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 net.shibboleth.oidc.security.credential.impl;
-
-import java.util.Collections;
-import java.util.List;
-
-import javax.annotation.Nonnull;
-
-import org.opensaml.security.credential.Credential;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-import net.shibboleth.oidc.security.credential.JWKCredential;
-import net.shibboleth.oidc.security.impl.CredentialConversionUtil;
-import net.shibboleth.oidc.security.jose.criterion.StaticCredentialCriterion;
-import net.shibboleth.utilities.java.support.logic.Constraint;
-import net.shibboleth.utilities.java.support.resolver.CriteriaSet;
-import net.shibboleth.utilities.java.support.resolver.ResolverException;
-
-/**
- * Extracts a credential held inside the {@link StaticCredentialCriterion} from the given criteria set.
- * Supports credential filter via evaluable criterion.
- */
-public class CriterionCredentialResolver extends BasicJOSEObjectCredentialResolver {
-
- /** Class logger. */
- @Nonnull private final Logger log = LoggerFactory.getLogger(CriterionCredentialResolver.class);
-
- @Override
- @Nonnull protected Iterable<Credential> resolveFromSource(@Nonnull final CriteriaSet criteriaSet)
- throws ResolverException {
- Constraint.isNotNull(criteriaSet, "CriteriaSet was null");
-
- if (criteriaSet.contains(StaticCredentialCriterion.class)) {
- final StaticCredentialCriterion credentialCriterion = criteriaSet.get(StaticCredentialCriterion.class);
- final Credential credential = credentialCriterion.getCredential();
- if (credential instanceof JWKCredential && log.isDebugEnabled()) {
- log.debug("Found credential '{}' with usage '{}' and alg '{}' from criterion",
- CredentialConversionUtil.resolveKid(credential),
- credential.getUsageType(), ((JWKCredential)credential).getAlgorithm());
- } else {
- log.debug("Found credential '{}' with usage '{}' from criterion",
- credential.getKeyNames(), credential.getUsageType());
- }
- return List.of(credential);
-
- } else {
- log.trace("Criteria did not contain a StaticCredentialCriterion");
- return Collections.emptyList();
- }
- }
-
-}
diff --git a/oidc-common-crypto-impl/src/main/java/net/shibboleth/oidc/security/credential/impl/DataEncryptionAlgorithmCriterion.java b/oidc-common-crypto-impl/src/main/java/net/shibboleth/oidc/security/credential/impl/DataEncryptionAlgorithmCriterion.java
new file mode 100644
index 0000000..c925fc9
--- /dev/null
+++ b/oidc-common-crypto-impl/src/main/java/net/shibboleth/oidc/security/credential/impl/DataEncryptionAlgorithmCriterion.java
@@ -0,0 +1,82 @@
+
+package net.shibboleth.oidc.security.credential.impl;
+
+import javax.annotation.Nonnull;
+
+import net.shibboleth.utilities.java.support.logic.Constraint;
+import net.shibboleth.utilities.java.support.primitive.StringSupport;
+import net.shibboleth.utilities.java.support.resolver.Criterion;
+
+/**
+ * An implementation of {@link Criterion} which specifies content encryption algorithm criteria.
+ */
+public final class DataEncryptionAlgorithmCriterion implements Criterion {
+
+ /** Key algorithm type of resolved credentials. */
+ private String encAlgorithm;
+
+ /**
+ * Constructor.
+ *
+ * @param algorithm key algorithm
+ */
+ public DataEncryptionAlgorithmCriterion(@Nonnull final String algorithm) {
+ setEncAlgorithm(algorithm);
+ }
+
+ /**
+ * Get the encryption algorithm criteria.
+ *
+ * @return returns the keyAlgorithm.
+ */
+ @Nonnull public String getEncAlgorithm() {
+ return encAlgorithm;
+ }
+
+ /**
+ * Set the encryption algorithm criteria.
+ *
+ * @param algorithm The encryption algorithm to set.
+ */
+ public void setEncAlgorithm(@Nonnull final String algorithm) {
+ final String trimmed = StringSupport.trimOrNull(algorithm);
+ Constraint.isNotNull(trimmed, "Encryption algorithm criteria cannot be null or empty");
+
+ encAlgorithm = trimmed;
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public String toString() {
+ final StringBuilder builder = new StringBuilder();
+ builder.append("DataEncryptionAlgorithmCriterion [encAlgorithm=");
+ builder.append(encAlgorithm);
+ builder.append("]");
+ return builder.toString();
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public int hashCode() {
+ return encAlgorithm.hashCode();
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public boolean equals(final Object obj) {
+ if (this == obj) {
+ return true;
+ }
+
+ if (obj == null) {
+ return false;
+ }
+
+ if (obj instanceof DataEncryptionAlgorithmCriterion) {
+ return encAlgorithm.equals(((DataEncryptionAlgorithmCriterion) obj).encAlgorithm);
+ }
+
+ return false;
+ }
+
+}
diff --git a/oidc-common-crypto-impl/src/main/java/net/shibboleth/oidc/security/credential/impl/KeyManagmentAlgorithmCriterion.java b/oidc-common-crypto-impl/src/main/java/net/shibboleth/oidc/security/credential/impl/KeyManagmentAlgorithmCriterion.java
new file mode 100644
index 0000000..46724ed
--- /dev/null
+++ b/oidc-common-crypto-impl/src/main/java/net/shibboleth/oidc/security/credential/impl/KeyManagmentAlgorithmCriterion.java
@@ -0,0 +1,82 @@
+
+package net.shibboleth.oidc.security.credential.impl;
+
+import javax.annotation.Nonnull;
+
+import net.shibboleth.utilities.java.support.logic.Constraint;
+import net.shibboleth.utilities.java.support.primitive.StringSupport;
+import net.shibboleth.utilities.java.support.resolver.Criterion;
+
+/**
+ * An implementation of {@link Criterion} which specifies content encryption algorithm criteria.
+ */
+public final class KeyManagmentAlgorithmCriterion implements Criterion {
+
+ /** Key algorithm type of resolved credentials. */
+ private String algorithmName;
+
+ /**
+ * Constructor.
+ *
+ * @param algorithm key algorithm
+ */
+ public KeyManagmentAlgorithmCriterion(@Nonnull final String algorithm) {
+ setAlgorithm(algorithm);
+ }
+
+ /**
+ * Get the algorithm criteria.
+ *
+ * @return returns the keyAlgorithm.
+ */
+ @Nonnull public String getAlgorithm() {
+ return algorithmName;
+ }
+
+ /**
+ * Set the algorithm criteria.
+ *
+ * @param algorithm The encryption algorithm to set.
+ */
+ public void setAlgorithm(@Nonnull final String algorithm) {
+ final String trimmed = StringSupport.trimOrNull(algorithm);
+ Constraint.isNotNull(trimmed, "Key Management algorithm criteria cannot be null or empty");
+
+ algorithmName = trimmed;
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public String toString() {
+ final StringBuilder builder = new StringBuilder();
+ builder.append("KeyManagmentAlgorithmCriterion [algorithm=");
+ builder.append(algorithmName);
+ builder.append("]");
+ return builder.toString();
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public int hashCode() {
+ return algorithmName.hashCode();
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public boolean equals(final Object obj) {
+ if (this == obj) {
+ return true;
+ }
+
+ if (obj == null) {
+ return false;
+ }
+
+ if (obj instanceof KeyManagmentAlgorithmCriterion) {
+ return algorithmName.equals(((KeyManagmentAlgorithmCriterion) obj).algorithmName);
+ }
+
+ return false;
+ }
+
+}
diff --git a/oidc-common-crypto-impl/src/main/java/net/shibboleth/oidc/security/credential/impl/LocalJOSEObjectCredentialResolver.java b/oidc-common-crypto-impl/src/main/java/net/shibboleth/oidc/security/credential/impl/LocalJOSEObjectCredentialResolver.java
index 5446ac0..53eadd8 100644
--- a/oidc-common-crypto-impl/src/main/java/net/shibboleth/oidc/security/credential/impl/LocalJOSEObjectCredentialResolver.java
+++ b/oidc-common-crypto-impl/src/main/java/net/shibboleth/oidc/security/credential/impl/LocalJOSEObjectCredentialResolver.java
@@ -37,7 +37,7 @@ import com.nimbusds.jose.JWEHeader;
import com.nimbusds.jose.JWSHeader;
import net.shibboleth.oidc.security.credential.JOSEObjectCredentialResolver;
-import net.shibboleth.oidc.security.impl.OIDCTokenDecrypter;
+import net.shibboleth.oidc.security.impl.JWETokenDecrypter;
import net.shibboleth.utilities.java.support.annotation.ParameterName;
import net.shibboleth.utilities.java.support.annotation.constraint.Live;
import net.shibboleth.utilities.java.support.annotation.constraint.NonnullElements;
@@ -58,7 +58,7 @@ import net.shibboleth.utilities.java.support.resolver.ResolverException;
*
* <p>
* A typical use case for this class would be as a resolver of decryption keys,
- * such as is needed by {@link OIDCTokenDecrypter}}.
+ * such as is needed by {@link JWETokenDecrypter}}.
* </p>
*
* <p>
diff --git a/oidc-common-crypto-impl/src/main/java/net/shibboleth/oidc/security/credential/impl/ProviderMetadataCredentialResolver.java b/oidc-common-crypto-impl/src/main/java/net/shibboleth/oidc/security/credential/impl/ProviderMetadataCredentialResolver.java
index 586a621..f633c8c 100644
--- a/oidc-common-crypto-impl/src/main/java/net/shibboleth/oidc/security/credential/impl/ProviderMetadataCredentialResolver.java
+++ b/oidc-common-crypto-impl/src/main/java/net/shibboleth/oidc/security/credential/impl/ProviderMetadataCredentialResolver.java
@@ -135,6 +135,8 @@ public class ProviderMetadataCredentialResolver extends BasicJOSEObjectCredentia
@Nonnull protected Collection<Credential> resolveFromMetadata(@Nonnull final CriteriaSet criteriaSet,
@Nonnull final OIDCProviderMetadata metadata) {
+ log.debug("Resolving JWKs from provider metadata");
+
final LinkedHashSet<Credential> credentials = new LinkedHashSet<>(1);
if (metadata.getJWKSetURI() != null) {
diff --git a/oidc-common-crypto-impl/src/main/java/net/shibboleth/oidc/security/impl/BaseJWTSignatureSecurityHandler.java b/oidc-common-crypto-impl/src/main/java/net/shibboleth/oidc/security/impl/BaseJWTSignatureSecurityHandler.java
index 789f88b..3e1c0de 100644
--- a/oidc-common-crypto-impl/src/main/java/net/shibboleth/oidc/security/impl/BaseJWTSignatureSecurityHandler.java
+++ b/oidc-common-crypto-impl/src/main/java/net/shibboleth/oidc/security/impl/BaseJWTSignatureSecurityHandler.java
@@ -27,7 +27,6 @@ import org.opensaml.messaging.context.navigate.ChildContextLookup;
import org.opensaml.messaging.handler.MessageHandlerException;
import org.opensaml.profile.context.ProfileRequestContext;
import org.opensaml.profile.context.navigate.ParentProfileRequestContextLookup;
-import org.opensaml.security.credential.Credential;
import org.opensaml.security.credential.UsageType;
import org.opensaml.security.criteria.UsageCriterion;
import org.opensaml.security.messaging.impl.BaseTrustEngineSecurityHandler;
@@ -41,10 +40,11 @@ import com.nimbusds.openid.connect.sdk.rp.OIDCClientInformation;
import net.shibboleth.idp.profile.context.RelyingPartyContext;
import net.shibboleth.oidc.profile.config.OIDCAuthorizationConfiguration;
+import net.shibboleth.oidc.security.credential.ClientSecretCredential;
import net.shibboleth.oidc.security.jose.context.SecurityParametersContext;
import net.shibboleth.oidc.security.jose.criterion.ClientInformationCriterion;
import net.shibboleth.oidc.security.jose.criterion.ProviderMetadataCriterion;
-import net.shibboleth.oidc.security.jose.criterion.StaticCredentialCriterion;
+import net.shibboleth.oidc.security.jose.criterion.ClientSecretCredentialCriterion;
import net.shibboleth.utilities.java.support.component.ComponentSupport;
import net.shibboleth.utilities.java.support.logic.Constraint;
import net.shibboleth.utilities.java.support.logic.FunctionSupport;
@@ -178,9 +178,9 @@ public abstract class BaseJWTSignatureSecurityHandler extends BaseTrustEngineSec
}
if (profileConfiguration != null) {
- final Credential credential = profileConfiguration.getClientCredential(PRC_LOOKUP.apply(messageContext));
+ final ClientSecretCredential credential = profileConfiguration.getClientCredential(PRC_LOOKUP.apply(messageContext));
if (credential != null) {
- criteriaSet.add(new StaticCredentialCriterion(credential));
+ criteriaSet.add(new ClientSecretCredentialCriterion(credential));
} else {
log.trace("{} No credential found from the profile configuration", getLogPrefix());
}
diff --git a/oidc-common-crypto-impl/src/main/java/net/shibboleth/oidc/security/impl/BaseSignedJWTTrustEngine.java b/oidc-common-crypto-impl/src/main/java/net/shibboleth/oidc/security/impl/BaseSignedJWTTrustEngine.java
index f5dcc59..0d0c798 100644
--- a/oidc-common-crypto-impl/src/main/java/net/shibboleth/oidc/security/impl/BaseSignedJWTTrustEngine.java
+++ b/oidc-common-crypto-impl/src/main/java/net/shibboleth/oidc/security/impl/BaseSignedJWTTrustEngine.java
@@ -172,9 +172,8 @@ public abstract class BaseSignedJWTTrustEngine<TrustBasisType> implements TrustE
if (log.isDebugEnabled()) {
final String kid = credential instanceof JWKCredential ?
((JWKCredential) credential).getKid() : null;
- log.debug("JWT {} verified using algorithm {}{}", signedJWT.serialize(),
- algorithm.getName(),
- kid != null ? " and key " + kid : "");
+ log.debug("Verified JWT using algorithm {}{}: {} ", algorithm.getName(),
+ kid != null ? " and key " + kid : "", signedJWT.serialize());
}
log.debug("Signature validation using candidate credential was successful");
return true;
diff --git a/oidc-common-crypto-impl/src/main/java/net/shibboleth/oidc/security/impl/DecryptJWE.java b/oidc-common-crypto-impl/src/main/java/net/shibboleth/oidc/security/impl/DecryptJWE.java
index 86d0ee3..920c48c 100644
--- a/oidc-common-crypto-impl/src/main/java/net/shibboleth/oidc/security/impl/DecryptJWE.java
+++ b/oidc-common-crypto-impl/src/main/java/net/shibboleth/oidc/security/impl/DecryptJWE.java
@@ -70,7 +70,7 @@ public class DecryptJWE extends AbstractProfileAction {
@Nullable private EncryptedJWT encryptedJwt;
/** The decryption object. */
- @Nullable private OIDCTokenDecrypter decrypter;
+ @Nullable private JWETokenDecrypter decrypter;
/** Strategy used to locate the {@link SecurityParametersContext}. */
@Nonnull private Function<ProfileRequestContext, SecurityParametersContext> securityParamsLookupStrategy;
@@ -155,7 +155,7 @@ public class DecryptJWE extends AbstractProfileAction {
return false;
} else {
final DecryptionParameters params = paramsCtx.getDecryptionParameters();
- decrypter = new OIDCTokenDecrypter(params);
+ decrypter = new JWETokenDecrypter(params);
}
diff --git a/oidc-common-crypto-impl/src/main/java/net/shibboleth/oidc/security/impl/EncryptJWTHandler.java b/oidc-common-crypto-impl/src/main/java/net/shibboleth/oidc/security/impl/EncryptJWTHandler.java
index bc56e93..7a2afb4 100644
--- a/oidc-common-crypto-impl/src/main/java/net/shibboleth/oidc/security/impl/EncryptJWTHandler.java
+++ b/oidc-common-crypto-impl/src/main/java/net/shibboleth/oidc/security/impl/EncryptJWTHandler.java
@@ -47,6 +47,7 @@ import com.nimbusds.jose.crypto.RSAEncrypter;
import com.nimbusds.jwt.EncryptedJWT;
import com.nimbusds.jwt.JWT;
+import net.shibboleth.oidc.security.CredentialConversionUtil;
import net.shibboleth.oidc.security.jose.EncryptionParameters;
import net.shibboleth.oidc.security.jose.context.SecurityParametersContext;
import net.shibboleth.utilities.java.support.annotation.constraint.NonnullAfterInit;
diff --git a/oidc-common-crypto-impl/src/main/java/net/shibboleth/oidc/security/impl/OIDCTokenDecrypter.java b/oidc-common-crypto-impl/src/main/java/net/shibboleth/oidc/security/impl/JWETokenDecrypter.java
similarity index 88%
rename from oidc-common-crypto-impl/src/main/java/net/shibboleth/oidc/security/impl/OIDCTokenDecrypter.java
rename to oidc-common-crypto-impl/src/main/java/net/shibboleth/oidc/security/impl/JWETokenDecrypter.java
index cc5ad63..9eb48bc 100644
--- a/oidc-common-crypto-impl/src/main/java/net/shibboleth/oidc/security/impl/OIDCTokenDecrypter.java
+++ b/oidc-common-crypto-impl/src/main/java/net/shibboleth/oidc/security/impl/JWETokenDecrypter.java
@@ -65,9 +65,11 @@ import com.nimbusds.jwt.EncryptedJWT;
import com.nimbusds.jwt.JWT;
import com.nimbusds.jwt.JWTParser;
+import net.shibboleth.oidc.security.CredentialConversionUtil;
import net.shibboleth.oidc.security.credential.JWKCredential;
+import net.shibboleth.oidc.security.credential.impl.DataEncryptionAlgorithmCriterion;
import net.shibboleth.oidc.security.credential.impl.EvaluableKeyIDCredentialCriterion;
-import net.shibboleth.oidc.security.credential.impl.JWKCredentialSupport;
+import net.shibboleth.oidc.security.credential.impl.KeyManagmentAlgorithmCriterion;
import net.shibboleth.oidc.security.jose.DecryptionParameters;
import net.shibboleth.oidc.security.jose.criterion.JOSEObjectCriterion;
import net.shibboleth.oidc.security.jose.criterion.KeyIdCriterion;
@@ -82,17 +84,14 @@ import net.shibboleth.utilities.java.support.resolver.ResolverException;
* The {@link EncryptedJWT} will be decrypted in-place, with its {@link State} changing to {@link State#DECRYPTED}
* on successful decryption. Any error that occurs decrypting the JWT will throw an {@link DecryptionException}.
*
- * <p>As this decrypter is specific to OIDC then, as per OIDC specification, symmetric decryption keys are derived from
- * resolved symmetric keys (e.g. a client_secret).</p>
- *
* <p>A decrypter should be created for each new decryption operation.</p>
*
* @since 2.2.0
*/
-public class OIDCTokenDecrypter {
+public class JWETokenDecrypter {
/** Class logger. */
- private final Logger log = LoggerFactory.getLogger(OIDCTokenDecrypter.class);
+ private final Logger log = LoggerFactory.getLogger(JWETokenDecrypter.class);
/** The JWT decryption parameters. */
private final DecryptionParameters params;
@@ -103,7 +102,7 @@ public class OIDCTokenDecrypter {
*
* @param decryptionParams the parameters to use during decryption
*/
- public OIDCTokenDecrypter(@Nonnull final DecryptionParameters decryptionParams) {
+ public JWETokenDecrypter(@Nonnull final DecryptionParameters decryptionParams) {
params = Constraint.isNotNull(decryptionParams, "Decryption params can not be null");
}
@@ -148,7 +147,7 @@ public class OIDCTokenDecrypter {
throw new DecryptionException("Error decrypting JWT", e);
}
} else {
- // Should not happen if all the above key managment modes are correctly captured
+ // Should not happen if all the above key management modes are correctly captured
throw new DecryptionException("JWE failed to decrypt without error");
}
@@ -157,7 +156,7 @@ public class OIDCTokenDecrypter {
/**
* Build a criteria set using the additional criteria in the params, those supplied, and those
- * that relating to the encrypted JWT.
+ * that relate to the encrypted JWT.
*
* @param encryptedObject the encrypted JWT to build criterion from
* @param criteria criteria supplied, can be {@literal null}.
@@ -184,6 +183,17 @@ public class OIDCTokenDecrypter {
new KeyIdCriterion(keyId)));
}
+ // Add algorithm if present(should be)
+ if (encryptedObject.getHeader().getAlgorithm() != null) {
+ newCriteriaSet.add(
+ new KeyManagmentAlgorithmCriterion(encryptedObject.getHeader().getAlgorithm().getName()));
+ }
+ // Add encryption method if present(should be)
+ if (encryptedObject.getHeader().getEncryptionMethod() != null) {
+ newCriteriaSet.add(
+ new DataEncryptionAlgorithmCriterion(encryptedObject.getHeader().getEncryptionMethod().getName()));
+ }
+
// Add the entire object so the resolver can access it
newCriteriaSet.add(new JOSEObjectCriterion(encryptedObject));
@@ -215,7 +225,7 @@ public class OIDCTokenDecrypter {
final KeyAlgorithmCriterion algoCrit = buildKeyAlgorithmCriteria(algAlgorithmURI);
if (algoCrit != null) {
criteriaSet.add(algoCrit);
- log.debug("Added decryption key algorithm 'alg' criteria: {}", algoCrit.getKeyAlgorithm());
+ log.debug("Added decryption key algorithm ('alg') criteria: {}", algoCrit.getKeyAlgorithm());
}
// Add key size criteria if possible
@@ -315,11 +325,12 @@ public class OIDCTokenDecrypter {
* <p>For each credential, algorithm compatibly is checked against that described by the JWE and any
* includes and excludes lists configured.</p>
*
- * <p>The process terminates when a resolved credential decrypts the JWT.</p>
+ * <p>The process terminates when a resolved credential decrypts the JWT. The resolvers should only retrieve
+ * appropriate keys, but that is not guaranteed.</p>
*
* @param encryptedObject the encrypted JWT to decrypt - in place.
*
- * @throws DecryptionException if the resolved credentials could not be used to decrypt the JWT.
+ * @throws DecryptionException if any of the resolved credentials could not be used to decrypt the JWT.
*/
private void decryptUsingKeyAgreement(final EncryptedJWT encryptedObject) throws DecryptionException {
@@ -334,8 +345,16 @@ public class OIDCTokenDecrypter {
try {
for (final Credential cred : params.getKEKCredentialResolver().resolve(criteria)) {
+ if (!(cred instanceof JWKCredential)) {
+ if (log.isTraceEnabled()) {
+ log.trace("JWT decryption requires a JWK credential, resolved credential '{}' was not",
+ CredentialConversionUtil.resolveKid(cred));
+ }
+ // Require a JWKCredential
+ continue;
+ }
try {
- validateKeyManagmentAlgorithm(encryptedObject, cred);
+ validateKeyManagmentAlgorithm(encryptedObject, (JWKCredential)cred);
final JWEDecrypter decrypter = new ECDHDecrypter((ECPrivateKey)cred.getPrivateKey());
encryptedObject.decrypt(decrypter);
return;
@@ -352,14 +371,15 @@ public class OIDCTokenDecrypter {
}
/**
- * Decrypt the encrypted JWT by first decrypting the wrapped content encryption key using on of the shared
+ * Decrypt the encrypted JWT by first decrypting the wrapped content encryption key using one of the shared
* key wrapping keys derived from a symmetric key resolved by the
* {@link DecryptionParameters#getKEKCredentialResolver()} resolver.
*
* <p>For each credential, algorithm compatibly is checked against that described by the JWE and any
* includes and excludes lists configured.</p>
*
- * <p>The process terminates when the first resolved credential (that decrypts the CEK) decrypts the JWT.</p>
+ * <p>The process terminates when the first resolved credential (that decrypts the CEK) decrypts the JWT.
+ * The resolvers should only retrieve appropriate keys, but that is not guaranteed.</p>
*
* @param encryptedObject the encrypted JWT to decrypt - in place.
*
@@ -387,13 +407,9 @@ public class OIDCTokenDecrypter {
continue;
}
try {
- final JWEAlgorithm alg = validateKeyManagmentAlgorithm(encryptedObject, cred);
- final EncryptionMethod enc = validateContentEncryptionAlgorithm(encryptedObject, cred);
- //Key wrapping requires a derived credential
- final JWKCredential derivedKey =
- JWKCredentialSupport.deriveSymmetricKeyForAlgAndEnc((JWKCredential)cred,
- alg, enc);
- final JWEDecrypter decrypter = new AESDecrypter(derivedKey.getSecretKey());
+ validateKeyManagmentAlgorithm(encryptedObject, (JWKCredential)cred);
+ validateContentEncryptionAlgorithm(encryptedObject,(JWKCredential) cred);
+ final JWEDecrypter decrypter = new AESDecrypter(cred.getSecretKey());
encryptedObject.decrypt(decrypter);
return;
} catch (final JOSEException | DecryptionException e) {
@@ -416,7 +432,8 @@ public class OIDCTokenDecrypter {
* <p>For each credential, algorithm compatibly is checked against that described by the JWE and any
* includes and excludes lists configured.</p>
*
- * <p>The process terminates when the first resolved credential (that decrypts the CEK) decrypts the JWT.</p>
+ * <p>The process terminates when the first resolved credential (that decrypts the CEK) decrypts the JWT.
+ * The resolvers should only retrieve appropriate keys, but that is not guaranteed.</p>
*
* @param encryptedObject the encrypted JWT to decrypt - in place.
*
@@ -435,8 +452,16 @@ public class OIDCTokenDecrypter {
try {
for (final Credential cred : params.getKEKCredentialResolver().resolve(criteria)) {
+ if (!(cred instanceof JWKCredential)) {
+ if (log.isTraceEnabled()) {
+ log.trace("JWT decryption requires a JWK credential, resolved credential '{}' was not",
+ CredentialConversionUtil.resolveKid(cred));
+ }
+ // Require a JWKCredential
+ continue;
+ }
try {
- validateKeyManagmentAlgorithm(encryptedObject, cred);
+ validateKeyManagmentAlgorithm(encryptedObject, (JWKCredential)cred);
final JWEDecrypter decrypter = new RSADecrypter(cred.getPrivateKey());
encryptedObject.decrypt(decrypter);
return;
@@ -461,7 +486,7 @@ public class OIDCTokenDecrypter {
* includes and excludes lists configured.</p>
*
* <p>The first resolved (and derived) credential that decrypts the JWT produces a result,
- * and the process terminates.</p>
+ * and the process terminates. The resolvers should only retrieve appropriate keys, but that is not guaranteed.</p>
*
* @param encryptedObject the encrypted JWT to decrypt - in place.
*
@@ -485,20 +510,16 @@ public class OIDCTokenDecrypter {
for (final Credential cred : params.getContentEncryptionKeyCredentialResolver().resolve(criteria)) {
if (!(cred instanceof JWKCredential)) {
if (log.isTraceEnabled()) {
- log.trace("JWT direct decryption requires a JWK credential, resolved credential "
- + "'{}' was not", CredentialConversionUtil.resolveKid(cred));
+ log.trace("JWT decryption requires a JWK credential, resolved credential '{}' was not",
+ CredentialConversionUtil.resolveKid(cred));
}
// Require a JWKCredential
continue;
}
try {
- validateKeyManagmentAlgorithm(encryptedObject, cred);
- final EncryptionMethod enc = validateContentEncryptionAlgorithm(encryptedObject, cred);
- // Symmetric key to use is derived from shared symmetric key e.g. client_secret
- final JWKCredential derivedKey =
- JWKCredentialSupport.deriveSymmetricKeyForAlgAndEnc((JWKCredential)cred,
- JWEAlgorithm.DIR, enc);
- final JWEDecrypter decrypter = new DirectDecrypter(derivedKey.getSecretKey());
+ validateKeyManagmentAlgorithm(encryptedObject, (JWKCredential)cred);
+ validateContentEncryptionAlgorithm(encryptedObject, (JWKCredential)cred);
+ final JWEDecrypter decrypter = new DirectDecrypter(cred.getSecretKey());
encryptedObject.decrypt(decrypter);
return;
} catch (final JOSEException | DecryptionException e) {
@@ -527,7 +548,7 @@ public class OIDCTokenDecrypter {
*/
// Checkstyle: CyclomaticComplexity OFF
private JWEAlgorithm validateKeyManagmentAlgorithm(
- @Nonnull final EncryptedJWT encryptedObject, @Nonnull final Credential cred) throws DecryptionException {
+ @Nonnull final EncryptedJWT encryptedObject, @Nonnull final JWKCredential cred) throws DecryptionException {
if (encryptedObject.getHeader() == null) {
throw new DecryptionException("JWE did not contain a JOSE header, is in an illegal state");
@@ -536,10 +557,9 @@ public class OIDCTokenDecrypter {
final JWEAlgorithm headerAlg = encryptedObject.getHeader().getAlgorithm();
validateAlgorithmURI(headerAlg.getName());
- if (cred instanceof JWKCredential && ((JWKCredential)cred).getAlgorithm() != null) {
- final JWKCredential jwkCred = (JWKCredential)cred;
- if (!headerAlg.equals(jwkCred.getAlgorithm())) {
- throw new DecryptionException("Credential algorithm '"+jwkCred.getAlgorithm()+"' "
+ if (cred.getAlgorithm() != null) {
+ if (!headerAlg.equals(cred.getAlgorithm())) {
+ throw new DecryptionException("Credential algorithm '"+cred.getAlgorithm()+"' "
+ "was not a match for the "
+ "algorithm '"+encryptedObject.getHeader().getAlgorithm()+"'");
@@ -557,7 +577,7 @@ public class OIDCTokenDecrypter {
throw new DecryptionException("Credential did not contain an AES secret key");
}
if (JWEAlgorithm.DIR.equals(headerAlg) && cred.getSecretKey() == null) {
- throw new DecryptionException("Credential did not contain an direct encryption secret key");
+ throw new DecryptionException("Credential did not contain a direct encryption secret key");
}
//All fine
@@ -578,7 +598,7 @@ public class OIDCTokenDecrypter {
* @throws DecryptionException if there is an algorithm mismatch.
*/
@Nonnull private EncryptionMethod validateContentEncryptionAlgorithm(
- @Nonnull final EncryptedJWT encryptedObject, @Nonnull final Credential cred) throws DecryptionException {
+ @Nonnull final EncryptedJWT encryptedObject, @Nonnull final JWKCredential cred) throws DecryptionException {
if (encryptedObject.getHeader() == null) {
throw new DecryptionException("JWE did not contain a JOSE header, is in an illegal state");
@@ -589,8 +609,7 @@ public class OIDCTokenDecrypter {
throw new DecryptionException("JWE did not contain an 'enc' JOSE header, is in an illegal state");
}
- final String encAlgorithmURI = StringSupport.trimOrNull(enc.getName());
-
+ final String encAlgorithmURI = StringSupport.trimOrNull(enc.getName());
validateAlgorithmURI(encAlgorithmURI);
final String jcaKeyAlgorithm = AlgorithmSupport.getKeyAlgorithm(encAlgorithmURI);
diff --git a/oidc-common-crypto-impl/src/main/java/net/shibboleth/oidc/security/impl/SignJWTHandler.java b/oidc-common-crypto-impl/src/main/java/net/shibboleth/oidc/security/impl/SignJWTHandler.java
index 98e9b96..2175400 100644
--- a/oidc-common-crypto-impl/src/main/java/net/shibboleth/oidc/security/impl/SignJWTHandler.java
+++ b/oidc-common-crypto-impl/src/main/java/net/shibboleth/oidc/security/impl/SignJWTHandler.java
@@ -46,6 +46,7 @@ import com.nimbusds.jwt.JWT;
import com.nimbusds.jwt.JWTClaimsSet;
import com.nimbusds.jwt.SignedJWT;
+import net.shibboleth.oidc.security.CredentialConversionUtil;
import net.shibboleth.oidc.security.credential.JWKCredential;
import net.shibboleth.oidc.security.jose.SignatureSigningParameters;
import net.shibboleth.oidc.security.jose.context.SecurityParametersContext;
@@ -59,7 +60,6 @@ import net.shibboleth.utilities.java.support.primitive.StringSupport;
/**
* Action that signs a request object and sets it as the request object to the authentication request.
*/
-//TODO move to commons?
public class SignJWTHandler extends AbstractMessageHandler {
/** Class logger. */
@@ -216,9 +216,11 @@ public class SignJWTHandler extends AbstractMessageHandler {
jwt = new SignedJWT(headerBuilder.build(), jwtClaimSetToSign);
jwt.sign(signer);
if (log.isDebugEnabled() && !log.isTraceEnabled()) {
- log.debug("{} Signed JWT '{}'", getLogPrefix(), logName);
+ log.debug("{} Signed JWT '{}' using kid '{}'", getLogPrefix(), logName,
+ CredentialConversionUtil.resolveKid(credential));
} else if (log.isTraceEnabled()) {
- log.trace("{} Signed JWT '{}': {}", getLogPrefix(), logName, jwt.serialize());
+ log.trace("{} Signed JWT '{}' using kid '{}': {}", getLogPrefix(), logName,
+ CredentialConversionUtil.resolveKid(credential),jwt.serialize());
}
if (jwt.getState() != State.SIGNED) {
diff --git a/oidc-common-crypto-impl/src/main/java/net/shibboleth/oidc/security/jose/impl/DefaultEncryptionParametersResolver.java b/oidc-common-crypto-impl/src/main/java/net/shibboleth/oidc/security/jose/impl/DefaultEncryptionParametersResolver.java
index 0cc7512..7cbb806 100644
--- a/oidc-common-crypto-impl/src/main/java/net/shibboleth/oidc/security/jose/impl/DefaultEncryptionParametersResolver.java
+++ b/oidc-common-crypto-impl/src/main/java/net/shibboleth/oidc/security/jose/impl/DefaultEncryptionParametersResolver.java
@@ -33,7 +33,8 @@ import org.opensaml.security.credential.Credential;
import org.opensaml.security.credential.CredentialResolver;
import org.opensaml.security.credential.CredentialSupport;
import org.opensaml.security.credential.UsageType;
-import org.opensaml.security.credential.criteria.impl.EvaluableUsageCredentialCriterion;
+import org.opensaml.security.credential.criteria.impl.EvaluableKeyAlgorithmCredentialCriterion;
+import org.opensaml.security.criteria.KeyAlgorithmCriterion;
import org.opensaml.security.criteria.UsageCriterion;
import org.opensaml.xmlsec.algorithm.AlgorithmRegistry;
import org.opensaml.xmlsec.algorithm.AlgorithmSupport;
@@ -43,14 +44,15 @@ import org.opensaml.xmlsec.impl.AlgorithmRuntimeSupportedPredicate;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
+import com.google.common.base.Strings;
import com.nimbusds.jose.Algorithm;
import com.nimbusds.jose.EncryptionMethod;
-import com.nimbusds.jose.JOSEException;
import com.nimbusds.jose.JWEAlgorithm;
+import net.shibboleth.oidc.security.CredentialConversionUtil;
import net.shibboleth.oidc.security.credential.JWKCredential;
-import net.shibboleth.oidc.security.credential.impl.JWKCredentialSupport;
-import net.shibboleth.oidc.security.impl.CredentialConversionUtil;
+import net.shibboleth.oidc.security.credential.impl.DataEncryptionAlgorithmCriterion;
+import net.shibboleth.oidc.security.credential.impl.KeyManagmentAlgorithmCriterion;
import net.shibboleth.oidc.security.jose.EncryptionConfiguration;
import net.shibboleth.oidc.security.jose.EncryptionParameters;
import net.shibboleth.oidc.security.jose.EncryptionParametersResolver;
@@ -62,7 +64,7 @@ import net.shibboleth.utilities.java.support.resolver.CriteriaSet;
import net.shibboleth.utilities.java.support.resolver.ResolverException;
/**
- * Basic implementation of an {@link EncryptionParametersResolver}. The resolver delegates much of its functionality
+ * Default implementation of an {@link EncryptionParametersResolver}. The resolver delegates much of its functionality
* to various lookup strategies and credential resolvers. Its main purpose is to compose the results.
*
* <p>The set of usable key transport and data encryption algorithms are determined by injected strategies. The set of
@@ -73,15 +75,13 @@ import net.shibboleth.utilities.java.support.resolver.ResolverException;
* <p>Once the set of algorithms and credentials have been looked up and resolved. The key transport algorithms are
* tried in the order they are specified until a suitable, compatible, credential is found. It is expected asymmetric
* encryption keys will be resolved from the OpenID Providers keyset document, and symmetric keys will be derived from
- * the client_secret (although any resolvers could be supplied, and hence this behaviour is not guranteed). </p>
+ * the client_secret (although any resolvers could be supplied, and hence this behaviour is not guaranteed). </p>
*
- * <p>Symmetric keys are expected to be returned in their original format. The resolver will derive the correct
- * symmetric key to add to the correct parameters e.g. for key wrapping and direct content encryption.</p>
+ * <p>Extra criterion are built and provided to the credential resolvers based on the key management mode described
+ * by the algorithms being tested.</p>
*
- * <p>Note: the criteria supplied to the credential resolvers should be relatively light on evaluable criterion.
- * For example, only containing the {@link EvaluableUsageCredentialCriterion} - alongside any non-evaluable
- * criterion needed by the resolvers. Most of the specific filtering e.g. algorithm and key length, is performed
- * by this resolver itself based on the logic described by the OpenID specifications.</p>
+ * <p>Symmetric keys are expected to be returned in their final format. For example, symmetric keys derived from the
+ * client_secret are expected to be in a key format ready for decryption.</p>
*
* <p>
* The following {@link net.shibboleth.utilities.java.support.resolver.Criterion} inputs are supported:
@@ -171,7 +171,6 @@ public class DefaultEncryptionParametersResolver extends AbstractSecurityParamet
algorithmRegistry = Constraint.isNotNull(registry, "AlgorithmRegistry was null");
}
- /** {@inheritDoc} */
@Override
@Nonnull public Iterable<EncryptionParameters> resolve(@Nonnull final CriteriaSet criteria)
throws ResolverException {
@@ -182,7 +181,6 @@ public class DefaultEncryptionParametersResolver extends AbstractSecurityParamet
return Collections.emptyList();
}
- /** {@inheritDoc} */
@Override
@Nullable public EncryptionParameters resolveSingle(@Nonnull final CriteriaSet criteria)
throws ResolverException {
@@ -211,7 +209,7 @@ public class DefaultEncryptionParametersResolver extends AbstractSecurityParamet
}
/**
- * Resolve and return the effective {@link CredentialResolver} used to encrypt content encryption keys.
+ * Resolve and return the effective {@link CredentialResolver} used to encrypt/wrap content encryption keys.
*
* @param criteria the input criteria being evaluated
* @return the effective resolver, or null
@@ -365,9 +363,7 @@ public class DefaultEncryptionParametersResolver extends AbstractSecurityParamet
criteria.add(new UsageCriterion(UsageType.ENCRYPTION));
}
- // Pre-resolve these for efficiency
- final List<Credential> keyTransportCredentials = getEffectiveKeyTransportCredentials(criteria);
- log.trace("Resolved {} key transport credentials", keyTransportCredentials.size());
+ // Determine the set of transport and content encryption algorithms from the lookup strategies
final List<String> keyTransportAlgorithms =
keyTransportEncryptionAlgorithmsLookupStrategy.apply(criteria, includeExcludePredicate);
log.trace("Resolved effective key transport algorithms: {}", keyTransportAlgorithms);
@@ -375,26 +371,16 @@ public class DefaultEncryptionParametersResolver extends AbstractSecurityParamet
final List<String> dataEncryptionAlgorithms = dataEncryptionAlgorithmsLookupStrategy.apply(criteria,
includeExcludePredicate);
log.trace("Resolved effective data encryption algorithms: {}", dataEncryptionAlgorithms);
- final List<Credential> dataEncryptionCredentials = getEffectiveDataEncryptionCredentials(criteria);
- log.trace("Resolved {} data encryption credentials", dataEncryptionCredentials.size());
+
resolveCredentialForSupportedAlgorithm(criteria,
convertStringAlgorithmURIsToJwkAlgorithms(keyTransportAlgorithms),
- convertStringEncryptionMethodURIsToEncryptionMethods(dataEncryptionAlgorithms),
- keyTransportCredentials, dataEncryptionCredentials, params);
+ convertStringEncryptionMethodURIsToEncryptionMethods(dataEncryptionAlgorithms), params);
}
/**
* Resolve a credential (key) compatible with one-of the supported algorithms. Algorithms are tried in the order
- * they appear in the list of keyTransportAlgorithms.
- *
- * <p>Symmetric key algorithms e.g. either for key wrapping or direct content encryption, are passed through a
- * key derivation function. It is therefore assumed the input shared secret is the original key e.g. the
- * raw client_secret.</p>
- *
- * <p>Keys for asymmetric key algorithms are added to the parameter context as is. It is assumed such keys
- * are taken from the OpenID Provider's keyset document, however any resolver can be used and hence there is
- * no guarantee of this.</p>
+ * they appear in the list of keyTransportAlgorithms (key management algorithms). The first compatible is returned.
*
* <p>The first key that is compatible with the key transport algorithm is returned. That is, if two or more
* keys support the same algorithm, the first key resolved will be returned. There is no guarantee which
@@ -408,122 +394,227 @@ public class DefaultEncryptionParametersResolver extends AbstractSecurityParamet
* @param dataEncryptionCredentials the list of local data encryption credentials
* @param params the encryption parameters to add the credential to
*/
- // Checkstyle: ParameterNumber|MethodLength|CyclomaticComplexity OFF
protected void resolveCredentialForSupportedAlgorithm(
@Nonnull final CriteriaSet criteria,
@Nonnull final List<JWEAlgorithm> keyTransportAlgorithms,
@Nonnull final List<EncryptionMethod> dataEncryptionAlgorithms,
- @Nonnull final List<Credential> keyTransportCredentials,
- @Nonnull final List<Credential> dataEncryptionCredentials,
@Nonnull final EncryptionParameters params) {
for (final JWEAlgorithm algorithm : keyTransportAlgorithms) {
if (JWEAlgorithm.DIR.equals(algorithm)) {
- // Direct content encryption requires a derived key
-
- final JWKCredential credential =
- findCredentialThatSupportsAlgorithm(dataEncryptionCredentials, algorithm);
-
- final EncryptionMethod encryptionMethod =
- findEncryptionMethodThatSupportsCredential(dataEncryptionAlgorithms, credential);
-
- final JWKCredential derivedCredential =
- deriveSymmetricKeyForAlgAndEnc(credential, algorithm, encryptionMethod);
-
- if (derivedCredential != null) {
- if (log.isDebugEnabled()) {
- log.debug("Derived key from '{}' for alg '{}' and enc '{}'",
- CredentialConversionUtil.resolveKid(credential),
- algorithm.getName(), encryptionMethod.getName());
- }
-
- params.setKeyTransportEncryptionAlgorithm(JWEAlgorithm.DIR.getName());
- params.setDataEncryptionCredential(derivedCredential);
- params.setDataEncryptionAlgorithm(encryptionMethod.getName());
- return;
- }
-
+ // Direct content encryption
+ if (buildDirectEncryptionParameters(params, criteria, dataEncryptionAlgorithms, algorithm)) {
+ return;
+ }
} else if (JWEAlgorithm.Family.AES_GCM_KW.contains(algorithm)
|| JWEAlgorithm.Family.AES_KW.contains(algorithm)) {
- // Key wrapping requires a derived key
-
- final JWKCredential credential =
- findCredentialThatSupportsAlgorithm(keyTransportCredentials, algorithm);
-
- final EncryptionMethod encryptionMethod =
- resolveEncryptionMethod(dataEncryptionAlgorithms);
-
- final JWKCredential derivedCredential =
- deriveSymmetricKeyForAlgAndEnc(credential, algorithm, encryptionMethod);
+ // Key wrapping
+ if (buildKeyWrappingParameters(params, criteria, dataEncryptionAlgorithms, algorithm)) {
+ return;
+ }
- if (derivedCredential != null) {
+ } else if (JWEAlgorithm.Family.ASYMMETRIC.contains(algorithm)){
+ // Supports key encryption, or key agreement.
+ if (buildKeyEncryptionOrAgreementParameters(params, criteria, dataEncryptionAlgorithms, algorithm)) {
+ return;
+ }
+ } else {
+ log.trace("Algorithm '{}' is not supported, moving on", algorithm);
+ }
+ }
+ }
+
+ /**
+ * Build direct encryption parameters from the data encryption credentials input.
+ *
+ * <p>Note, the symmetric key used is assumed —although not guaranteed— already appropriate for the cryptographic
+ * operation being performed. That is, if a client_secret, the resolvers will derive an appropriate key for the
+ * encryption algorithm used as no further derivation occurs here. </p>
+ *
+ * @param params the parameter context to stash the resolved encryption parameters
+ * @param dataEncryptionAlgorithms the data encryption algorithms
+ * @param dataEncryptionCredentials the data encryption credentials
+ * @param algorithm the direct encryption algorithm
+ */
+ private boolean buildDirectEncryptionParameters(@Nonnull final EncryptionParameters params,
+ @Nonnull final CriteriaSet criteria, @Nonnull final List<EncryptionMethod> dataEncryptionAlgorithms,
+ @Nonnull final JWEAlgorithm algorithm) {
+
+
+ for (final EncryptionMethod method : dataEncryptionAlgorithms) {
+
+ // Resolution must occur for each 'enc' method tested, as the derived direct encryption could be different
+ // for each.
+ final CriteriaSet credentialCriteria = buildEncryptionKeyAlgorithmCriteria(criteria, algorithm, method);
+
+ final List<Credential> dataEncryptionCredentials= getEffectiveDataEncryptionCredentials(credentialCriteria);
+ log.trace("Resolved {} possible direct encryption credential(s) for 'alg={}' and 'enc={}'",
+ dataEncryptionCredentials.size(), algorithm.getName(), method.getName());
+
+ for (final Credential credential : dataEncryptionCredentials) {
+
+ if (checkCredentialSupportsAlgorithm(credential, algorithm) &&
+ checkCredentialSupportsEncryptionMethod(credential, method)) {
if (log.isDebugEnabled()) {
- log.debug("Derived key from '{}' for alg '{}' and enc '{}'",
+ log.debug("Resolved key from '{}' for 'alg={}' and 'enc={}'",
CredentialConversionUtil.resolveKid(credential),
- algorithm.getName(), encryptionMethod.getName());
+ algorithm.getName(), method.getName());
}
- params.setKeyTransportEncryptionCredential(derivedCredential);
- params.setKeyTransportEncryptionAlgorithm(algorithm.getName());
- params.setDataEncryptionAlgorithm(encryptionMethod.getName());
- return;
- }
- } else if (JWEAlgorithm.Family.ASYMMETRIC.contains(algorithm)){
- // Supports key encryption, or key agreement.
- final JWKCredential credential =
- findCredentialThatSupportsAlgorithm(keyTransportCredentials, algorithm);
-
- final EncryptionMethod encryptionMethod =
- resolveEncryptionMethod(dataEncryptionAlgorithms);
-
- if (credential != null) {
-
+
+ params.setKeyTransportEncryptionAlgorithm(JWEAlgorithm.DIR.getName());
+ params.setDataEncryptionCredential(credential);
+ params.setDataEncryptionAlgorithm(method.getName());
+ return true;
+ }
+ }
+ }
+ return false;
+ }
+
+ /**
+ * Build key wrapping encryption parameters from the key transport encryption credentials input.
+ *
+ * <p>Note, the symmetric key used is assumed —although not guaranteed— already appropriate for the cryptographic
+ * operation being performed. That is, if a client_secret, the resolvers will derive an appropriate key for the
+ * key management algorithm used as no further derivation occurs here. </p>
+ *
+ * @param params the parameter context to stash the resolved encryption parameters
+ * @param dataEncryptionAlgorithms the data encryption algorithms
+ * @param keyTransportCredentials the key transport encryption credentials
+ * @param algorithm the key wrapping algorithm
+ */
+ private boolean buildKeyWrappingParameters(@Nonnull final EncryptionParameters params,
+ @Nonnull final CriteriaSet criteria, @Nonnull final List<EncryptionMethod> dataEncryptionAlgorithms,
+ @Nonnull final JWEAlgorithm algorithm) {
+
+
+ for (final EncryptionMethod method : dataEncryptionAlgorithms) {
+
+ final CriteriaSet credentialCriteria = buildKeyManagmentAlgorithmCriteria(criteria, algorithm, method);
+
+ final List<Credential> keyTransportCredentials = getEffectiveKeyTransportCredentials(credentialCriteria);
+ log.trace("Resolved {} possible key transport credentials for 'alg={}' and 'enc={}'",
+ keyTransportCredentials.size(), algorithm.getName(), method.getName());
+
+ for (final Credential credential : keyTransportCredentials) {
+
+ if (checkCredentialSupportsAlgorithm(credential, algorithm) &&
+ checkCredentialSupportsEncryptionMethod(credential, method)) {
if (log.isDebugEnabled()) {
- log.debug("Selected key '{}' for alg '{}' and enc '{}'",
+ log.debug("Resolved key from '{}' for 'alg={}' and 'enc={}'",
CredentialConversionUtil.resolveKid(credential),
- algorithm.getName(), encryptionMethod.getName());
+ algorithm.getName(), method.getName());
}
+
params.setKeyTransportEncryptionCredential(credential);
params.setKeyTransportEncryptionAlgorithm(algorithm.getName());
- params.setDataEncryptionAlgorithm(encryptionMethod.getName());
- return;
- }
- } else {
- log.trace("Algorithm '{}' is not supported, moving on", algorithm);
- }
+ params.setDataEncryptionAlgorithm(method.getName());
+ return true;
+ }
+ }
+ }
+ return false;
+ }
+
+ /**
+ * Build key encryption parameters from the key transport encryption credentials input.
+ *
+ * @param params the parameter context to stash the resolved encryption parameters
+ * @param dataEncryptionAlgorithms the data encryption algorithms
+ * @param algorithm the key encryption algorithm
+ */
+ private boolean buildKeyEncryptionOrAgreementParameters(@Nonnull final EncryptionParameters params,
+ @Nonnull final CriteriaSet criteria, @Nonnull final List<EncryptionMethod> dataEncryptionAlgorithms,
+ @Nonnull final JWEAlgorithm algorithm) {
+
+
+ final EncryptionMethod encryptionMethod = resolveEncryptionMethod(dataEncryptionAlgorithms);
+
+ final List<Credential> keyTransportCredentials = getEffectiveKeyTransportCredentials(
+ buildKeyManagmentAlgorithmCriteria(criteria, algorithm, encryptionMethod));
+
+ log.trace("Resolved {} possible key transport credentials for 'alg={}'",
+ keyTransportCredentials.size(), algorithm.getName());
+
+ for (final Credential credential : keyTransportCredentials) {
+
+ if (checkCredentialSupportsAlgorithm(credential, algorithm)) {
+ if (log.isDebugEnabled()) {
+ log.debug("Resolved key from '{}' for 'alg={}' and 'enc={}'",
+ CredentialConversionUtil.resolveKid(credential),
+ algorithm.getName(), encryptionMethod.getName());
+ }
+
+ params.setKeyTransportEncryptionCredential(credential);
+ params.setKeyTransportEncryptionAlgorithm(algorithm.getName());
+ params.setDataEncryptionAlgorithm(encryptionMethod.getName());
+ return true;
+ }
}
+ return false;
}
- // Checkstyle: ParameterNumber|MethodLength|CyclomaticComplexity ON
+
/**
- * Wrapper to
- * {@link JWKCredentialSupport#deriveSymmetricKeyForAlgAndEnc(JWKCredential, JWEAlgorithm, EncryptionMethod)}
- * which derives a *new* symmetric key credential suitable for the given 'alg' and 'enc' algorithms. Catches
- * and logs errors, returning {@literal null} on error.
+ * Build criterion for credential resolvers from the JWE 'alg' header. These describe the algorithm used to decrypt
+ * or determine the value of the content/data encryption key.
*
- * @param credential the credential that contains a secret key to derive a new credential from
- * @param alg the key management mode algorithm
- * @param enc the content encryption algorithm
+ * @param existingCriteria any existing criterion passed into this resolver.
+ * @param alg the JWE algorithm
+ * @param enc the JWE encryption algorithm
*
- * @return a *new* derived credential, or {@code null} if an error occurs
+ * @return a criteria set with algorithm specific criterion
*/
- @Nullable private JWKCredential deriveSymmetricKeyForAlgAndEnc(
- @Nullable final JWKCredential credential, @Nullable final JWEAlgorithm alg,
- @Nullable final EncryptionMethod enc) {
-
- try {
- return JWKCredentialSupport.deriveSymmetricKeyForAlgAndEnc(credential, alg, enc);
- } catch (final JOSEException e) {
- log.warn("Unable to generate secret key: {}", e.getMessage());
- return null;
+ private CriteriaSet buildKeyManagmentAlgorithmCriteria(@Nonnull final CriteriaSet existingCriteria,
+ @Nonnull final JWEAlgorithm alg, @Nonnull final EncryptionMethod enc) {
+
+ final CriteriaSet credentialCriteria = new CriteriaSet();
+ credentialCriteria.addAll(existingCriteria);
+
+ credentialCriteria.add(new KeyManagmentAlgorithmCriterion(alg.getName()));
+ credentialCriteria.add(new DataEncryptionAlgorithmCriterion(enc.getName()));
+
+ final String jcaKeyAlgorithm = AlgorithmSupport.getKeyAlgorithm(alg.getName());
+ if (!Strings.isNullOrEmpty(jcaKeyAlgorithm)) {
+ credentialCriteria.add(new EvaluableKeyAlgorithmCredentialCriterion(
+ new KeyAlgorithmCriterion(jcaKeyAlgorithm)));
}
+ return credentialCriteria;
+
+ }
+ /**
+ * Build criterion for credential resolvers from the JWE 'enc' header. These describe the content encryption
+ * algorithm used to decrypt the cipher text inside the JWE.
+ *
+ * @param existingCriteria any existing criterion passed into this resolver.
+ * @param alg the JWE algorithm
+ * @param enc the JWE encryption algorithm
+ *
+ * @return a criteria set with algorithm specific criterion
+ */
+ private CriteriaSet buildEncryptionKeyAlgorithmCriteria(@Nonnull final CriteriaSet existingCriteria,
+ @Nonnull final JWEAlgorithm alg, @Nonnull final EncryptionMethod enc) {
+
+ final CriteriaSet credentialCriteria = new CriteriaSet();
+ credentialCriteria.addAll(existingCriteria);
+
+ credentialCriteria.add(new KeyManagmentAlgorithmCriterion(alg.getName()));
+ credentialCriteria.add(new DataEncryptionAlgorithmCriterion(enc.getName()));
+
+ final String jcaEncAlgorithm = AlgorithmSupport.getKeyAlgorithm(enc.getName());
+ if (!Strings.isNullOrEmpty(jcaEncAlgorithm)) {
+ credentialCriteria.add(new EvaluableKeyAlgorithmCredentialCriterion(
+ new KeyAlgorithmCriterion(jcaEncAlgorithm)));
+ }
+ return credentialCriteria;
+
}
-
/**
- * Determine if any of the given credentials match the given algorithm.
+ * Determine if the given credential matches the given algorithm.
*
- * <p>For a credential to be returned, it must meet the following criteria:</p>
+ * <p>For a credential to match, it must meet the following criteria:</p>
* <ol>
* <li>The credential must be a {@link JWKCredential}</li>
* <li>The credential must have a {@link UsageType} of {@link UsageType#ENCRYPTION}
@@ -533,33 +624,53 @@ public class DefaultEncryptionParametersResolver extends AbstractSecurityParamet
* <li>The credential's key must match the keylength required by that algorithm</li>
* </ol>
*
- * <p>The first key that is compatible with the algorithm is returned. That is, if two or more keys
- * support the same algorithm, the first key in the local credentials list
- * will be returned. There is no guarantee which key that is.</p>
- *
- * @param credentials the credentials to match against the algorithm
- * @param algorithm the algorithm to locate a credential for
+ * @param credential the credential to match against the algorithm
+ * @param algorithm the algorithm the credential must support
*
- * @return the first credential that matches the algorithm, {@literal null} otherwise.
+ * @return true if the credential supports the given algorithm, false otherwise
*/
- //TODO the keys should already match the ENC usage, so that should be a redundant check
- //TODO maybe this logic could be build into EvaluableCriterion for the resolvers.
- @Nullable protected JWKCredential findCredentialThatSupportsAlgorithm(@Nonnull final List<Credential> credentials,
+ protected boolean checkCredentialSupportsAlgorithm(@Nonnull final Credential credential,
@Nonnull final JWEAlgorithm algorithm) {
- return credentials.stream()
- .filter(Objects::nonNull)
- .filter(JWKCredential.class::isInstance)
- .filter(k -> UsageType.ENCRYPTION == k.getUsageType() || UsageType.UNSPECIFIED == k.getUsageType())
- .map(JWKCredential.class::cast)
- .filter(k -> checkKeyWithAlgorithm(k, algorithm))
- .filter(k -> checkKeyAlgorithmAndLength(k, algorithm.getName()))
- .findFirst().orElse(null);
+
+ if (!(credential instanceof JWKCredential)) {
+ return false;
+ }
+ if (credential.getUsageType() != UsageType.ENCRYPTION && credential.getUsageType() != UsageType.UNSPECIFIED) {
+ return false;
+ }
+ if (!checkKeyWithAlgorithm((JWKCredential)credential, algorithm)) {
+ return false;
+ }
+ if (!checkKeyAlgorithmAndLength(credential, algorithm.getName())) {
+ return false;
+ }
+ return true;
+ }
+
+ /**
+ * Determine if the given credential supports the given encryption method.
+ *
+ * <p>For a credential to match, it must meet the following criteria:</p>
+ * <ol>
+ * <li>The credential's key algorithm and key length must match that required by the encryption algorithm given</li>
+ * </ol>
+ *
+ * @param credential the credential to match against the algorithm
+ * @param encMethod the encryption algorithm the credential must support
+ *
+ * @return true if the credential supports the given algorithm, false otherwise
+ */
+ protected boolean checkCredentialSupportsEncryptionMethod(@Nonnull final Credential credential,
+ @Nonnull final EncryptionMethod encMethod) {
+
+ final Key key = CredentialSupport.extractEncryptionKey(credential);
+ return AlgorithmSupport.checkKeyAlgorithmAndLength(key, getAlgorithmRegistry().get(encMethod.getName()));
}
/**
- * Check the credential supports the algorithm given. If the algorithm is present, check that is
- * identical to the algorithm supplied. If not, check the key algorithm is compatible with the algorithm
- * family.
+ * Check the credential supports the algorithm given. If the exact algorithm the key supports is present, check
+ * that is identical to the algorithm supplied. If not, check the key algorithm is generally compatible with the
+ * algorithm family.
*
* @param credential the credential to check
* @param algorithm the algorithm to check compatibility with
@@ -585,33 +696,9 @@ public class DefaultEncryptionParametersResolver extends AbstractSecurityParamet
return false;
}
-
- /**
- * Find an encryption method that is supported by the credential. That is, supports the algorithm and
- * has the correct key length.
- *
- * @param dataEncryptionAlgorithms the data encryption algorithms
- * @param credential the credential to test
- *
- * @return the first supported encryption method, {@literal null} otherwise.
- */
- @Nullable private EncryptionMethod findEncryptionMethodThatSupportsCredential(
- @Nonnull final List<EncryptionMethod> dataEncryptionAlgorithms,
- @Nonnull final Credential credential) {
-
- final Key key = CredentialSupport.extractEncryptionKey(credential);
-
- for (final EncryptionMethod method : dataEncryptionAlgorithms) {
- if (AlgorithmSupport.checkKeyAlgorithmAndLength(key, getAlgorithmRegistry().get(method.getName()))) {
- return method;
- }
- }
- return null;
-
- }
/**
- * Get the effective list of data encryption credentials to consider.
+ * Get the effective list of data/content encryption credentials to consider.
*
* @param criteria the input criteria being evaluated
*
@@ -673,7 +760,7 @@ public class DefaultEncryptionParametersResolver extends AbstractSecurityParamet
}
/**
- * Convert the algorithms represented as strings, into Nimbus {@link Algorithm}s for later comparison.
+ * Convert the algorithms represented as Strings into Nimbus {@link Algorithm}s for later comparison.
* This will preserve the order of the original list ({@link List} is ordered).
*
* @param algos the algorithms to convert
@@ -685,7 +772,7 @@ public class DefaultEncryptionParametersResolver extends AbstractSecurityParamet
}
/**
- * Convert the encryption methods represented as strings, into Nimbus {@link EncryptionMethod}s for later
+ * Convert the encryption methods represented as Strings into Nimbus {@link EncryptionMethod}s for later
* comparison. This will preserve the order of the original list ({@link List} is ordered).
*
* @param encMethods the encryption methods to convert
@@ -741,7 +828,12 @@ public class DefaultEncryptionParametersResolver extends AbstractSecurityParamet
return false;
}
- return AlgorithmSupport.checkKeyAlgorithmAndLength(key, getAlgorithmRegistry().get(algorithm));
+ final boolean valid = AlgorithmSupport.checkKeyAlgorithmAndLength(key, getAlgorithmRegistry().get(algorithm));
+ if (!valid) {
+ log.trace("Key '{}' does not match algorithm and key length requirement for '{}'",
+ CredentialConversionUtil.resolveKid(credential), algorithm);
+ }
+ return valid;
}
diff --git a/oidc-common-crypto-impl/src/test/java/net/shibboleth/oidc/security/credential/impl/ClientSecretCriterionCredentialResolverTest.java b/oidc-common-crypto-impl/src/test/java/net/shibboleth/oidc/security/credential/impl/ClientSecretCriterionCredentialResolverTest.java
new file mode 100644
index 0000000..6021c42
--- /dev/null
+++ b/oidc-common-crypto-impl/src/test/java/net/shibboleth/oidc/security/credential/impl/ClientSecretCriterionCredentialResolverTest.java
@@ -0,0 +1,227 @@
+
+package net.shibboleth.oidc.security.credential.impl;
+
+import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.assertFalse;
+import static org.testng.Assert.assertNotNull;
+import static org.testng.Assert.assertTrue;
+
+import java.time.Instant;
+import java.util.Date;
+import java.util.List;
+
+import javax.crypto.SecretKey;
+
+import org.opensaml.security.credential.Credential;
+import org.opensaml.security.credential.UsageType;
+import org.testng.annotations.Test;
+
+import com.nimbusds.jose.EncryptionMethod;
+import com.nimbusds.jose.JOSEException;
+import com.nimbusds.jose.JOSEObjectType;
+import com.nimbusds.jose.JWEAlgorithm;
+import com.nimbusds.jose.JWEHeader;
+import com.nimbusds.jose.JWEObject;
+import com.nimbusds.jose.JWEObject.State;
+import com.nimbusds.jose.JWSAlgorithm;
+import com.nimbusds.jose.JWSHeader;
+import com.nimbusds.jose.KeyLengthException;
+import com.nimbusds.jose.Payload;
+import com.nimbusds.jose.crypto.AESDecrypter;
+import com.nimbusds.jose.crypto.AESEncrypter;
+import com.nimbusds.jose.crypto.MACSigner;
+import com.nimbusds.jwt.EncryptedJWT;
+import com.nimbusds.jwt.JWTClaimsSet;
+import com.nimbusds.jwt.SignedJWT;
+import com.nimbusds.oauth2.sdk.auth.Secret;
+import com.nimbusds.oauth2.sdk.jose.SecretKeyDerivation;
+
+import net.shibboleth.oidc.security.credential.DefaultClientSecretCredential;
+import net.shibboleth.oidc.security.jose.criterion.ClientSecretCredentialCriterion;
+import net.shibboleth.utilities.java.support.resolver.CriteriaSet;
+import net.shibboleth.utilities.java.support.resolver.ResolverException;
+
+/** Tests for {@link ClientSecretCriterionCredentialResolver}. */
+public class ClientSecretCriterionCredentialResolverTest {
+
+ private static final String CLIENT_SECRET = "aPdSgVkXp2s5v8y/B?E(H+MbQeThWmZq";
+
+ /** Resolver to test. */
+ private ClientSecretCriterionCredentialResolver resolver;
+
+ @Test
+ public void testResolveSigningKey() throws ResolverException {
+ resolver = new ClientSecretCriterionCredentialResolver(UsageType.SIGNING);
+
+ final CriteriaSet set = new CriteriaSet();
+ set.add(new ClientSecretCredentialCriterion(new DefaultClientSecretCredential(CLIENT_SECRET)));
+ final Iterable<Credential> resolvedCredentials = resolver.resolve(set);
+
+ assertNotNull(resolvedCredentials);
+ assertTrue(resolvedCredentials.iterator().hasNext());
+ final Credential cred = resolvedCredentials.iterator().next();
+ assertNotNull(cred);
+ assertNotNull(cred.getSecretKey());
+ assertEquals(cred.getSecretKey().getAlgorithm(), "NONE");
+ assertEquals(cred.getSecretKey().getEncoded().length, 32);
+ assertEquals(cred.getUsageType(), UsageType.SIGNING);
+
+ }
+
+ @Test(expectedExceptions = ResolverException.class)
+ public void testResolveIncompatibleUsageType() throws ResolverException {
+ resolver = new ClientSecretCriterionCredentialResolver(UsageType.UNSPECIFIED);
+
+ final CriteriaSet set = new CriteriaSet();
+ set.add(new ClientSecretCredentialCriterion(new DefaultClientSecretCredential(CLIENT_SECRET)));
+ set.add(new KeyManagmentAlgorithmCriterion(JWEAlgorithm.A128KW.getName()));
+ set.add(new DataEncryptionAlgorithmCriterion(EncryptionMethod.A128CBC_HS256.getName()));
+ final Iterable<Credential> resolvedCredentials = resolver.resolve(set);
+
+ }
+
+ @Test(expectedExceptions = ResolverException.class)
+ public void testResolveNoKeyAlogrithmCriterion() throws ResolverException {
+ resolver = new ClientSecretCriterionCredentialResolver(UsageType.ENCRYPTION);
+
+ final CriteriaSet set = new CriteriaSet();
+ set.add(new ClientSecretCredentialCriterion(new DefaultClientSecretCredential(CLIENT_SECRET)));
+
+ set.add(new DataEncryptionAlgorithmCriterion(EncryptionMethod.A128CBC_HS256.getName()));
+ final Iterable<Credential> resolvedCredentials = resolver.resolve(set);
+
+ }
+
+ @Test(expectedExceptions = ResolverException.class)
+ public void testResolveNoDataEncryptionAlogrithmCriterion() throws ResolverException {
+ resolver = new ClientSecretCriterionCredentialResolver(UsageType.ENCRYPTION);
+
+ final CriteriaSet set = new CriteriaSet();
+ set.add(new ClientSecretCredentialCriterion(new DefaultClientSecretCredential(CLIENT_SECRET)));
+ set.add(new KeyManagmentAlgorithmCriterion(JWEAlgorithm.A128KW.getName()));
+ final Iterable<Credential> resolvedCredentials = resolver.resolve(set);
+
+ }
+
+ @Test
+ public void testResolveKeyWrappingKey() throws ResolverException {
+ resolver = new ClientSecretCriterionCredentialResolver(UsageType.ENCRYPTION);
+
+ final CriteriaSet set = new CriteriaSet();
+ set.add(new ClientSecretCredentialCriterion(new DefaultClientSecretCredential(CLIENT_SECRET)));
+ set.add(new KeyManagmentAlgorithmCriterion(JWEAlgorithm.A128KW.getName()));
+ set.add(new DataEncryptionAlgorithmCriterion(EncryptionMethod.A128CBC_HS256.getName()));
+ final Iterable<Credential> resolvedCredentials = resolver.resolve(set);
+
+ assertNotNull(resolvedCredentials);
+ assertTrue(resolvedCredentials.iterator().hasNext());
+ final Credential cred = resolvedCredentials.iterator().next();
+ assertNotNull(cred);
+ assertNotNull(cred.getSecretKey());
+ assertEquals(cred.getSecretKey().getAlgorithm(), "AES");
+ assertEquals(cred.getSecretKey().getEncoded().length, 16);
+ assertEquals(cred.getUsageType(), UsageType.ENCRYPTION);
+
+ }
+
+ /* Test the derived key is indeed compatible with a derived decryption key.*/
+ @Test
+ public void testResolveKeyWrappingKey_Decrypts() throws Exception {
+
+
+ final JWEObject jweObject =
+ new JWEObject(new JWEHeader.Builder(JWEAlgorithm.A128KW, EncryptionMethod.A128GCM)
+ .contentType("JWT")
+ .keyID("mock-key")
+ .build(),
+ new Payload(createdSignedJWT()));
+
+ resolver = new ClientSecretCriterionCredentialResolver(UsageType.ENCRYPTION);
+
+ final CriteriaSet set = new CriteriaSet();
+ set.add(new ClientSecretCredentialCriterion(new DefaultClientSecretCredential(CLIENT_SECRET)));
+ set.add(new KeyManagmentAlgorithmCriterion(JWEAlgorithm.A128KW.getName()));
+ set.add(new DataEncryptionAlgorithmCriterion(EncryptionMethod.A128GCM.getName()));
+ final Iterable<Credential> resolvedCredentials = resolver.resolve(set);
+
+ assertNotNull(resolvedCredentials);
+ assertTrue(resolvedCredentials.iterator().hasNext());
+ final Credential cred = resolvedCredentials.iterator().next();
+ assertNotNull(cred);
+ assertNotNull(cred.getSecretKey());
+ assertEquals(cred.getSecretKey().getAlgorithm(), "AES");
+ assertEquals(cred.getSecretKey().getEncoded().length, 16);
+ assertEquals(cred.getUsageType(), UsageType.ENCRYPTION);
+
+ jweObject.encrypt(new AESEncrypter(cred.getSecretKey()));
+ final EncryptedJWT jwe = EncryptedJWT.parse(jweObject.serialize());
+
+ final SecretKey key = SecretKeyDerivation.deriveSecretKey(new Secret(CLIENT_SECRET), JWEAlgorithm.A128KW,
+ EncryptionMethod.A128GCM);
+
+ jwe.decrypt(new AESDecrypter(key));
+ assertTrue(jwe.getState() == State.DECRYPTED);
+ final SignedJWT jws =jwe.getPayload().toSignedJWT();
+ assertEquals(jws.getJWTClaimsSet().getSubject(), "jdoe");
+
+ }
+
+ private SignedJWT createdSignedJWT() throws KeyLengthException, JOSEException {
+ final var header = new JWSHeader.Builder(JWSAlgorithm.HS256)
+ .type(JOSEObjectType.JWT)
+ .keyID("mock-key")
+ .build();
+ final var signedJWT = new SignedJWT(header,createClaims());
+ signedJWT.sign(new MACSigner(CLIENT_SECRET));
+ return signedJWT;
+ }
+
+ private JWTClaimsSet createClaims() {
+ return new JWTClaimsSet.Builder()
+ .issuer("https://localhost:9918")
+ .audience(List.of("test-client"))
+ .subject("jdoe")
+ .claim("nonce", "abadnonce")
+ .claim("azp", "test-client")
+ .claim("name","jdoe")
+ .expirationTime(Date.from(Instant.now().plusSeconds(120)))
+ .build();
+ }
+
+ @Test
+ public void testResolveDirectEncryptionKey() throws ResolverException {
+ resolver = new ClientSecretCriterionCredentialResolver(UsageType.ENCRYPTION);
+
+ final CriteriaSet set = new CriteriaSet();
+ set.add(new ClientSecretCredentialCriterion(new DefaultClientSecretCredential(CLIENT_SECRET)));
+ set.add(new KeyManagmentAlgorithmCriterion(JWEAlgorithm.DIR.getName()));
+ set.add(new DataEncryptionAlgorithmCriterion(EncryptionMethod.A128CBC_HS256.getName()));
+ final Iterable<Credential> resolvedCredentials = resolver.resolve(set);
+
+ assertNotNull(resolvedCredentials);
+ assertTrue(resolvedCredentials.iterator().hasNext());
+ final Credential cred = resolvedCredentials.iterator().next();
+ assertNotNull(cred);
+ assertNotNull(cred.getSecretKey());
+ assertEquals(cred.getSecretKey().getEncoded().length, 32);
+ assertEquals(cred.getSecretKey().getAlgorithm(), "AES");
+ assertEquals(cred.getUsageType(), UsageType.ENCRYPTION);
+
+ }
+
+ /* Should fail, as asymmetric key can not be created from client_secret.*/
+ @Test
+ public void testIncompatibleAlg() throws ResolverException {
+ resolver = new ClientSecretCriterionCredentialResolver(UsageType.ENCRYPTION);
+
+ final CriteriaSet set = new CriteriaSet();
+ set.add(new ClientSecretCredentialCriterion(new DefaultClientSecretCredential(CLIENT_SECRET)));
+ set.add(new KeyManagmentAlgorithmCriterion(JWEAlgorithm.RSA_OAEP_256.getName()));
+ set.add(new DataEncryptionAlgorithmCriterion(EncryptionMethod.A128CBC_HS256.getName()));
+ final Iterable<Credential> resolvedCredentials = resolver.resolve(set);
+
+ assertNotNull(resolvedCredentials);
+ assertFalse(resolvedCredentials.iterator().hasNext());
+ }
+
+}
diff --git a/oidc-common-crypto-impl/src/test/java/net/shibboleth/oidc/security/impl/EncryptJWTHandlerTest.java b/oidc-common-crypto-impl/src/test/java/net/shibboleth/oidc/security/impl/EncryptJWTHandlerTest.java
index e6c363e..2646f8a 100644
--- a/oidc-common-crypto-impl/src/test/java/net/shibboleth/oidc/security/impl/EncryptJWTHandlerTest.java
+++ b/oidc-common-crypto-impl/src/test/java/net/shibboleth/oidc/security/impl/EncryptJWTHandlerTest.java
@@ -31,6 +31,7 @@ import org.opensaml.messaging.handler.MessageHandlerException;
import org.testng.annotations.BeforeMethod;
import org.testng.annotations.Test;
+import com.nimbusds.jose.EncryptionMethod;
import com.nimbusds.jose.JWEAlgorithm;
import com.nimbusds.jose.JWEObject.State;
import com.nimbusds.jose.Payload;
@@ -224,7 +225,8 @@ public class EncryptJWTHandlerTest extends AbstractHandlerTest {
params.setKeyTransportEncryptionAlgorithm(KeyManagementConstants.ALGO_ID_ALG_AES_256_KW);
final var kwCred = TestCredentialHelper.createClientSecretCredential(CLIENT_SECRET);
- params.setKeyTransportEncryptionCredential(kwCred);
+ final var derivedKey = kwCred.toEncryptionCredential(JWEAlgorithm.A256KW, EncryptionMethod.A256GCM);
+ params.setKeyTransportEncryptionCredential(derivedKey);
secParamCtx.setEncryptionParameters(params);
@@ -238,7 +240,7 @@ public class EncryptJWTHandlerTest extends AbstractHandlerTest {
assertTrue(jwt instanceof EncryptedJWT);
final var encryptedJWT = (EncryptedJWT)jwt;
- final AESDecrypter testDecrypter = new AESDecrypter(kwCred.getSecretKey());
+ final AESDecrypter testDecrypter = new AESDecrypter(derivedKey.getSecretKey());
encryptedJWT.decrypt(testDecrypter);
assertStandardClaimsExist(encryptedJWT);
diff --git a/oidc-common-crypto-impl/src/test/java/net/shibboleth/oidc/security/impl/ExplicitKeySignedJWTTrustEngineTest.java b/oidc-common-crypto-impl/src/test/java/net/shibboleth/oidc/security/impl/ExplicitKeySignedJWTTrustEngineTest.java
index eced91a..5112c6a 100644
--- a/oidc-common-crypto-impl/src/test/java/net/shibboleth/oidc/security/impl/ExplicitKeySignedJWTTrustEngineTest.java
+++ b/oidc-common-crypto-impl/src/test/java/net/shibboleth/oidc/security/impl/ExplicitKeySignedJWTTrustEngineTest.java
@@ -151,8 +151,7 @@ public class ExplicitKeySignedJWTTrustEngineTest {
public Credential resolveSingle(final CriteriaSet criteria) throws ResolverException {
try {
return TestCredentialHelper
- .createSharedSecretCredential("mockKey", CLIENT_SECRET,
- JWSAlgorithm.HS256, UsageType.SIGNING);
+ .createClientSecretCredential(CLIENT_SECRET).toSigningCredential();
} catch (final KeyException e) {
fail(e.getMessage());
return null;
diff --git a/oidc-common-crypto-impl/src/test/java/net/shibboleth/oidc/security/impl/OIDCTokenDecrypterTest.java b/oidc-common-crypto-impl/src/test/java/net/shibboleth/oidc/security/impl/JWETokenDecrypterTest.java
similarity index 80%
rename from oidc-common-crypto-impl/src/test/java/net/shibboleth/oidc/security/impl/OIDCTokenDecrypterTest.java
rename to oidc-common-crypto-impl/src/test/java/net/shibboleth/oidc/security/impl/JWETokenDecrypterTest.java
index 41c5bc1..faee700 100644
--- a/oidc-common-crypto-impl/src/test/java/net/shibboleth/oidc/security/impl/OIDCTokenDecrypterTest.java
+++ b/oidc-common-crypto-impl/src/test/java/net/shibboleth/oidc/security/impl/JWETokenDecrypterTest.java
@@ -6,6 +6,9 @@ import static org.testng.Assert.fail;
import java.nio.charset.StandardCharsets;
import java.security.KeyException;
+import java.security.KeyPair;
+import java.security.KeyPairGenerator;
+import java.security.NoSuchAlgorithmException;
import java.security.interfaces.RSAPublicKey;
import java.text.ParseException;
import java.time.Instant;
@@ -14,7 +17,9 @@ import java.util.Date;
import java.util.List;
import org.opensaml.core.config.InitializationException;
+import org.opensaml.security.credential.BasicCredential;
import org.opensaml.security.credential.Credential;
+import org.opensaml.security.credential.UsageType;
import org.opensaml.security.credential.impl.AbstractCriteriaFilteringCredentialResolver;
import org.opensaml.security.crypto.KeySupport;
import org.opensaml.xmlsec.config.GlobalAlgorithmRegistryInitializer;
@@ -50,18 +55,18 @@ import com.nimbusds.jwt.JWT;
import com.nimbusds.jwt.JWTClaimsSet;
import com.nimbusds.jwt.SignedJWT;
+import net.shibboleth.oidc.security.credential.BasicExpiringJWKCredential;
import net.shibboleth.oidc.security.credential.BasicJWKCredential;
import net.shibboleth.oidc.security.credential.JOSEObjectCredentialResolver;
import net.shibboleth.oidc.security.credential.JWKCredential;
-import net.shibboleth.oidc.security.credential.impl.JWKCredentialSupport;
import net.shibboleth.oidc.security.jose.DecryptionParameters;
import net.shibboleth.utilities.java.support.resolver.CriteriaSet;
import net.shibboleth.utilities.java.support.resolver.ResolverException;
-/** Tests for the {@link OIDCTokenDecrypter}.*/
-public class OIDCTokenDecrypterTest {
+/** Tests for the {@link JWETokenDecrypter}.*/
+public class JWETokenDecrypterTest {
- private OIDCTokenDecrypter decrypter;
+ private JWETokenDecrypter decrypter;
private static final String CLIENT_SECRET = "Xp2s5v8y/B?E(H+MbQeThWmYq3t6w9z$";
@@ -111,7 +116,7 @@ public class OIDCTokenDecrypterTest {
jweObject.encrypt(new PasswordBasedEncrypter(CLIENT_SECRET.getBytes(StandardCharsets.UTF_8),8,1000));
final EncryptedJWT jwe = EncryptedJWT.parse(jweObject.serialize());
- decrypter = new OIDCTokenDecrypter(new DecryptionParameters());
+ decrypter = new JWETokenDecrypter(new DecryptionParameters());
decrypter.decrypt(jwe);
}
@@ -121,12 +126,11 @@ public class OIDCTokenDecrypterTest {
final JWEObject jweObject =
new JWEObject(new JWEHeader.Builder(JWEAlgorithm.A256KW, EncryptionMethod.A256GCM)
.contentType("JWT")
- .keyID("mock-key")
+ .keyID("client_secret_credential")
.build(),
new Payload(createdSignedJWT()));
- final JWKCredential cred = JWKCredentialSupport.deriveSymmetricKeyForAlgAndEnc(
- TestCredentialHelper.createClientSecretCredential(CLIENT_SECRET), JWEAlgorithm.DIR,
- EncryptionMethod.A256GCM);
+ final JWKCredential cred = TestCredentialHelper.createClientSecretCredential(CLIENT_SECRET)
+ .toEncryptionCredential(JWEAlgorithm.DIR, EncryptionMethod.A256GCM);
jweObject.encrypt(new AESEncrypter(cred.getSecretKey()));
final EncryptedJWT jwe = EncryptedJWT.parse(jweObject.serialize());
@@ -135,17 +139,13 @@ public class OIDCTokenDecrypterTest {
@Override
public Credential resolveSingle(final CriteriaSet criteria) throws ResolverException {
- final BasicJWKCredential jwkCredential = new BasicJWKCredential();
- jwkCredential.setAlgorithm(JWEAlgorithm.A256KW);
- jwkCredential.getKeyNames().add("mock-key");
- jwkCredential.setKid("mock-key");
try {
- jwkCredential.setSecretKey(KeySupport.decodeSecretKey(
- JWSAssemblyUtils.getSecretBytes(CLIENT_SECRET), "AES"));
- } catch (final KeyException e) {
- throw new ResolverException(e);
- }
- return jwkCredential;
+ return TestCredentialHelper.createClientSecretCredential(CLIENT_SECRET)
+ .toEncryptionCredential(JWEAlgorithm.DIR, EncryptionMethod.A256GCM);
+ } catch (KeyException | JOSEException e) {
+ fail();
+ return null;
+ }
}
@Override
@@ -153,7 +153,7 @@ public class OIDCTokenDecrypterTest {
return List.of(resolveSingle(criteria));
}
});
- decrypter = new OIDCTokenDecrypter(params);
+ decrypter = new JWETokenDecrypter(params);
final JWT decryptedJWE = decrypter.decrypt(jwe);
assertTrue(jwe.getState() == State.DECRYPTED);
assertTrue(decryptedJWE instanceof SignedJWT);
@@ -166,24 +166,63 @@ public class OIDCTokenDecrypterTest {
final JWEObject jweObject =
new JWEObject(new JWEHeader.Builder(JWEAlgorithm.A256KW, EncryptionMethod.A256GCM)
.contentType("JWT")
- .keyID("mock-key")
+ .keyID("client_secret_credential")
.build(),
new Payload(createdSignedJWT()));
- final JWKCredential cred = JWKCredentialSupport.deriveSymmetricKeyForAlgAndEnc(
- TestCredentialHelper.createClientSecretCredential(CLIENT_SECRET), JWEAlgorithm.DIR,
- EncryptionMethod.A256GCM);
+ final JWKCredential cred = TestCredentialHelper.createClientSecretCredential(CLIENT_SECRET)
+ .toEncryptionCredential(JWEAlgorithm.DIR, EncryptionMethod.A256GCM);
jweObject.encrypt(new AESEncrypter(cred.getSecretKey()));
final EncryptedJWT jwe = EncryptedJWT.parse(jweObject.serialize());
final var params = new DecryptionParameters();
params.setKEKCredentialResolver(new MockKeyWrapCriteriaFilteringCredentialResolver());
- decrypter = new OIDCTokenDecrypter(params);
+ decrypter = new JWETokenDecrypter(params);
final JWT decryptedJWE = decrypter.decrypt(jwe);
assertTrue(jwe.getState() == State.DECRYPTED);
assertTrue(decryptedJWE instanceof SignedJWT);
assertEquals(decryptedJWE.getJWTClaimsSet().getSubject(), "jdoe");
}
+ @Test(expectedExceptions = DecryptionException.class)
+ void testDecryptionByKeyWrapping_WrongCredentialType() throws Exception {
+
+ final JWEObject jweObject =
+ new JWEObject(new JWEHeader.Builder(JWEAlgorithm.A256KW, EncryptionMethod.A256GCM)
+ .contentType("JWT")
+ .keyID("client_secret_credential")
+ .build(),
+ new Payload(createdSignedJWT()));
+ final JWKCredential cred = TestCredentialHelper.createClientSecretCredential(CLIENT_SECRET)
+ .toEncryptionCredential(JWEAlgorithm.DIR, EncryptionMethod.A256GCM);
+ jweObject.encrypt(new AESEncrypter(cred.getSecretKey()));
+ final EncryptedJWT jwe = EncryptedJWT.parse(jweObject.serialize());
+
+ final var params = new DecryptionParameters();
+ params.setKEKCredentialResolver(new JOSEObjectCredentialResolver() {
+
+ @Override
+ public Credential resolveSingle(final CriteriaSet criteria) throws ResolverException {
+ try {
+ final KeyPairGenerator generator = KeyPairGenerator.getInstance("RSA");
+ generator.initialize(2048);
+ final KeyPair keyPair = generator.generateKeyPair();
+ return new BasicCredential(keyPair.getPublic(), keyPair.getPrivate());
+ } catch (final NoSuchAlgorithmException e) {
+ fail();
+ return null;
+ }
+ }
+
+ @Override
+ public Iterable<Credential> resolve(final CriteriaSet criteria) throws ResolverException {
+ return List.of(resolveSingle(criteria));
+ }
+ });
+ decrypter = new JWETokenDecrypter(params);
+ final JWT decryptedJWE = decrypter.decrypt(jwe);
+
+ }
+
@Test
void testDecryptionByDirectEncryption() throws Exception {
@@ -195,9 +234,9 @@ public class OIDCTokenDecrypterTest {
new Payload(createdSignedJWT()));
- final JWKCredential cred = JWKCredentialSupport.deriveSymmetricKeyForAlgAndEnc(
- TestCredentialHelper.createClientSecretCredential(CLIENT_SECRET), JWEAlgorithm.DIR,
- EncryptionMethod.A256GCM);
+ final JWKCredential cred = TestCredentialHelper.createClientSecretCredential(CLIENT_SECRET)
+ .toEncryptionCredential(JWEAlgorithm.DIR, EncryptionMethod.A256GCM);
+
jweObject.encrypt(new DirectEncrypter(cred.getSecretKey()));
final EncryptedJWT jwe = EncryptedJWT.parse(jweObject.serialize());
@@ -206,17 +245,13 @@ public class OIDCTokenDecrypterTest {
@Override
public Credential resolveSingle(final CriteriaSet criteria) throws ResolverException {
- final BasicJWKCredential jwkCredential = new BasicJWKCredential();
- jwkCredential.setAlgorithm(JWEAlgorithm.DIR);
- jwkCredential.getKeyNames().add("mock-key");
- jwkCredential.setKid("mock-key");
try {
- jwkCredential.setSecretKey(KeySupport.decodeSecretKey(
- JWSAssemblyUtils.getSecretBytes(CLIENT_SECRET), "AES"));
- } catch (final KeyException e) {
- throw new ResolverException(e);
- }
- return jwkCredential;
+ return TestCredentialHelper.createClientSecretCredential(CLIENT_SECRET)
+ .toEncryptionCredential(JWEAlgorithm.DIR, EncryptionMethod.A256GCM);
+ } catch (KeyException | JOSEException e) {
+ fail();
+ return null;
+ }
}
@Override
@@ -224,13 +259,52 @@ public class OIDCTokenDecrypterTest {
return List.of(resolveSingle(criteria));
}
});
- decrypter = new OIDCTokenDecrypter(params);
+ decrypter = new JWETokenDecrypter(params);
final JWT decryptedJWE = decrypter.decrypt(jwe);
assertTrue(jwe.getState() == State.DECRYPTED);
assertTrue(decryptedJWE instanceof SignedJWT);
assertEquals(decryptedJWE.getJWTClaimsSet().getSubject(), "jdoe");
}
+ @Test(expectedExceptions = DecryptionException.class)
+ void testDecryptionByDirectEncryption_SecretKeyIsNull() throws Exception {
+
+ final JWEObject jweObject =
+ new JWEObject(new JWEHeader.Builder(JWEAlgorithm.DIR, EncryptionMethod.A256GCM)
+ .contentType("JWT")
+ .keyID("mock-key")
+ .build(),
+ new Payload(createdSignedJWT()));
+
+
+ final JWKCredential cred = TestCredentialHelper.createClientSecretCredential(CLIENT_SECRET)
+ .toEncryptionCredential(JWEAlgorithm.DIR, EncryptionMethod.A256GCM);
+
+ jweObject.encrypt(new DirectEncrypter(cred.getSecretKey()));
+ final EncryptedJWT jwe = EncryptedJWT.parse(jweObject.serialize());
+
+ final var params = new DecryptionParameters();
+ params.setContentEncryptionKeyCredentialResolver(new JOSEObjectCredentialResolver() {
+
+ @Override
+ public Credential resolveSingle(final CriteriaSet criteria) throws ResolverException {
+ final BasicExpiringJWKCredential jwkCredential = new BasicExpiringJWKCredential();
+ jwkCredential.getKeyNames().add("mock-key");
+ jwkCredential.setKid("mock-key");
+ jwkCredential.setUsageType(UsageType.ENCRYPTION);
+ return jwkCredential;
+ }
+
+ @Override
+ public Iterable<Credential> resolve(final CriteriaSet criteria) throws ResolverException {
+ return List.of(resolveSingle(criteria));
+ }
+ });
+ decrypter = new JWETokenDecrypter(params);
+ final JWT decryptedJWE = decrypter.decrypt(jwe);
+
+ }
+
@Test
void testDecryptionByDirectEncryption_Using_EvaluableCriteriaFiltering() throws Exception {
@@ -238,18 +312,17 @@ public class OIDCTokenDecrypterTest {
final JWEObject jweObject =
new JWEObject(new JWEHeader.Builder(JWEAlgorithm.DIR, EncryptionMethod.A256GCM)
.contentType("JWT")
- .keyID("mock-key")
+ .keyID("client_secret_credential")
.build(),
new Payload(createdSignedJWT()));
- final JWKCredential cred = JWKCredentialSupport.deriveSymmetricKeyForAlgAndEnc(
- TestCredentialHelper.createClientSecretCredential(CLIENT_SECRET), JWEAlgorithm.DIR,
- EncryptionMethod.A256GCM);
+ final JWKCredential cred = TestCredentialHelper.createClientSecretCredential(CLIENT_SECRET)
+ .toEncryptionCredential(JWEAlgorithm.DIR, EncryptionMethod.A256GCM);
jweObject.encrypt(new DirectEncrypter(cred.getSecretKey()));
final EncryptedJWT jwe = EncryptedJWT.parse(jweObject.serialize());
final var params = new DecryptionParameters();
- params.setContentEncryptionKeyCredentialResolver(new MockDirCriteriaFilteringCredentialResolver());
- decrypter = new OIDCTokenDecrypter(params);
+ params.setContentEncryptionKeyCredentialResolver(new MockKeyWrapCriteriaFilteringCredentialResolver());
+ decrypter = new JWETokenDecrypter(params);
final JWT decryptedJWE = decrypter.decrypt(jwe);
assertTrue(jwe.getState() == State.DECRYPTED);
assertTrue(decryptedJWE instanceof SignedJWT);
@@ -295,7 +368,7 @@ public class OIDCTokenDecrypterTest {
// Include the 'enc' algorithm but not the 'alg' algorithm. So decrypt should fail.
params.setIncludedAlgorithms(List.of("A256GCM"));
try {
- decrypter = new OIDCTokenDecrypter(params);
+ decrypter = new JWETokenDecrypter(params);
decrypter.decrypt(jwe);
} catch (final DecryptionException e) {
// Do nothing, JWE should not be decrypted.
@@ -340,7 +413,7 @@ public class OIDCTokenDecrypterTest {
}
});
try {
- decrypter = new OIDCTokenDecrypter(params);
+ decrypter = new JWETokenDecrypter(params);
decrypter.decrypt(jwe);
} catch (final DecryptionException e) {
// Do nothing, JWE should not be decrypted.
@@ -383,7 +456,7 @@ public class OIDCTokenDecrypterTest {
return List.of(resolveSingle(criteria));
}
});
- decrypter = new OIDCTokenDecrypter(params);
+ decrypter = new JWETokenDecrypter(params);
try {
decrypter.decrypt(jwe);
} catch (final DecryptionException e) {
@@ -432,13 +505,15 @@ public class OIDCTokenDecrypterTest {
return List.of(resolveSingle(criteria));
}
});
- decrypter = new OIDCTokenDecrypter(params);
+ decrypter = new JWETokenDecrypter(params);
final JWT decryptedJWE = decrypter.decrypt(jwe);
assertTrue(jwe.getState() == State.DECRYPTED);
assertTrue(decryptedJWE instanceof SignedJWT);
assertEquals(decryptedJWE.getJWTClaimsSet().getSubject(), "jdoe");
}
+
+
/* Same as testDecryptionByKeyEncryption but using a resolver that supports credential filtering.*/
@Test
void testDecryptionByKeyEncryption_Using_EvaluableCriteriaFiltering() throws Exception {
@@ -458,7 +533,7 @@ public class OIDCTokenDecrypterTest {
final EncryptedJWT jwe = EncryptedJWT.parse(jweObject.serialize());
final var params = new DecryptionParameters();
params.setKEKCredentialResolver(new MockRSACriteriaFilteringCredentialResolver(key));
- decrypter = new OIDCTokenDecrypter(params);
+ decrypter = new JWETokenDecrypter(params);
final JWT decryptedJWE = decrypter.decrypt(jwe);
assertTrue(jwe.getState() == State.DECRYPTED);
assertTrue(decryptedJWE instanceof SignedJWT);
@@ -494,7 +569,7 @@ public class OIDCTokenDecrypterTest {
final var params = new DecryptionParameters();
params.setKEKCredentialResolver(new MockRSAKeysCriteriaFilteringCredentialResolver(List.of(key, keyTwo)));
- decrypter = new OIDCTokenDecrypter(params);
+ decrypter = new JWETokenDecrypter(params);
final JWT decryptedJWE = decrypter.decrypt(jwe);
assertTrue(jwe.getState() == State.DECRYPTED);
assertTrue(decryptedJWE instanceof SignedJWT);
@@ -527,7 +602,7 @@ public class OIDCTokenDecrypterTest {
final var params = new DecryptionParameters();
params.setKEKCredentialResolver(new MockRSAKeysCriteriaFilteringCredentialResolver(List.of(key, keyTwo)));
- decrypter = new OIDCTokenDecrypter(params);
+ decrypter = new JWETokenDecrypter(params);
final JWT decryptedJWE = decrypter.decrypt(jwe);
assertTrue(jwe.getState() == State.DECRYPTED);
assertTrue(decryptedJWE instanceof SignedJWT);
@@ -574,7 +649,7 @@ public class OIDCTokenDecrypterTest {
return List.of(resolveSingle(criteria));
}
});
- decrypter = new OIDCTokenDecrypter(params);
+ decrypter = new JWETokenDecrypter(params);
final JWT decryptedJWE = decrypter.decrypt(jwe);
assertTrue(jwe.getState() == State.DECRYPTED);
assertTrue(decryptedJWE instanceof SignedJWT);
@@ -600,7 +675,7 @@ public class OIDCTokenDecrypterTest {
final EncryptedJWT jwe = EncryptedJWT.parse(jweObject.serialize());
final var params = new DecryptionParameters();
params.setKEKCredentialResolver(new MockKeyAgreementCriteriaFilteringCredentialResolver(key));
- decrypter = new OIDCTokenDecrypter(params);
+ decrypter = new JWETokenDecrypter(params);
final JWT decryptedJWE = decrypter.decrypt(jwe);
assertTrue(jwe.getState() == State.DECRYPTED);
assertTrue(decryptedJWE instanceof SignedJWT);
@@ -665,43 +740,20 @@ public class OIDCTokenDecrypterTest {
}
}
-
- private static class MockDirCriteriaFilteringCredentialResolver extends AbstractCriteriaFilteringCredentialResolver
- implements JOSEObjectCredentialResolver {
-
- @Override
- protected Iterable<Credential> resolveFromSource(final CriteriaSet criteriaSet) throws ResolverException {
- final BasicJWKCredential jwkCredential = new BasicJWKCredential();
- jwkCredential.setAlgorithm(JWEAlgorithm.DIR);
- jwkCredential.getKeyNames().add("mock-key");
- jwkCredential.setKid("mock-key");
- try {
- jwkCredential.setSecretKey(KeySupport.decodeSecretKey(
- JWSAssemblyUtils.getSecretBytes(CLIENT_SECRET), "AES"));
- } catch (final KeyException e) {
- throw new ResolverException(e);
- }
- return List.of(jwkCredential);
- }
-
- }
+
private static class MockKeyWrapCriteriaFilteringCredentialResolver extends AbstractCriteriaFilteringCredentialResolver
implements JOSEObjectCredentialResolver {
@Override
protected Iterable<Credential> resolveFromSource(final CriteriaSet criteriaSet) throws ResolverException {
- final BasicJWKCredential jwkCredential = new BasicJWKCredential();
- jwkCredential.setAlgorithm(JWEAlgorithm.A256KW);
- jwkCredential.getKeyNames().add("mock-key");
- jwkCredential.setKid("mock-key");
try {
- jwkCredential.setSecretKey(KeySupport.decodeSecretKey(
- JWSAssemblyUtils.getSecretBytes(CLIENT_SECRET), "AES"));
- } catch (final KeyException e) {
- throw new ResolverException(e);
- }
- return List.of(jwkCredential);
+ return List.of(TestCredentialHelper.createClientSecretCredential(CLIENT_SECRET)
+ .toEncryptionCredential(JWEAlgorithm.DIR, EncryptionMethod.A256GCM));
+ } catch (KeyException | JOSEException e) {
+ fail();
+ return null;
+ }
}
}
diff --git a/oidc-common-crypto-impl/src/test/java/net/shibboleth/oidc/security/impl/SignJWTHandlerTest.java b/oidc-common-crypto-impl/src/test/java/net/shibboleth/oidc/security/impl/SignJWTHandlerTest.java
index c89aae0..a8e4872 100644
--- a/oidc-common-crypto-impl/src/test/java/net/shibboleth/oidc/security/impl/SignJWTHandlerTest.java
+++ b/oidc-common-crypto-impl/src/test/java/net/shibboleth/oidc/security/impl/SignJWTHandlerTest.java
@@ -97,7 +97,8 @@ public class SignJWTHandlerTest extends AbstractHandlerTest {
final SecurityParametersContext secParamCtx = new SecurityParametersContext();
final var params = new SignatureSigningParameters();
- params.setSigningCredential(TestCredentialHelper.createClientSecretCredential(CLIENT_SECRET));
+ params.setSigningCredential(
+ TestCredentialHelper.createClientSecretCredential(CLIENT_SECRET).toSigningCredential());
params.setSignatureAlgorithm("HS256");
secParamCtx.setSignatureSigningParameters(params);
prc.getOutboundMessageContext().addSubcontext(secParamCtx);
@@ -115,7 +116,8 @@ public class SignJWTHandlerTest extends AbstractHandlerTest {
final SecurityParametersContext secParamCtx = new SecurityParametersContext();
final var params = new SignatureSigningParameters();
- params.setSigningCredential(TestCredentialHelper.createClientSecretCredential(CLIENT_SECRET));
+ params.setSigningCredential(
+ TestCredentialHelper.createClientSecretCredential(CLIENT_SECRET).toSigningCredential());
params.setSignatureAlgorithm("RS256");
secParamCtx.setSignatureSigningParameters(params);
prc.getOutboundMessageContext().addSubcontext(secParamCtx);
diff --git a/oidc-common-crypto-impl/src/test/java/net/shibboleth/oidc/security/impl/TestCredentialHelper.java b/oidc-common-crypto-impl/src/test/java/net/shibboleth/oidc/security/impl/TestCredentialHelper.java
index 54a68b3..65be91a 100644
--- a/oidc-common-crypto-impl/src/test/java/net/shibboleth/oidc/security/impl/TestCredentialHelper.java
+++ b/oidc-common-crypto-impl/src/test/java/net/shibboleth/oidc/security/impl/TestCredentialHelper.java
@@ -24,7 +24,6 @@ import java.time.Duration;
import org.opensaml.security.credential.UsageType;
import org.opensaml.security.crypto.KeySupport;
-import com.nimbusds.jose.Algorithm;
import com.nimbusds.jose.JOSEException;
import com.nimbusds.jose.JWEAlgorithm;
import com.nimbusds.jose.jwk.AsymmetricJWK;
@@ -33,6 +32,8 @@ import com.nimbusds.jose.jwk.JWK;
import com.nimbusds.jose.jwk.RSAKey;
import net.shibboleth.oidc.security.credential.BasicExpiringJWKCredential;
+import net.shibboleth.oidc.security.credential.ClientSecretCredential;
+import net.shibboleth.oidc.security.credential.DefaultClientSecretCredential;
import net.shibboleth.oidc.security.credential.JWKCredential;
/** Helper that creates different credentials.*/
@@ -42,36 +43,9 @@ public final class TestCredentialHelper {
}
- /**
- * Create a simple symmetric key client credential from from the given shared secret.
- *
- * @param secret the secret to convert to a {@link JWKCredential}.
- *
- * @return the credential
- * @throws KeyException on error creating the key
- */
- public static JWKCredential createClientSecretCredential(final String secret) throws KeyException {
- return createClientSecretCredential("mockKey", secret, null);
- }
-
- /**
- * Create a simple symmetric key client credential from from the given shared secret.
- *
- * @param kid the key ID
- * @param secret the secret to convert to a {@link JWKCredential}.
- * @param algorithm the JWA algorithm to set on the credential.
- *
- * @return the credential
- * @throws KeyException on error creating the key
- */
- public static JWKCredential createClientSecretCredential(final String kid, final String secret,
- final Algorithm algorithm)
- throws KeyException {
- return createSharedSecretCredential(kid, secret, algorithm, UsageType.UNSPECIFIED);
- }
/**
- * Create a simple symmetric key client credential from from the given shared secret.
+ * Create a simple symmetric key client_secret credential from from the given shared secret.
*
* @param kid the key ID
* @param secret the secret to convert to a {@link JWKCredential}.
@@ -80,17 +54,9 @@ public final class TestCredentialHelper {
* @return the credential
* @throws KeyException on error creating the key
*/
- public static JWKCredential createSharedSecretCredential(final String kid, final String secret,
- final Algorithm algorithm, final UsageType usage)
+ public static ClientSecretCredential createClientSecretCredential(final String secret)
throws KeyException {
- final BasicExpiringJWKCredential jwkCredential = new BasicExpiringJWKCredential();
- jwkCredential.setSecretKey(KeySupport.decodeSecretKey(JWSAssemblyUtils.getSecretBytes(secret), "AES"));
- jwkCredential.setCredentialExpiresAt(Duration.ZERO);
- jwkCredential.setUsageType(usage);
- jwkCredential.setKid(kid);
- jwkCredential.setAlgorithm(algorithm);
- jwkCredential.getKeyNames().add("mockKey");
- return jwkCredential;
+ return new DefaultClientSecretCredential(secret);
}
/**
diff --git a/oidc-common-crypto-impl/src/test/java/net/shibboleth/oidc/security/jose/impl/DefaultEncryptionParametersResolverTest.java b/oidc-common-crypto-impl/src/test/java/net/shibboleth/oidc/security/jose/impl/DefaultEncryptionParametersResolverTest.java
index d5b0c65..2d8902a 100644
--- a/oidc-common-crypto-impl/src/test/java/net/shibboleth/oidc/security/jose/impl/DefaultEncryptionParametersResolverTest.java
+++ b/oidc-common-crypto-impl/src/test/java/net/shibboleth/oidc/security/jose/impl/DefaultEncryptionParametersResolverTest.java
@@ -37,6 +37,7 @@ import org.opensaml.xmlsec.config.GlobalAlgorithmRegistryInitializer;
import org.testng.annotations.BeforeMethod;
import org.testng.annotations.Test;
+import com.nimbusds.jose.EncryptionMethod;
import com.nimbusds.jose.JWEAlgorithm;
import com.nimbusds.jose.jwk.Curve;
import com.nimbusds.jose.jwk.ECKey;
@@ -48,14 +49,14 @@ import com.nimbusds.jose.jwk.gen.RSAKeyGenerator;
import net.shibboleth.oidc.jwa.support.EncryptionConstants;
import net.shibboleth.oidc.jwa.support.KeyManagementConstants;
import net.shibboleth.oidc.security.credential.BasicJWKCredential;
+import net.shibboleth.oidc.security.credential.ClientSecretCredential;
+import net.shibboleth.oidc.security.credential.DefaultClientSecretCredential;
import net.shibboleth.oidc.security.credential.JOSEObjectCredentialResolver;
import net.shibboleth.oidc.security.credential.JWKCredential;
import net.shibboleth.oidc.security.impl.TestCredentialHelper;
import net.shibboleth.oidc.security.jose.EncryptionParameters;
+import net.shibboleth.oidc.security.jose.criterion.ClientSecretCredentialCriterion;
import net.shibboleth.oidc.security.jose.criterion.EncryptionConfigurationCriterion;
-import net.shibboleth.oidc.security.jose.criterion.StaticCredentialCriterion;
-import net.shibboleth.oidc.security.jose.impl.BasicEncryptionConfiguration;
-import net.shibboleth.oidc.security.jose.impl.DefaultEncryptionParametersResolver;
import net.shibboleth.utilities.java.support.resolver.CriteriaSet;
import net.shibboleth.utilities.java.support.resolver.ResolverException;
@@ -89,11 +90,34 @@ public class DefaultEncryptionParametersResolverTest {
@Override
protected Iterable<Credential> resolveFromSource(final CriteriaSet criteriaSet) throws ResolverException {
- if (criteriaSet.contains(StaticCredentialCriterion.class)) {
- final StaticCredentialCriterion credentialCriterion =
- criteriaSet.get(StaticCredentialCriterion.class);
- final Credential credential = credentialCriterion.getCredential();
- return List.of(credential);
+ if (criteriaSet.contains(ClientSecretCredentialCriterion.class)) {
+ final ClientSecretCredentialCriterion credentialCriterion =
+ criteriaSet.get(ClientSecretCredentialCriterion.class);
+ final ClientSecretCredential credential = credentialCriterion.getCredential();
+ return List.of(credential.toSigningCredential());
+
+ } else {
+ return Collections.emptyList();
+ }
+ }
+
+ }
+
+ /** Mock static credential resolver that is filterable.*/
+ private static class MockStaticCriteriaFilteringCredentialResolver_WrongKeyType
+ extends AbstractCriteriaFilteringCredentialResolver
+ implements JOSEObjectCredentialResolver {
+
+
+ @Override
+ protected Iterable<Credential> resolveFromSource(final CriteriaSet criteriaSet) throws ResolverException {
+ if (criteriaSet.contains(ClientSecretCredentialCriterion.class)) {
+ final ClientSecretCredentialCriterion credentialCriterion =
+ criteriaSet.get(ClientSecretCredentialCriterion.class);
+ final ClientSecretCredential credential = credentialCriterion.getCredential();
+
+ // Wrong key type for encryption
+ return List.of(credential.toSigningCredential());
} else {
return Collections.emptyList();
@@ -148,8 +172,8 @@ public class DefaultEncryptionParametersResolverTest {
.keyID("mock-key-rsa")
.generate();
creds.add(TestCredentialHelper.createKeyEncryptionCredential(key));
- creds.add(TestCredentialHelper.createSharedSecretCredential("mock-key-client-secret",
- SYMMETRIC_KEY, JWEAlgorithm.A256KW, UsageType.UNSPECIFIED));
+ creds.add(TestCredentialHelper.createClientSecretCredential(SYMMETRIC_KEY)
+ .toEncryptionCredential(JWEAlgorithm.A256KW, EncryptionMethod.A128CBC_HS256));
config.setKEKCredentialResolver(new MockStaticFilteringCredentialResolver(creds));
@@ -180,10 +204,9 @@ public class DefaultEncryptionParametersResolverTest {
.keyID("mock-key-rsa")
.generate();
creds.add(TestCredentialHelper.createKeyEncryptionCredential(key));
- creds.add(TestCredentialHelper.createSharedSecretCredential("mock-key-client-secret",
- SYMMETRIC_KEY, JWEAlgorithm.A256KW, UsageType.UNSPECIFIED));
+ creds.add(TestCredentialHelper.createClientSecretCredential(SYMMETRIC_KEY)
+ .toEncryptionCredential(JWEAlgorithm.A256KW, EncryptionMethod.A128CBC_HS256));
-
config.setKEKCredentialResolver(new MockStaticFilteringCredentialResolver(creds));
final EncryptionParameters param = resolver.resolveSingle(criteria);
@@ -193,6 +216,7 @@ public class DefaultEncryptionParametersResolverTest {
}
+ /* Generate a JWK with no 'alg', is optional and should generally match on the type.*/
@Test
public void testBasicRSA_NoAlgorithmSpecifiedInJWKCredential() throws Exception {
final CriteriaSet criteria = buildBasicCriteriaSet();
@@ -266,12 +290,11 @@ public class DefaultEncryptionParametersResolverTest {
.keyID("mock-key")
.generate();
creds.add(TestCredentialHelper.createKeyAgreementCredential(key));
- creds.add(TestCredentialHelper.createSharedSecretCredential("mock-key-client-secret",
- SYMMETRIC_KEY, JWEAlgorithm.A256KW, UsageType.UNSPECIFIED));
-
+ creds.add(TestCredentialHelper.createClientSecretCredential(SYMMETRIC_KEY)
+ .toEncryptionCredential(JWEAlgorithm.A256KW, EncryptionMethod.A128CBC_HS256));
config.setKEKCredentialResolver(new MockStaticFilteringCredentialResolver(creds));
-
+
final EncryptionParameters param = resolver.resolveSingle(criteria);
assertNotNull(param);
@@ -292,10 +315,12 @@ public class DefaultEncryptionParametersResolverTest {
config.setKeyTransportEncryptionAlgorithms(
List.of(KeyManagementConstants.ALGO_ID_ALG_AES_256_KW));
- criteria.add(new StaticCredentialCriterion(TestCredentialHelper.createSharedSecretCredential("mock-key",
- SYMMETRIC_KEY, JWEAlgorithm.A256KW, UsageType.UNSPECIFIED)));
+ final List<Credential> creds = new ArrayList<>();
+ creds.add(TestCredentialHelper.createClientSecretCredential(SYMMETRIC_KEY)
+ .toEncryptionCredential(JWEAlgorithm.A256KW, EncryptionMethod.A128CBC_HS256));
+
- config.setKEKCredentialResolver(new MockStaticCriteriaFilteringCredentialResolver());
+ config.setKEKCredentialResolver(new MockStaticFilteringCredentialResolver(creds));
final EncryptionParameters param = resolver.resolveSingle(criteria);
@@ -310,7 +335,7 @@ public class DefaultEncryptionParametersResolverTest {
}
- /* The key is 256bit and does not support the 128bit enc. algo.*/
+ /* The key is 256bit and does not support the 128bit enc. algo.*/
@Test
public void testBasicAESKeyWrap_WrongKeyLength() throws Exception {
final CriteriaSet criteria = buildBasicCriteriaSet();
@@ -318,10 +343,13 @@ public class DefaultEncryptionParametersResolverTest {
List.of(KeyManagementConstants.ALGO_ID_ALG_AES_128_KW));
config.setDataEncryptionAlgorithms(List.of(EncryptionConstants.ALGO_ID_ENC_ALG_A128CBC_HS256));
- criteria.add(new StaticCredentialCriterion(TestCredentialHelper.createSharedSecretCredential("mock-key",
- SYMMETRIC_KEY, JWEAlgorithm.A256KW, UsageType.UNSPECIFIED)));
+ final List<Credential> creds = new ArrayList<>();
+ creds.add(TestCredentialHelper.createClientSecretCredential(SYMMETRIC_KEY)
+ .toEncryptionCredential(JWEAlgorithm.A256KW, EncryptionMethod.A128CBC_HS256));
+
- config.setKEKCredentialResolver(new MockStaticCriteriaFilteringCredentialResolver());
+ config.setKEKCredentialResolver(new MockStaticFilteringCredentialResolver(creds));
+
final EncryptionParameters param = resolver.resolveSingle(criteria);
assertNull(param);
@@ -340,8 +368,8 @@ public class DefaultEncryptionParametersResolverTest {
.keyID("mock-key-rsa")
.generate();
creds.add(TestCredentialHelper.createKeyEncryptionCredential(key));
- creds.add(TestCredentialHelper.createSharedSecretCredential("mock-key-client-secret",
- SYMMETRIC_KEY, JWEAlgorithm.A256KW, UsageType.UNSPECIFIED));
+ creds.add(TestCredentialHelper.createClientSecretCredential(SYMMETRIC_KEY)
+ .toEncryptionCredential(JWEAlgorithm.A256KW, EncryptionMethod.A128CBC_HS256));
config.setKEKCredentialResolver(new MockStaticFilteringCredentialResolver(creds));
@@ -374,8 +402,8 @@ public class DefaultEncryptionParametersResolverTest {
.keyID("mock-key-rsa")
.generate();
creds.add(TestCredentialHelper.createKeyEncryptionCredential(key));
- creds.add(TestCredentialHelper.createSharedSecretCredential("mock-key-client-secret",
- SYMMETRIC_KEY, JWEAlgorithm.A256KW, UsageType.UNSPECIFIED));
+ creds.add(TestCredentialHelper.createClientSecretCredential(SYMMETRIC_KEY)
+ .toEncryptionCredential(JWEAlgorithm.A256KW, EncryptionMethod.A128CBC_HS256));
config.setKEKCredentialResolver(new MockStaticFilteringCredentialResolver(creds));
@@ -408,8 +436,8 @@ public class DefaultEncryptionParametersResolverTest {
.keyID("mock-key-rsa")
.generate();
creds.add(TestCredentialHelper.createKeyEncryptionCredential(key));
- creds.add(TestCredentialHelper.createSharedSecretCredential("mock-key-client-secret",
- SYMMETRIC_KEY, JWEAlgorithm.A256KW, UsageType.UNSPECIFIED));
+ creds.add(TestCredentialHelper.createClientSecretCredential(SYMMETRIC_KEY)
+ .toEncryptionCredential(JWEAlgorithm.A256KW, EncryptionMethod.A128CBC_HS256));
config.setKEKCredentialResolver(new MockStaticFilteringCredentialResolver(creds));
@@ -426,92 +454,44 @@ public class DefaultEncryptionParametersResolverTest {
assertEquals(param.getKeyTransportEncryptionCredential().getPublicKey().getAlgorithm(),"RSA");
}
-
- @Test
- public void testBasicAESKeyWrap_NoAlgorithmSpecifiedInJWKCredential() throws Exception {
- final CriteriaSet criteria = buildBasicCriteriaSet();
- config.setKeyTransportEncryptionAlgorithms(
- List.of(KeyManagementConstants.ALGO_ID_ALG_AES_256_KW));
-
- final JWKCredential cred = TestCredentialHelper.createSharedSecretCredential("mock-key",
- SYMMETRIC_KEY, JWEAlgorithm.A256KW, UsageType.UNSPECIFIED);
- // Blank algorithm, this should work on the 'key algorithm' alone
- ((BasicJWKCredential)cred).setAlgorithm(null);
-
- criteria.add(new StaticCredentialCriterion(cred));
- config.setKEKCredentialResolver(new MockStaticCriteriaFilteringCredentialResolver());
- final EncryptionParameters param = resolver.resolveSingle(criteria);
-
- assertNotNull(param);
- assertNotNull(param.getDataEncryptionAlgorithm());
- assertNotNull(param.getKeyTransportEncryptionAlgorithm());
- assertEquals(param.getDataEncryptionAlgorithm(),EncryptionConstants.ALGO_ID_ENC_ALG_A128CBC_HS256);
- assertEquals(param.getKeyTransportEncryptionAlgorithm(),KeyManagementConstants.ALGO_ID_ALG_AES_256_KW);
- assertNotNull(param.getKeyTransportEncryptionCredential());
- assertNotNull(param.getKeyTransportEncryptionCredential().getSecretKey());
- assertEquals(param.getKeyTransportEncryptionCredential().getSecretKey().getAlgorithm(),"AES");
-
- }
@Test
- public void testBasicAESKeyWrap_WrongUsageType() throws Exception {
+ public void testBasicAESKeyWrap_WrongKeyAndUsageType() throws Exception {
final CriteriaSet criteria = buildBasicCriteriaSet();
config.setKeyTransportEncryptionAlgorithms(
- List.of(KeyManagementConstants.ALGO_ID_ALG_AES_256_KW));
-
- final JWKCredential cred = TestCredentialHelper.createSharedSecretCredential("mock-key",
- SYMMETRIC_KEY, JWEAlgorithm.A256KW, UsageType.SIGNING);
+ List.of(KeyManagementConstants.ALGO_ID_ALG_AES_256_KW));
- criteria.add(new StaticCredentialCriterion(cred));
- config.setKEKCredentialResolver(new MockStaticCriteriaFilteringCredentialResolver());
+ criteria.add(
+ new ClientSecretCredentialCriterion(new DefaultClientSecretCredential(SYMMETRIC_KEY)));
+ config.setKEKCredentialResolver(new MockStaticCriteriaFilteringCredentialResolver_WrongKeyType());
final EncryptionParameters param = resolver.resolveSingle(criteria);
assertNull(param);
}
- @Test
- public void testBasicAESKeyWrap_WrongCredentialAlgorithm() throws Exception {
- final CriteriaSet criteria = buildBasicCriteriaSet();
- config.setKeyTransportEncryptionAlgorithms(
- List.of(KeyManagementConstants.ALGO_ID_ALG_AES_256_KW));
-
- final RSAKey key = new RSAKeyGenerator(2048)
- .algorithm(JWEAlgorithm.RSA_OAEP_256)
- .keyUse(KeyUse.ENCRYPTION)
- .keyID("mock-key")
- .generate();
-
- criteria.add(new StaticCredentialCriterion(TestCredentialHelper.createKeyEncryptionCredential(key)));
-
- config.setKEKCredentialResolver(new MockStaticCriteriaFilteringCredentialResolver());
- final EncryptionParameters param = resolver.resolveSingle(criteria);
-
- assertNull(param);
-
-
- }
-
/* Direct encryption algorithm not supported at runtime.*/
@Test(enabled=false)
public void testBasicDirectEncryption() throws Exception {
final CriteriaSet criteria = buildBasicCriteriaSet();
config.setKeyTransportEncryptionAlgorithms(
- List.of(KeyManagementConstants.ALGO_ID_ALG_DIR));
+ List.of(KeyManagementConstants.ALGO_ID_ALG_DIR));
+ config.setDataEncryptionAlgorithms(List.of(EncryptionConstants.ALGO_ID_ENC_ALG_A128CBC_HS256,
+ EncryptionConstants.ALGO_ID_ENC_ALG_A256CBC_HS512));
final List<Credential> creds = new ArrayList<>();
- creds.add(TestCredentialHelper.createSharedSecretCredential("mock-key-client-secret",
- SYMMETRIC_KEY, JWEAlgorithm.DIR, UsageType.UNSPECIFIED));
+ creds.add(TestCredentialHelper.createClientSecretCredential(SYMMETRIC_KEY)
+ .toEncryptionCredential(JWEAlgorithm.DIR, EncryptionMethod.A128CBC_HS256));
- config.setKEKCredentialResolver(new MockStaticFilteringCredentialResolver(creds));
+ config.setContentEncryptionKeyCredentialResolver(new MockStaticFilteringCredentialResolver(creds));
final EncryptionParameters param = resolver.resolveSingle(criteria);
assertNotNull(param);
assertNotNull(param.getDataEncryptionAlgorithm());
assertNotNull(param.getKeyTransportEncryptionAlgorithm());
- assertEquals(param.getDataEncryptionAlgorithm(),EncryptionConstants.ALGO_ID_ENC_ALG_A256CBC_HS512);
+ assertEquals(param.getDataEncryptionAlgorithm(),EncryptionConstants.ALGO_ID_ENC_ALG_A128CBC_HS256);
assertEquals(param.getKeyTransportEncryptionAlgorithm(),KeyManagementConstants.ALGO_ID_ALG_DIR);
assertNotNull(param.getDataEncryptionCredential());
assertNotNull(param.getDataEncryptionCredential().getSecretKey());
diff --git a/oidc-common-metadata-impl/src/main/java/net/shibboleth/oidc/metadata/impl/ClientInformationNodeProcessor.java b/oidc-common-metadata-impl/src/main/java/net/shibboleth/oidc/metadata/impl/ClientInformationNodeProcessor.java
index 462dd34..3cb3f7b 100644
--- a/oidc-common-metadata-impl/src/main/java/net/shibboleth/oidc/metadata/impl/ClientInformationNodeProcessor.java
+++ b/oidc-common-metadata-impl/src/main/java/net/shibboleth/oidc/metadata/impl/ClientInformationNodeProcessor.java
@@ -74,9 +74,9 @@ import net.shibboleth.oidc.saml.xmlobject.Constants;
import net.shibboleth.oidc.saml.xmlobject.DefaultAcrValue;
import net.shibboleth.oidc.saml.xmlobject.MetadataValueSAMLObject;
import net.shibboleth.oidc.saml.xmlobject.OAuthRPExtensions;
+import net.shibboleth.oidc.security.CredentialConversionUtil;
import net.shibboleth.oidc.security.credential.JWKReferenceCredential;
import net.shibboleth.oidc.security.credential.NimbusSecretCredential;
-import net.shibboleth.oidc.security.impl.CredentialConversionUtil;
import net.shibboleth.utilities.java.support.annotation.constraint.NonnullElements;
import net.shibboleth.utilities.java.support.component.ComponentInitializationException;
import net.shibboleth.utilities.java.support.primitive.StringSupport;
diff --git a/oidc-common-metadata-impl/src/main/java/net/shibboleth/oidc/metadata/keyinfo/ext/impl/provider/InlineJwksProvider.java b/oidc-common-metadata-impl/src/main/java/net/shibboleth/oidc/metadata/keyinfo/ext/impl/provider/InlineJwksProvider.java
index 1ed00d5..4147740 100644
--- a/oidc-common-metadata-impl/src/main/java/net/shibboleth/oidc/metadata/keyinfo/ext/impl/provider/InlineJwksProvider.java
+++ b/oidc-common-metadata-impl/src/main/java/net/shibboleth/oidc/metadata/keyinfo/ext/impl/provider/InlineJwksProvider.java
@@ -42,9 +42,9 @@ import com.nimbusds.jose.jwk.JWKSet;
import com.nimbusds.jose.jwk.KeyType;
import net.shibboleth.oidc.saml.xmlobject.JwksData;
+import net.shibboleth.oidc.security.CredentialConversionUtil;
import net.shibboleth.oidc.security.credential.BasicJWKCredential;
import net.shibboleth.oidc.security.credential.JWKCredential;
-import net.shibboleth.oidc.security.impl.CredentialConversionUtil;
import net.shibboleth.utilities.java.support.codec.Base64Support;
import net.shibboleth.utilities.java.support.codec.DecodingException;
import net.shibboleth.utilities.java.support.collection.LazySet;
diff --git a/oidc-common-profile-api/src/main/java/net/shibboleth/oidc/profile/config/OIDCAuthorizationConfiguration.java b/oidc-common-profile-api/src/main/java/net/shibboleth/oidc/profile/config/OIDCAuthorizationConfiguration.java
index 39f511a..6b1f6b0 100644
--- a/oidc-common-profile-api/src/main/java/net/shibboleth/oidc/profile/config/OIDCAuthorizationConfiguration.java
+++ b/oidc-common-profile-api/src/main/java/net/shibboleth/oidc/profile/config/OIDCAuthorizationConfiguration.java
@@ -31,12 +31,12 @@ import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import org.opensaml.profile.context.ProfileRequestContext;
-import org.opensaml.security.credential.Credential;
import com.google.common.base.Predicates;
import net.shibboleth.idp.authn.config.AuthenticationProfileConfiguration;
import net.shibboleth.idp.profile.config.OverriddenIssuerProfileConfiguration;
+import net.shibboleth.oidc.security.credential.ClientSecretCredential;
import net.shibboleth.utilities.java.support.annotation.constraint.NonnullElements;
import net.shibboleth.utilities.java.support.annotation.constraint.NotEmpty;
import net.shibboleth.utilities.java.support.annotation.constraint.NotLive;
@@ -102,16 +102,14 @@ public class OIDCAuthorizationConfiguration extends AbstractOIDCSSOConfiguration
/** An override to specify a specific redirect_uri to use over the normally computed one.*/
@Nonnull private Function<ProfileRequestContext, String> redirectUriOverrideLookupStrategy;
- /**
- * Lookup function to retrieve the client_id from the given profile request context.
- * Typically obtained from the issuer_id of the downstream relying-party (OP).
- */
+ /** Lookup function to retrieve the client_id from the given profile request context.*/
+ //TODO this is the same as the issuer in the proxy context?
@Nonnull private Function<ProfileRequestContext, String> clientIdLookupStrategy;
/**
* Lookup function to retrieve a client credential from the given profile request context.
*/
- @Nonnull private Function<ProfileRequestContext, Credential> clientCredentialLookupStrategy;
+ @Nonnull private Function<ProfileRequestContext, ClientSecretCredential> clientCredentialLookupStrategy;
/** Lookup function to determine the client_authentication method. */
//TODO same as tokenEndpointAuthMethodsLookupStrategy?
@@ -441,7 +439,7 @@ public class OIDCAuthorizationConfiguration extends AbstractOIDCSSOConfiguration
* @param strategy the strategy to use
*/
public void setClientCredentialLookupStrategy(
- @Nonnull final Function<ProfileRequestContext, Credential> strategy) {
+ @Nonnull final Function<ProfileRequestContext, ClientSecretCredential> strategy) {
clientCredentialLookupStrategy =
Constraint.isNotNull(strategy, "Client credential lookup strategy can not be null");
}
@@ -451,7 +449,7 @@ public class OIDCAuthorizationConfiguration extends AbstractOIDCSSOConfiguration
*
* @param clientCredential the static client credential to use
*/
- public void setClientCredential(@Nullable final Credential clientCredential) {
+ public void setClientCredential(@Nullable final ClientSecretCredential clientCredential) {
clientCredentialLookupStrategy = FunctionSupport.constant(clientCredential);
}
@@ -463,7 +461,7 @@ public class OIDCAuthorizationConfiguration extends AbstractOIDCSSOConfiguration
*
* @return the client credential
*/
- public Credential getClientCredential(
+ public ClientSecretCredential getClientCredential(
@Nullable final ProfileRequestContext profileRequestContext) {
return clientCredentialLookupStrategy.apply(profileRequestContext);
}
diff --git a/oidc-common-profile-impl/src/main/java/net/shibboleth/oidc/profile/impl/FormOutboundKeySetResponseMessage.java b/oidc-common-profile-impl/src/main/java/net/shibboleth/oidc/profile/impl/FormOutboundKeySetResponseMessage.java
index 12a2fac..2673f19 100644
--- a/oidc-common-profile-impl/src/main/java/net/shibboleth/oidc/profile/impl/FormOutboundKeySetResponseMessage.java
+++ b/oidc-common-profile-impl/src/main/java/net/shibboleth/oidc/profile/impl/FormOutboundKeySetResponseMessage.java
@@ -43,7 +43,7 @@ import net.shibboleth.idp.profile.config.SecurityConfiguration;
import net.shibboleth.idp.profile.context.RelyingPartyContext;
import net.shibboleth.oidc.profile.config.JSONSecurityConfiguration;
import net.shibboleth.oidc.profile.messaging.JSONSuccessResponse;
-import net.shibboleth.oidc.security.impl.CredentialConversionUtil;
+import net.shibboleth.oidc.security.CredentialConversionUtil;
import net.shibboleth.utilities.java.support.component.ComponentSupport;
import net.shibboleth.utilities.java.support.logic.Constraint;
diff --git a/oidc-common-profile-impl/src/main/java/net/shibboleth/oidc/profile/impl/PopulateJWTDecryptionParameters.java b/oidc-common-profile-impl/src/main/java/net/shibboleth/oidc/profile/impl/PopulateJWTDecryptionParameters.java
index 3566cc7..956c331 100644
--- a/oidc-common-profile-impl/src/main/java/net/shibboleth/oidc/profile/impl/PopulateJWTDecryptionParameters.java
+++ b/oidc-common-profile-impl/src/main/java/net/shibboleth/oidc/profile/impl/PopulateJWTDecryptionParameters.java
@@ -27,20 +27,20 @@ import org.opensaml.profile.action.ActionSupport;
import org.opensaml.profile.action.EventIds;
import org.opensaml.profile.context.ProfileRequestContext;
import org.opensaml.profile.context.navigate.InboundMessageContextLookup;
-import org.opensaml.security.credential.Credential;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import net.shibboleth.idp.profile.AbstractProfileAction;
import net.shibboleth.idp.profile.context.RelyingPartyContext;
import net.shibboleth.oidc.profile.config.OIDCAuthorizationConfiguration;
+import net.shibboleth.oidc.security.credential.ClientSecretCredential;
import net.shibboleth.oidc.security.jose.DecryptionConfiguration;
import net.shibboleth.oidc.security.jose.DecryptionParameters;
import net.shibboleth.oidc.security.jose.DecryptionParametersResolver;
import net.shibboleth.oidc.security.jose.EncryptionConfiguration;
import net.shibboleth.oidc.security.jose.context.SecurityParametersContext;
+import net.shibboleth.oidc.security.jose.criterion.ClientSecretCredentialCriterion;
import net.shibboleth.oidc.security.jose.criterion.DecryptionConfigurationCriterion;
-import net.shibboleth.oidc.security.jose.criterion.StaticCredentialCriterion;
import net.shibboleth.utilities.java.support.annotation.constraint.NonnullAfterInit;
import net.shibboleth.utilities.java.support.component.ComponentInitializationException;
import net.shibboleth.utilities.java.support.component.ComponentSupport;
@@ -150,7 +150,7 @@ public class PopulateJWTDecryptionParameters extends AbstractProfileAction {
throw new ComponentInitializationException("DecryptionParametersResolver cannot be null");
}
if (configurationLookupStrategy == null) {
- throw new ComponentInitializationException("DecryptionConfiguraitonLookup cannot be null");
+ throw new ComponentInitializationException("DecryptionConfigurationLookup cannot be null");
}
}
@@ -202,7 +202,7 @@ public class PopulateJWTDecryptionParameters extends AbstractProfileAction {
final CriteriaSet criteria = new CriteriaSet();
criteria.add(new DecryptionConfigurationCriterion(configs));
- // Build a static credential criteria. Extract the decryption credential from the RP config.
+ // Build a client secret credential criteria. Extract the decryption credential from the RP config.
final RelyingPartyContext rpCtx = relyingPartyContextLookupStrategy.apply(profileRequestContext);
if (rpCtx != null && rpCtx.getConfiguration() != null &&
rpCtx.getProfileConfig() instanceof OIDCAuthorizationConfiguration) {
@@ -210,9 +210,10 @@ public class PopulateJWTDecryptionParameters extends AbstractProfileAction {
(OIDCAuthorizationConfiguration) rpCtx.getProfileConfig();
if (profileConfiguration != null) {
- final Credential credential = profileConfiguration.getClientCredential(profileRequestContext);
+ final ClientSecretCredential credential =
+ profileConfiguration.getClientCredential(profileRequestContext);
if (credential != null) {
- criteria.add(new StaticCredentialCriterion(credential));
+ criteria.add(new ClientSecretCredentialCriterion(credential));
} else {
log.trace("{} No credential found from the profile configuration", getLogPrefix());
}
diff --git a/oidc-common-profile-impl/src/main/java/net/shibboleth/oidc/profile/impl/PopulateJWTEncryptionParameters.java b/oidc-common-profile-impl/src/main/java/net/shibboleth/oidc/profile/impl/PopulateJWTEncryptionParameters.java
index fce324d..7659769 100644
--- a/oidc-common-profile-impl/src/main/java/net/shibboleth/oidc/profile/impl/PopulateJWTEncryptionParameters.java
+++ b/oidc-common-profile-impl/src/main/java/net/shibboleth/oidc/profile/impl/PopulateJWTEncryptionParameters.java
@@ -29,27 +29,29 @@ import org.opensaml.profile.action.ActionSupport;
import org.opensaml.profile.action.EventIds;
import org.opensaml.profile.context.ProfileRequestContext;
import org.opensaml.profile.context.navigate.OutboundMessageContextLookup;
-import org.opensaml.security.credential.Credential;
import org.opensaml.security.credential.UsageType;
import org.opensaml.security.criteria.UsageCriterion;
import org.opensaml.xmlsec.criterion.EncryptionOptionalCriterion;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
+import com.google.common.base.Predicates;
+
import net.shibboleth.idp.profile.AbstractProfileAction;
import net.shibboleth.idp.profile.context.RelyingPartyContext;
import net.shibboleth.oidc.metadata.context.OIDCMetadataContext;
import net.shibboleth.oidc.metadata.context.OIDCProviderMetadataContext;
import net.shibboleth.oidc.profile.config.OIDCAuthorizationConfiguration;
import net.shibboleth.oidc.profile.config.logic.EncryptionOptionalPredicate;
+import net.shibboleth.oidc.security.credential.ClientSecretCredential;
import net.shibboleth.oidc.security.jose.EncryptionConfiguration;
import net.shibboleth.oidc.security.jose.EncryptionParameters;
import net.shibboleth.oidc.security.jose.EncryptionParametersResolver;
import net.shibboleth.oidc.security.jose.context.SecurityParametersContext;
import net.shibboleth.oidc.security.jose.criterion.ClientInformationCriterion;
+import net.shibboleth.oidc.security.jose.criterion.ClientSecretCredentialCriterion;
import net.shibboleth.oidc.security.jose.criterion.EncryptionConfigurationCriterion;
import net.shibboleth.oidc.security.jose.criterion.ProviderMetadataCriterion;
-import net.shibboleth.oidc.security.jose.criterion.StaticCredentialCriterion;
import net.shibboleth.utilities.java.support.annotation.constraint.NonnullAfterInit;
import net.shibboleth.utilities.java.support.annotation.constraint.NonnullElements;
import net.shibboleth.utilities.java.support.annotation.constraint.NotEmpty;
@@ -226,6 +228,16 @@ public class PopulateJWTEncryptionParameters extends AbstractProfileAction {
encryptionOptionalPredicate = Constraint.isNotNull(condition, "Condition cannot be null");
}
+
+ /**
+ * Sets the boolean condition to apply to determine how to proceed if encryption parameter resolution fails.
+ *
+ * @param flag the flag to set
+ */
+ public void setEncryptionOptional(@Nonnull final boolean flag) {
+ ComponentSupport.ifInitializedThrowUnmodifiabledComponentException(this);
+ encryptionOptionalPredicate = flag ? Predicates.alwaysTrue() : Predicates.alwaysFalse();
+ }
@Override
protected void doInitialize() throws ComponentInitializationException {
@@ -273,14 +285,12 @@ public class PopulateJWTEncryptionParameters extends AbstractProfileAction {
if (params != null) {
log.debug("{} Resolved EncryptionParameters for {}", getLogPrefix(),forFriendlyName);
encryptionContext.setEncryptionParameters(params);
- } else {
- if (encryptionOptional) {
- log.debug("{} Resolver returned no EncryptionParameters", getLogPrefix());
- log.debug("{} Encryption is optional, ignoring inability to encrypt", getLogPrefix());
- } else {
- log.warn("{} Resolver returned no EncryptionParameters", getLogPrefix());
- ActionSupport.buildEvent(profileRequestContext, EventIds.INVALID_SEC_CFG);
- }
+ } else if (encryptionOptional) {
+ log.debug("{} Resolver returned no EncryptionParameters", getLogPrefix());
+ log.debug("{} Encryption is optional, ignoring inability to encrypt", getLogPrefix());
+ } else {
+ log.warn("{} Resolver returned no EncryptionParameters", getLogPrefix());
+ ActionSupport.buildEvent(profileRequestContext, EventIds.INVALID_SEC_CFG);
}
} catch (final ResolverException e) {
if (encryptionOptional) {
@@ -341,11 +351,14 @@ public class PopulateJWTEncryptionParameters extends AbstractProfileAction {
(OIDCAuthorizationConfiguration) rpCtx.getProfileConfig();
if (profileConfiguration != null) {
- final Credential credential = profileConfiguration.getClientCredential(profileRequestContext);
+ final ClientSecretCredential credential =
+ profileConfiguration.getClientCredential(profileRequestContext);
if (credential != null) {
- criteria.add(new StaticCredentialCriterion(credential));
+ criteria.add(new ClientSecretCredentialCriterion(credential));
+ log.debug("{} Adding client_secret credential to resolution criteria",
+ getLogPrefix());
} else {
- log.trace("{} No credential found from the profile configuration", getLogPrefix());
+ log.trace("{} No client_secret credential found from the profile configuration", getLogPrefix());
}
} else {
log.trace("{} Profile configuration not available, "
diff --git a/oidc-common-profile-impl/src/main/java/net/shibboleth/oidc/profile/impl/PopulateJWTSignatureSigningParametersHandler.java b/oidc-common-profile-impl/src/main/java/net/shibboleth/oidc/profile/impl/PopulateJWTSignatureSigningParametersHandler.java
index bb2a07c..2f7c575 100644
--- a/oidc-common-profile-impl/src/main/java/net/shibboleth/oidc/profile/impl/PopulateJWTSignatureSigningParametersHandler.java
+++ b/oidc-common-profile-impl/src/main/java/net/shibboleth/oidc/profile/impl/PopulateJWTSignatureSigningParametersHandler.java
@@ -32,7 +32,6 @@ import org.opensaml.profile.context.ProfileRequestContext;
import org.opensaml.saml.common.messaging.context.SAMLMetadataContext;
import org.opensaml.saml.common.messaging.context.SAMLPeerEntityContext;
import org.opensaml.saml.criterion.RoleDescriptorCriterion;
-import org.opensaml.security.credential.Credential;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -40,6 +39,7 @@ import net.shibboleth.idp.profile.context.RelyingPartyContext;
import net.shibboleth.oidc.metadata.context.OIDCMetadataContext;
import net.shibboleth.oidc.metadata.context.OIDCProviderMetadataContext;
import net.shibboleth.oidc.profile.config.OIDCAuthorizationConfiguration;
+import net.shibboleth.oidc.security.credential.ClientSecretCredential;
import net.shibboleth.oidc.security.jose.SignatureSigningConfiguration;
import net.shibboleth.oidc.security.jose.SignatureSigningParameters;
import net.shibboleth.oidc.security.jose.SignatureSigningParametersResolver;
@@ -47,7 +47,7 @@ import net.shibboleth.oidc.security.jose.context.SecurityParametersContext;
import net.shibboleth.oidc.security.jose.criterion.ClientInformationCriterion;
import net.shibboleth.oidc.security.jose.criterion.ProviderMetadataCriterion;
import net.shibboleth.oidc.security.jose.criterion.SignatureSigningConfigurationCriterion;
-import net.shibboleth.oidc.security.jose.criterion.StaticCredentialCriterion;
+import net.shibboleth.oidc.security.jose.criterion.ClientSecretCredentialCriterion;
import net.shibboleth.utilities.java.support.annotation.constraint.NonnullAfterInit;
import net.shibboleth.utilities.java.support.component.ComponentInitializationException;
import net.shibboleth.utilities.java.support.component.ComponentSupport;
@@ -312,7 +312,7 @@ public class PopulateJWTSignatureSigningParametersHandler extends AbstractMessag
}
if (messageContext.getParent() instanceof ProfileRequestContext) {
- // Add any static credentials from the RP context
+ // Add any static client secret credentials from the RP context
final RelyingPartyContext rpCtx =
relyingPartyContextLookupStrategy.apply(messageContext);
if (rpCtx != null && rpCtx.getConfiguration() != null &&
@@ -321,10 +321,10 @@ public class PopulateJWTSignatureSigningParametersHandler extends AbstractMessag
(OIDCAuthorizationConfiguration) rpCtx.getProfileConfig();
if (profileConfiguration != null) {
- final Credential credential = profileConfiguration.getClientCredential(
+ final ClientSecretCredential credential = profileConfiguration.getClientCredential(
(ProfileRequestContext)messageContext.getParent());
if (credential != null) {
- criteria.add(new StaticCredentialCriterion(credential));
+ criteria.add(new ClientSecretCredentialCriterion(credential));
} else {
log.trace("{} No credential found from the profile configuration", getLogPrefix());
}
--
To stop receiving notification emails like this one, please contact
the administrator of this repository.
More information about the commits
mailing list