[java-idp-plugin-oidc-rp] branch main updated: Update client authentication handler to use JWSTokenSigner in commons
Phil Smart
philip.smart at jisc.ac.uk
Tue Oct 3 11:12:17 UTC 2023
This is an automated email from the git hooks/post-receive script.
philsmart pushed a commit to branch main
in repository java-idp-plugin-oidc-rp.
View the commit online:
http://git.shibboleth.net/view/?p=java-idp-plugin-oidc-rp.git;a=commit;h=8493d99d354fd7f8ac565f12f22601550423bc1a
The following commit(s) were added to refs/heads/main by this push:
new 8493d99 Update client authentication handler to use JWSTokenSigner in commons
8493d99 is described below
commit 8493d99d354fd7f8ac565f12f22601550423bc1a
Author: Phil Smart <philip.smart at jisc.ac.uk>
AuthorDate: Tue Oct 3 12:12:10 2023 +0100
Update client authentication handler to use JWSTokenSigner in commons
---
...izeOAuth2ClientAuthenticationMethodHandler.java | 170 ++++-----------------
1 file changed, 31 insertions(+), 139 deletions(-)
diff --git a/idp-oidc-rp-impl/src/main/java/net/shibboleth/idp/plugin/authn/oidc/rp/impl/InitializeOAuth2ClientAuthenticationMethodHandler.java b/idp-oidc-rp-impl/src/main/java/net/shibboleth/idp/plugin/authn/oidc/rp/impl/InitializeOAuth2ClientAuthenticationMethodHandler.java
index 8352120..66e68b0 100644
--- a/idp-oidc-rp-impl/src/main/java/net/shibboleth/idp/plugin/authn/oidc/rp/impl/InitializeOAuth2ClientAuthenticationMethodHandler.java
+++ b/idp-oidc-rp-impl/src/main/java/net/shibboleth/idp/plugin/authn/oidc/rp/impl/InitializeOAuth2ClientAuthenticationMethodHandler.java
@@ -14,8 +14,6 @@
package net.shibboleth.idp.plugin.authn.oidc.rp.impl;
-import java.nio.charset.StandardCharsets;
-import java.security.interfaces.ECPrivateKey;
import java.time.Duration;
import java.time.Instant;
import java.util.Date;
@@ -23,7 +21,6 @@ import java.util.function.Function;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
-import javax.crypto.SecretKey;
import org.opensaml.messaging.context.MessageContext;
import org.opensaml.messaging.context.navigate.ChildContextLookup;
@@ -32,19 +29,11 @@ import org.opensaml.messaging.handler.MessageHandlerException;
import org.opensaml.profile.action.EventIds;
import org.opensaml.profile.context.ProfileRequestContext;
import org.opensaml.profile.context.navigate.ParentProfileRequestContextLookup;
-import org.opensaml.security.credential.Credential;
import org.slf4j.Logger;
import com.nimbusds.jose.Algorithm;
-import com.nimbusds.jose.JOSEException;
import com.nimbusds.jose.JOSEObjectType;
import com.nimbusds.jose.JWSAlgorithm;
-import com.nimbusds.jose.JWSHeader;
-import com.nimbusds.jose.JWSObject.State;
-import com.nimbusds.jose.JWSSigner;
-import com.nimbusds.jose.crypto.ECDSASigner;
-import com.nimbusds.jose.crypto.MACSigner;
-import com.nimbusds.jose.crypto.RSASSASigner;
import com.nimbusds.jwt.JWTClaimsSet;
import com.nimbusds.jwt.SignedJWT;
import com.nimbusds.oauth2.sdk.auth.ClientAuthentication;
@@ -62,9 +51,9 @@ import net.shibboleth.oidc.authn.context.OAuth2ClientAuthenticationContext;
import net.shibboleth.oidc.metadata.context.OIDCProviderMetadataContext;
import net.shibboleth.oidc.profile.config.OIDCAuthenticationRelyingPartyProfileConfiguration;
import net.shibboleth.oidc.profile.messaging.context.OIDCPeerEntityContext;
-import net.shibboleth.oidc.security.CredentialConversionUtil;
import net.shibboleth.oidc.security.credential.ClientSecretCredential;
-import net.shibboleth.oidc.security.credential.JWKCredential;
+import net.shibboleth.oidc.security.impl.JWSTokenSigner;
+import net.shibboleth.oidc.security.jose.SignatureException;
import net.shibboleth.oidc.security.jose.SignatureSigningParameters;
import net.shibboleth.oidc.security.jose.context.SecurityParametersContext;
import net.shibboleth.profile.context.RelyingPartyContext;
@@ -311,7 +300,7 @@ public class InitializeOAuth2ClientAuthenticationMethodHandler extends AbstractM
}
if (clientAuthentication == null) {
- throw new MessageHandlerException("Client authentication could be constructed");
+ throw new MessageHandlerException("Client authentication could not be constructed");
}
oauth2ClientAuthenticationContext.setClientAuthentication(clientAuthentication);
@@ -331,17 +320,18 @@ public class InitializeOAuth2ClientAuthenticationMethodHandler extends AbstractM
final SecurityParametersContext bearerSecurityParams = jwtBearerClientAuthSecurityParameters;
if (bearerSecurityParams == null || bearerSecurityParams.getSignatureSigningParameters() == null) {
- throw new MessageHandlerException("Missing security parameters needed to build client_secret_jwt");
+ throw new MessageHandlerException("Missing security parameters needed to sign client_secret_jwt");
}
- final SignatureSigningParameters signatureSigningParameters = bearerSecurityParams.getSignatureSigningParameters();
+ final SignatureSigningParameters signatureSigningParameters =
+ bearerSecurityParams.getSignatureSigningParameters();
assert signatureSigningParameters != null;
if (signatureSigningParameters.getSignatureAlgorithm() == null ||
signatureSigningParameters.getSigningCredential() == null) {
- throw new MessageHandlerException("Missing credential needed to build client_secret_jwt");
+ throw new MessageHandlerException("Missing credential needed to sign client_secret_jwt");
}
- final Algorithm jwsAlgorithm = resolveAlgorithm(signatureSigningParameters);
+ final Algorithm jwsAlgorithm = new JWSAlgorithm(signatureSigningParameters.getSignatureAlgorithm());
if (!JWSAlgorithm.Family.HMAC_SHA.contains(jwsAlgorithm)) {
throw new MessageHandlerException("Trying to construct client_secret_jwt using the wrong algorithm: "
+ jwsAlgorithm);
@@ -359,16 +349,17 @@ public class InitializeOAuth2ClientAuthenticationMethodHandler extends AbstractM
final SecurityParametersContext bearerSecurityParams = jwtBearerClientAuthSecurityParameters;
if (bearerSecurityParams == null || bearerSecurityParams.getSignatureSigningParameters() == null) {
- throw new MessageHandlerException("Missing security parameters needed to private_key_jwt");
+ throw new MessageHandlerException("Missing security parameters needed to sign private_key_jwt");
}
- final SignatureSigningParameters signatureSigningParameters = bearerSecurityParams.getSignatureSigningParameters();
+ final SignatureSigningParameters signatureSigningParameters =
+ bearerSecurityParams.getSignatureSigningParameters();
assert signatureSigningParameters != null;
if (signatureSigningParameters.getSigningCredential() == null) {
- throw new MessageHandlerException("Missing credential needed to build private_key_jwt");
+ throw new MessageHandlerException("Missing credential needed to sign private_key_jwt");
}
- final Algorithm jwsAlgorithm = resolveAlgorithm(signatureSigningParameters);
+ final Algorithm jwsAlgorithm = new JWSAlgorithm(signatureSigningParameters.getSignatureAlgorithm());
if (!JWSAlgorithm.Family.SIGNATURE.contains(jwsAlgorithm)) {
throw new MessageHandlerException("Trying to construct private_key_jwt using the wrong algorithm: "
+ jwsAlgorithm);
@@ -398,136 +389,37 @@ public class InitializeOAuth2ClientAuthenticationMethodHandler extends AbstractM
* the correct 'alg' and credential existing in the security context ahead of time for the correct SignedJWT to be
* returned e.g. for either client_secret_jwt or private_key_jwt.
*
- * @return a signed JWT bearer token, or {@code null} if there was an error during construction
+ * @return a signed JWT bearer token, or throws an exception if there was an error during construction
+ *
+ * @throws MessageHandlerException on error constructing the JWT
*/
- @Nullable private SignedJWT buildClientAuthenticationJwt() {
+ @Nonnull private SignedJWT buildClientAuthenticationJwt() throws MessageHandlerException {
final SecurityParametersContext bearerSecurityParams = jwtBearerClientAuthSecurityParameters;
if (bearerSecurityParams == null) {
- log.error("{} Requested client_secret_jwt client authentication, but signing parameters context "
- + "could not be found",getLogPrefix());
- return null;
+ throw new MessageHandlerException("Requested client_secret_jwt client authentication, but "
+ + "signing parameters context could not be found");
}
final SignatureSigningParameters signingParams = bearerSecurityParams.getSignatureSigningParameters();
if (signingParams == null) {
- log.error("{} Requested client_secret_jwt client authentication, but signing parameters "
- + "could not be found",getLogPrefix());
- return null;
+ throw new MessageHandlerException("Requested client_secret_jwt client authentication, but "
+ + "signing parameters could not be found");
}
final JWTClaimsSet claims = buildClientAuthenticationJwtClaims();
- final SignedJWT signed = signClaims(claims, signingParams);
- if (signed == null) {
- log.trace("Could not construct client_secret_jwt client authentication");
- return null;
- }
- return signed;
- }
-
- /**
- * Sign the given JWT claims set using the signing parameters from the context.
- *
- * @param jwtClaimSetToSign the claims to sign
- * @param signingParams the signing parameters required to sign the JWT
- *
- * @return a signed JWT or {@code null} if an error occurs.
- */
- @Nullable private SignedJWT signClaims(@Nonnull final JWTClaimsSet jwtClaimSetToSign,
- @Nonnull final SignatureSigningParameters signingParams) {
+
try {
- SignedJWT jwt = null;
- final Credential credential = signingParams.getSigningCredential();
- if (credential == null) {
- log.error("{} JWT Bearer Token could not be signed, no signing credential found", getLogPrefix());
- return null;
- }
- final Algorithm jwsAlgorithm = resolveAlgorithm(signingParams);
- if (jwsAlgorithm == null) {
- log.error("{} JWT Bearer Token could not be signed, no signing algorithm found", getLogPrefix());
- return null;
- }
- final JWSSigner signer = getSigner(jwsAlgorithm, credential);
- final JWSHeader.Builder headerBuilder = new JWSHeader.Builder(new JWSAlgorithm(jwsAlgorithm.getName()))
- .keyID(CredentialConversionUtil.resolveKid(credential));
- headerBuilder.type(JOSEObjectType.JWT);
- jwt = new SignedJWT(headerBuilder.build(), jwtClaimSetToSign);
- jwt.sign(signer);
+ final JWSTokenSigner signer = new JWSTokenSigner(signingParams);
+ final SignedJWT signed = signer.sign(claims, JOSEObjectType.JWT.getType());
if (log.isDebugEnabled() && !log.isTraceEnabled()) {
- log.debug("{} Signed JWT Bearer Token for client authentication using kid '{}'", getLogPrefix(),
- CredentialConversionUtil.resolveKid(credential));
+ log.debug("{} Signed JWT Bearer Token for client authentication'", getLogPrefix());
} else if (log.isTraceEnabled()) {
- log.trace("{} Signed JWT Bearer Token for client authentication using kid '{}': {}", getLogPrefix(),
- CredentialConversionUtil.resolveKid(credential),jwt.serialize());
- }
-
- if (jwt.getState() != State.SIGNED) {
- // Should not really happen, as JOSEException should be thrown
- log.error("{} JWT Bearer Token for client authentication was not signed", getLogPrefix());
- return null;
- }
- return jwt;
-
- } catch (final JOSEException e) {
- log.error("{} Error signing claims set: {}", getLogPrefix(), e.getMessage());
- return null;
- }
- }
-
- /**
- * Returns correct implementation of signer based on algorithm type.
- *
- * @param jwsAlgorithm JWS algorithm
- * @param credential the credential to use
- * @return signer for algorithm and private key
- * @throws JOSEException if algorithm cannot be supported
- */
- private JWSSigner getSigner(@Nonnull final Algorithm jwsAlgorithm,
- @Nonnull final Credential credential) throws JOSEException {
- if (JWSAlgorithm.Family.EC.contains(jwsAlgorithm)) {
- return new ECDSASigner((ECPrivateKey) credential.getPrivateKey());
- }
- if (JWSAlgorithm.Family.RSA.contains(jwsAlgorithm)) {
- return new RSASSASigner(credential.getPrivateKey());
- }
- if (JWSAlgorithm.Family.HMAC_SHA.contains(jwsAlgorithm)) {
- return new MACSigner(credential.getSecretKey());
- }
- throw new JOSEException("Unsupported algorithm " + jwsAlgorithm.getName());
- }
-
- /**
- * Resolves JWS algorithm from signature signing parameters.
- *
- * @param params the signature signing parameters
- * @return JWS algorithm
- */
- @Nullable protected JWSAlgorithm resolveAlgorithm(@Nonnull final SignatureSigningParameters params) {
-
- if (params.getSignatureAlgorithm() == null) {
- log.trace("{} Signature algorithm is null", getLogPrefix());
- return null;
- }
- final JWSAlgorithm algorithm = new JWSAlgorithm(params.getSignatureAlgorithm());
- final Credential credential = params.getSigningCredential();
- if (credential instanceof final JWKCredential jwkCred && !algorithm.equals(jwkCred.getAlgorithm())) {
- log.debug("{} Signature signing algorithm {} differs from JWK algorithm '{}'", getLogPrefix(),
- algorithm.getName(), jwkCred.getAlgorithm() != null ?
- jwkCred.getAlgorithm() : "not specified");
- }
- log.trace("{} Algorithm resolved {}", getLogPrefix(), algorithm.getName());
- return algorithm;
- }
-
- /**
- * Convert the encoded byte array representing the secret into a UTF-8 String.
- *
- * @param key the key to convert
- * @return the UTF-8 encoded string value of the secret.
- */
- @Nullable private String convertSecretKeyToString(@Nullable final SecretKey key) {
- if (key == null || key.getEncoded() == null) {
- return null;
+ log.trace("{} Signed JWT Bearer Token for client authentication: {}", getLogPrefix()
+ ,signed.serialize());
+ }
+ return signed;
+ } catch (final SignatureException e) {
+ throw new MessageHandlerException(e);
}
- return new String(key.getEncoded(),StandardCharsets.UTF_8);
}
}
--
To stop receiving notification emails like this one, please contact
the administrator of this repository.
More information about the commits
mailing list