[java-oidc-common] branch main updated: Move Encrypt and Sign message handlers from the RP to commons

Phil Smart philip.smart at jisc.ac.uk
Tue Jan 3 15:30:22 UTC 2023


This is an automated email from the git hooks/post-receive script.

philsmart pushed a commit to branch main
in repository java-oidc-common.

View the commit online:
http://git.shibboleth.net/view/?p=java-oidc-common.git;a=commit;h=b7981cc99d7344857d9271f65609f7c67716eacd

The following commit(s) were added to refs/heads/main by this push:
     new b7981cc  Move Encrypt and Sign message handlers from the RP to commons
b7981cc is described below

commit b7981cc99d7344857d9271f65609f7c67716eacd
Author: Phil Smart <philip.smart at jisc.ac.uk>
AuthorDate: Tue Jan 3 15:30:19 2023 +0000

    Move Encrypt and Sign message handlers from the RP to commons
---
 .../oidc/security/impl/EncryptJWTHandler.java      | 286 +++++++++++++++++++++
 .../oidc/security/impl/SignJWTHandler.java         | 281 ++++++++++++++++++++
 2 files changed, 567 insertions(+)

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
new file mode 100644
index 0000000..eb11c8e
--- /dev/null
+++ b/oidc-common-crypto-impl/src/main/java/net/shibboleth/oidc/security/impl/EncryptJWTHandler.java
@@ -0,0 +1,286 @@
+/*
+ * 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.impl;
+
+import java.security.interfaces.ECPublicKey;
+import java.security.interfaces.RSAPublicKey;
+import java.util.function.BiConsumer;
+import java.util.function.Function;
+
+import javax.annotation.Nonnull;
+import javax.annotation.Nullable;
+
+import org.opensaml.messaging.context.MessageContext;
+import org.opensaml.messaging.context.navigate.ChildContextLookup;
+import org.opensaml.messaging.handler.AbstractMessageHandler;
+import org.opensaml.messaging.handler.MessageHandler;
+import org.opensaml.messaging.handler.MessageHandlerException;
+import org.opensaml.security.credential.Credential;
+import org.opensaml.xmlsec.EncryptionParameters;
+import org.opensaml.xmlsec.context.SecurityParametersContext;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.nimbusds.jose.EncryptionMethod;
+import com.nimbusds.jose.JWEAlgorithm;
+import com.nimbusds.jose.JWEHeader;
+import com.nimbusds.jose.JWEObject;
+import com.nimbusds.jose.Payload;
+import com.nimbusds.jose.crypto.AESEncrypter;
+import com.nimbusds.jose.crypto.DirectEncrypter;
+import com.nimbusds.jose.crypto.ECDHEncrypter;
+import com.nimbusds.jose.crypto.RSAEncrypter;
+import com.nimbusds.jwt.EncryptedJWT;
+import com.nimbusds.jwt.JWT;
+
+import net.shibboleth.oidc.security.JWTEncryptionParameters;
+import net.shibboleth.oidc.security.context.JWTSecurityParametersContext;
+import net.shibboleth.utilities.java.support.annotation.constraint.NonnullAfterInit;
+import net.shibboleth.utilities.java.support.annotation.constraint.NotEmpty;
+import net.shibboleth.utilities.java.support.component.ComponentInitializationException;
+import net.shibboleth.utilities.java.support.component.ComponentSupport;
+import net.shibboleth.utilities.java.support.logic.Constraint;
+import net.shibboleth.utilities.java.support.primitive.StringSupport;
+
+/**
+ * A {@link MessageHandler} that encrypts a JWT using the {@link EncryptionParameters} found in the 
+ * {@link JWTSecurityParametersContext}. The {@link Payload} to encrypt is determined by lookup strategy. 
+ * A consumer takes the {@link EncryptedJWT} and updates the correct object in the {@link MessageContext}.
+ */
+//TODO encrypt action is unpleasent to look at
+public class EncryptJWTHandler extends AbstractMessageHandler {
+    
+    /** Class logger. */
+    @Nonnull private final Logger log = LoggerFactory.getLogger(EncryptJWTHandler.class);
+    
+    /** Strategy used to locate the {@link SecurityParametersContext} to use for signing. */
+    @Nonnull private Function<MessageContext, JWTSecurityParametersContext> securityParametersLookupStrategy;
+    
+    /** Strategy used to locate the payload to encrypt.*/
+    @NonnullAfterInit private Function<MessageContext, Payload> payloadToEncryptLookupStrategy;
+    
+    /** A consumer that takes the EncryptedJWT and updates the correct object inside the MessageContext.*/
+    @NonnullAfterInit private BiConsumer<JWT, MessageContext> jwtUpdateConsumer;
+    
+    /** The signature signing parameters. */
+    @Nullable private JWTEncryptionParameters encryptionParameters;
+    
+    /** A friendly name to log as the subject of encryption.*/
+    @Nonnull private String logName;
+    
+    
+    /** Constructor.*/
+    public EncryptJWTHandler() { 
+        logName = "not-specified";
+        securityParametersLookupStrategy = new ChildContextLookup<>(JWTSecurityParametersContext.class);
+    }
+    
+    /**
+     * Set the friendly name to log as the subject of encryption.
+     * 
+     * @param name the friendly name
+     */
+    public void setLogName(@Nonnull @NotEmpty final String name) {
+        ComponentSupport.ifInitializedThrowUnmodifiabledComponentException(this);
+        ComponentSupport.ifDestroyedThrowDestroyedComponentException(this);
+
+        logName = Constraint.isNotEmpty(name, "ForFriendlyName can not be null or empty");
+    }
+    
+    /**
+     * Set the consumer used to update the MessageContext with the supplied EncryptedJWT.
+     * 
+     * @param consumer the consumer
+     */
+    public void setJwtUpdateConsumer(final BiConsumer<JWT, MessageContext> consumer) {
+        ComponentSupport.ifInitializedThrowUnmodifiabledComponentException(this);
+        ComponentSupport.ifDestroyedThrowDestroyedComponentException(this);
+
+        jwtUpdateConsumer = Constraint.isNotNull(consumer, "JWT Update Consumer can not be null");
+    }
+    
+    /**
+     * Set the strategy used to locate the {@link Payload} to encrypt.
+     * 
+     * @param strategy the strategy
+     */
+    public void setPayloadToEncryptLookupStrategy(@Nonnull final Function<MessageContext, Payload> strategy) {
+        ComponentSupport.ifInitializedThrowUnmodifiabledComponentException(this);
+        ComponentSupport.ifDestroyedThrowDestroyedComponentException(this);
+
+        payloadToEncryptLookupStrategy =
+                Constraint.isNotNull(strategy, "Payload To Encrypt Lookup Strategy can not be null");
+    }
+    
+    /**
+     * Set the strategy used to locate the {@link SecurityParametersContext} to use.
+     * 
+     * @param strategy lookup strategy
+     */
+    public void setSecurityParametersLookupStrategy(
+            @Nonnull final Function<MessageContext, JWTSecurityParametersContext> strategy) {
+        ComponentSupport.ifInitializedThrowUnmodifiabledComponentException(this);
+
+        securityParametersLookupStrategy =
+                Constraint.isNotNull(strategy, "SecurityParameterContext lookup strategy cannot be null");
+    }
+    
+    @Override
+    protected void doInitialize() throws ComponentInitializationException {
+        if (payloadToEncryptLookupStrategy == null) {
+            throw new ComponentInitializationException("Payload To Encrypt Lookup Strategy can not be null");
+        }
+        if (jwtUpdateConsumer == null) {
+            throw new ComponentInitializationException("JWT Update Consumer can not be null");
+        }
+        super.doInitialize();
+    }
+
+    
+    @Override
+    protected boolean doPreInvoke(@Nonnull final MessageContext messageContext) throws MessageHandlerException {
+        
+        if (!super.doPreInvoke(messageContext)) {
+            return false;
+        }        
+            
+        final JWTSecurityParametersContext secParamCtx = 
+                securityParametersLookupStrategy.apply(messageContext);
+        if (secParamCtx == null) {
+            log.trace("{} Message context did not contain an encryption parameters context, "
+                    + "encryption skipped", getLogPrefix());
+            return false;
+        }
+        
+        encryptionParameters = secParamCtx.getEncryptionParameters();
+        if (encryptionParameters == null) {
+            log.debug("{} Message context did not contain encryption parameters, "
+                    + "request object will not be encrypted", getLogPrefix());
+            return false;
+        }
+        
+        // If we have parameters (so encryption is enabled), but the parameters are not in the correct state, 
+        // throw an exception as opposed to skipping encryption
+        if (StringSupport.trimOrNull(encryptionParameters.getKeyTransportEncryptionAlgorithm()) == null ||
+                StringSupport.trimOrNull(encryptionParameters.getDataEncryptionAlgorithm()) == null ||
+                (encryptionParameters.getKeyTransportEncryptionCredential() == null &&
+                encryptionParameters.getDataEncryptionCredential() == null)) {
+            throw new MessageHandlerException("Message context did not contain all required encryption parameters");
+        }
+        if (encryptionParameters.getKeyTransportEncryptionCredential() != null &&
+                encryptionParameters.getDataEncryptionCredential() != null) {
+            throw new MessageHandlerException("Message context contained both a content encryption and "
+                    + "key transport credential. Only one required.");
+        }
+        
+        return true;
+    }    
+
+    @Override
+    protected void doInvoke(@Nonnull final MessageContext messageContext) throws MessageHandlerException {
+        
+        final Payload payload = payloadToEncryptLookupStrategy.apply(messageContext);
+        if (payload == null) {
+            log.trace("{} No plain text source payload provided to encrypt, encryption skipped", getLogPrefix());
+            return;
+        }
+        
+        final JWEAlgorithm encAlg = JWEAlgorithm.parse(encryptionParameters.getKeyTransportEncryptionAlgorithm());
+        final EncryptionMethod encEnc = EncryptionMethod.parse(encryptionParameters.getDataEncryptionAlgorithm());
+        
+        
+        final Credential keyTransportCredential = encryptionParameters.getKeyTransportEncryptionCredential();
+        final Credential dataEncryptionCredential = encryptionParameters.getDataEncryptionCredential();
+        
+        final String keyTransportKid = keyTransportCredential == null ? null : 
+            CredentialConversionUtil.resolveKid(keyTransportCredential);
+        final String dataEncryptionKid = dataEncryptionCredential == null ? null : 
+            CredentialConversionUtil.resolveKid(dataEncryptionCredential);
+
+        JWEObject jweObject = null;
+        try {            
+            if (JWEAlgorithm.Family.RSA.contains(encAlg) && keyTransportCredential != null &&
+                    keyTransportCredential.getPublicKey() != null) {
+                
+                jweObject = new JWEObject(new JWEHeader.Builder(encAlg, encEnc).contentType("JWT")
+                                .keyID(keyTransportKid).build(), payload);
+                logEncryption(keyTransportKid, encAlg.getName(), encEnc.getName());
+                jweObject.encrypt(new RSAEncrypter((RSAPublicKey) keyTransportCredential.getPublicKey()));
+                
+            } else if (JWEAlgorithm.Family.ECDH_ES.contains(encAlg) && keyTransportCredential != null &&
+                    keyTransportCredential.getPublicKey() != null) {
+                
+                jweObject = new JWEObject(new JWEHeader.Builder(encAlg, encEnc).contentType("JWT")
+                        .keyID(keyTransportKid).build(), payload);                
+                logEncryption(keyTransportKid, encAlg.getName(), encEnc.getName());
+                jweObject.encrypt(new ECDHEncrypter((ECPublicKey) keyTransportCredential.getPublicKey()));
+                
+            } else if ((JWEAlgorithm.Family.AES_KW.contains(encAlg) || JWEAlgorithm.Family.AES_GCM_KW.contains(encAlg)) 
+                    && keyTransportCredential != null && keyTransportCredential.getSecretKey() != null) {
+                
+                jweObject = new JWEObject(new JWEHeader.Builder(encAlg, encEnc).contentType("JWT")
+                        .keyID(keyTransportKid).build(), payload);
+                logEncryption(keyTransportKid, encAlg.getName(), encEnc.getName());              
+                jweObject.encrypt(new AESEncrypter(keyTransportCredential.getSecretKey()));
+                
+            } else if (JWEAlgorithm.DIR.equals(encAlg) && dataEncryptionCredential != null &&
+                    dataEncryptionCredential.getSecretKey() != null){
+                
+                jweObject = new JWEObject(new JWEHeader.Builder(encAlg, encEnc).contentType("JWT")
+                        .keyID(dataEncryptionKid).build(), payload);
+                logEncryption(dataEncryptionKid, encAlg.getName(), encEnc.getName());      
+                jweObject.encrypt(new DirectEncrypter(dataEncryptionCredential.getSecretKey()));
+                
+            } else {
+                log.error("{} Unsupported algorithm '{}' or key '{}'", getLogPrefix(), encAlg.getName(),
+                        keyTransportKid);
+                throw new MessageHandlerException("Unsupported algorithm "+encAlg.getName());
+            }
+
+            final EncryptedJWT encryptedJWT = EncryptedJWT.parse(jweObject.serialize());
+            jwtUpdateConsumer.accept(encryptedJWT, messageContext);
+            
+            if (log.isDebugEnabled() && !log.isTraceEnabled()) {
+                log.debug("{} Encrypted '{}' JWT", getLogPrefix(), logName);
+            } else if (log.isTraceEnabled()) {
+                log.debug("{} Encrypted '{}' JWT: {}", getLogPrefix(), logName, encryptedJWT.serialize());
+            }
+            
+        } catch (final Exception e) {
+            log.error("{} Encryption failed", getLogPrefix(), e);           
+            throw new MessageHandlerException("Encryption failed", e);
+        }
+        
+    }
+    
+    /**
+     * A convince method to log encryption parameters. Avoids some of the clutter in the calling
+     * methods.
+     * 
+     * @param keyID the keyID
+     * @param enc the content encryption algorithm
+     * @param alg the key management algorithm
+     */
+    private void logEncryption(@Nullable final String keyID, 
+            @Nullable final String enc, @Nullable final String alg) {
+        log.debug("{} Encrypting '{}' with kid '{}' and params alg: {} enc: {}", 
+                getLogPrefix(), logName, keyID, alg, enc); 
+    }
+
+}
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
new file mode 100644
index 0000000..8aff29b
--- /dev/null
+++ b/oidc-common-crypto-impl/src/main/java/net/shibboleth/oidc/security/impl/SignJWTHandler.java
@@ -0,0 +1,281 @@
+/*
+ * 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.impl;
+
+import java.security.interfaces.ECPrivateKey;
+import java.util.function.BiConsumer;
+import java.util.function.Function;
+
+import javax.annotation.Nonnull;
+import javax.annotation.Nullable;
+
+import org.opensaml.messaging.context.MessageContext;
+import org.opensaml.messaging.context.navigate.ChildContextLookup;
+import org.opensaml.messaging.handler.AbstractMessageHandler;
+import org.opensaml.messaging.handler.MessageHandlerException;
+import org.opensaml.security.credential.Credential;
+import org.opensaml.xmlsec.context.SecurityParametersContext;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+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.JWT;
+import com.nimbusds.jwt.JWTClaimsSet;
+import com.nimbusds.jwt.SignedJWT;
+
+import net.shibboleth.oidc.security.JWTSignatureSigningParameters;
+import net.shibboleth.oidc.security.context.JWTSecurityParametersContext;
+import net.shibboleth.oidc.security.credential.JWKCredential;
+import net.shibboleth.utilities.java.support.annotation.constraint.NonnullAfterInit;
+import net.shibboleth.utilities.java.support.annotation.constraint.NotEmpty;
+import net.shibboleth.utilities.java.support.component.ComponentInitializationException;
+import net.shibboleth.utilities.java.support.component.ComponentSupport;
+import net.shibboleth.utilities.java.support.logic.Constraint;
+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. */
+    @Nonnull private final Logger log = LoggerFactory.getLogger(SignJWTHandler.class);
+    
+    /** Strategy used to locate the {@link SecurityParametersContext} to use for signing. */
+    @Nonnull private Function<MessageContext, JWTSecurityParametersContext> securityParametersLookupStrategy;
+    
+    /** A consumer that takes the EncryptedJWT and updates the correct object inside the MessageContext.*/
+    @NonnullAfterInit private BiConsumer<JWT, MessageContext> jwtUpdateConsumer;
+    
+    /** Strategy used to locate the payload to encrypt.*/
+    @NonnullAfterInit private Function<MessageContext, JWTClaimsSet> claimsToSignLookupStrategy;    
+       
+    /** The signature signing parameters. */
+    @Nullable private JWTSignatureSigningParameters signatureSigningParameters;
+    
+    /** resolved credential. */
+    @Nullable private Credential credential;
+    
+    /** The claims to sign.*/
+    @Nullable private JWTClaimsSet jwtClaimSetToSign;
+    
+    /** "typ" header to insert while signing. */
+    @Nullable @NotEmpty private String typeHeader;
+    
+    /** A friendly name to log as the subject of signing.*/
+    @Nonnull private String logName;
+    
+    /** Constructor.*/
+    public SignJWTHandler() {
+        logName = "not-specified";
+        securityParametersLookupStrategy = new ChildContextLookup<>(JWTSecurityParametersContext.class);        
+    }
+    
+    /**
+     * Set the friendly name to log as the subject of signing.
+     * 
+     * @param name the friendly name
+     */
+    public void setLogName(@Nonnull @NotEmpty final String name) {
+        ComponentSupport.ifInitializedThrowUnmodifiabledComponentException(this);
+        ComponentSupport.ifDestroyedThrowDestroyedComponentException(this);
+
+        logName = Constraint.isNotEmpty(name, "ForFriendlyName can not be null or empty");
+    }
+    
+    @Override
+    protected void doInitialize() throws ComponentInitializationException {
+        if (claimsToSignLookupStrategy == null) {
+            throw new ComponentInitializationException("Claims To Sign Lookup Strategy can not be null");
+        }
+        if (jwtUpdateConsumer == null) {
+            throw new ComponentInitializationException("JWT Update Consumer can not be null");
+        }
+        super.doInitialize();
+    }
+    
+    /**
+     * Set the strategy used to locate the {@link JWTClaimsSet} to sign.
+     * 
+     * @param strategy the strategy
+     */
+    public void setClaimsToSignLookupStrategy(@Nonnull final Function<MessageContext, JWTClaimsSet> strategy) {
+        ComponentSupport.ifInitializedThrowUnmodifiabledComponentException(this);
+        ComponentSupport.ifDestroyedThrowDestroyedComponentException(this);
+
+        claimsToSignLookupStrategy =
+                Constraint.isNotNull(strategy, "Claims To Sign Lookup Strategy can not be null");
+    }
+    
+    /**
+     * Set the consumer used to update the MessageContext with the supplied EncryptedJWT.
+     * 
+     * @param consumer the consumer
+     */
+    public void setJwtUpdateConsumer(final BiConsumer<JWT, MessageContext> consumer) {
+        ComponentSupport.ifInitializedThrowUnmodifiabledComponentException(this);
+        ComponentSupport.ifDestroyedThrowDestroyedComponentException(this);
+
+        jwtUpdateConsumer = Constraint.isNotNull(consumer, "JWT Update Consumer can not be null");
+    }
+    
+    /**
+     * Sets the value to be inserted as a "typ" header for the JWS.
+     * 
+     * @param type header value
+     */
+    public void setTypeHeader(@Nullable @NotEmpty final String type) {
+        ComponentSupport.ifInitializedThrowUnmodifiabledComponentException(this);
+        
+        typeHeader = StringSupport.trimOrNull(type);
+    }
+    
+    /**
+     * Set the strategy used to locate the {@link SecurityParametersContext} to use.
+     * 
+     * @param strategy lookup strategy
+     */
+    public void setSecurityParametersLookupStrategy(
+            @Nonnull final Function<MessageContext, JWTSecurityParametersContext> strategy) {
+        ComponentSupport.ifInitializedThrowUnmodifiabledComponentException(this);
+
+        securityParametersLookupStrategy =
+                Constraint.isNotNull(strategy, "SecurityParameterContext lookup strategy cannot be null");
+    }
+    
+    /** {@inheritDoc} */
+    @Override
+    protected boolean doPreInvoke(@Nonnull final MessageContext messageContext) throws MessageHandlerException {
+        
+        if (!super.doPreInvoke(messageContext)) {
+            return false;
+        }  
+                  
+        final JWTSecurityParametersContext secParamCtx = 
+                securityParametersLookupStrategy.apply(messageContext);
+        if (secParamCtx == null) {
+            log.debug("{} Message context did not contain a signing parameters context, "
+                    + "signing skipped", getLogPrefix());
+            return false;
+        }
+        
+        signatureSigningParameters = secParamCtx.getSignatureSigningParameters();
+        if (signatureSigningParameters == null || signatureSigningParameters.getSigningCredential() == null) {
+            log.debug("{} No signature signing credentials available", getLogPrefix());
+            return false;
+        }
+        
+        jwtClaimSetToSign = claimsToSignLookupStrategy.apply(messageContext);
+        if (jwtClaimSetToSign == null) {
+            log.debug("{} No JWT claims, nothing to sign", getLogPrefix());
+            return false;
+        }
+        
+        credential = signatureSigningParameters.getSigningCredential();
+        
+        return true;
+         
+    }
+    
+    @Override
+    protected void doInvoke(@Nonnull final MessageContext messageContext) throws MessageHandlerException {
+                    
+        try {
+            SignedJWT jwt = null; 
+            final Algorithm jwsAlgorithm = resolveAlgorithm();
+            final JWSSigner signer = getSigner(jwsAlgorithm);
+            final JWSHeader.Builder headerBuilder = new JWSHeader.Builder(new JWSAlgorithm(jwsAlgorithm.getName()))
+                    .keyID(CredentialConversionUtil.resolveKid(credential));
+            if (typeHeader != null) {
+                headerBuilder.type(new JOSEObjectType(typeHeader));
+            }
+            jwt = new SignedJWT(headerBuilder.build(), jwtClaimSetToSign);
+            jwt.sign(signer);
+            if (log.isDebugEnabled() && !log.isTraceEnabled()) {
+                log.debug("{} Signed JWT '{}'", getLogPrefix(), logName);
+            } else if (log.isTraceEnabled()) {
+                log.trace("{} Signed JWT '{}': {}", getLogPrefix(), logName, jwt.serialize());
+            }            
+            
+            if (jwt.getState() != State.SIGNED) {
+                // Should not really happen, as JOSEException should be thrown
+                log.error("{} JWT '{}' was not signed", getLogPrefix(), logName);
+                throw new MessageHandlerException("JWT was not signed, unknown cause");
+            }
+            
+            // Use consumer to update the signed JWT
+            jwtUpdateConsumer.accept(jwt, messageContext);
+            
+        } catch (final JOSEException e) {
+            log.error("{} Error signing claim set: {}", getLogPrefix(), e.getMessage());
+            throw new MessageHandlerException("Error signing claims set",e);
+        }
+        
+        
+    }
+    
+    /**
+     * Returns correct implementation of signer based on algorithm type.
+     * 
+     * @param jwsAlgorithm JWS algorithm
+     * @return signer for algorithm and private key
+     * @throws JOSEException if algorithm cannot be supported
+     */
+    private JWSSigner getSigner(final Algorithm jwsAlgorithm) 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.
+     * 
+     * @return JWS algorithm
+     */
+    protected JWSAlgorithm resolveAlgorithm() {
+
+        final JWSAlgorithm algorithm = new JWSAlgorithm(signatureSigningParameters.getSignatureAlgorithm());
+        if (credential instanceof JWKCredential && !algorithm.equals(((JWKCredential) credential).getAlgorithm())) {
+            log.debug("{} Signature signing algorithm {} differs from JWK algorithm {}", getLogPrefix(),
+                    algorithm.getName(), (((JWKCredential) credential).getAlgorithm() != null ? 
+                            ((JWKCredential) credential).getAlgorithm() : "not specified"));            
+        }
+        log.trace("{} Algorithm resolved {}", getLogPrefix(), algorithm.getName());
+        return algorithm;
+    }
+
+
+
+}

-- 
To stop receiving notification emails like this one, please contact
the administrator of this repository.


More information about the commits mailing list