[java-idp-plugin-duo] branch main updated: JDUO-20 - Remove Auth0 dependency from Nimbus Client

Phil Smart philip.smart at jisc.ac.uk
Thu Oct 29 17:16:09 UTC 2020


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

philsmart pushed a commit to branch main
in repository java-idp-plugin-duo.

View the commit online:
http://git.shibboleth.net/view/?p=java-idp-plugin-duo.git;a=commit;h=37ce5efb56437cce5e5df20b555c7173bd322866

The following commit(s) were added to refs/heads/main by this push:
       new  37ce5ef   JDUO-20 - Remove Auth0 dependency from Nimbus Client
37ce5ef is described below

commit 37ce5efb56437cce5e5df20b555c7173bd322866
Author: Phil Smart <philip.smart at jisc.ac.uk>
AuthorDate: Thu Oct 29 17:16:02 2020 +0000

    JDUO-20 - Remove Auth0 dependency from Nimbus Client
    
     HMAC is now generated by combining lower level Nimbus functions that
    bypass key length size checks.
    
    https://issues.shibboleth.net/jira/browse/JDUO-20
---
 .../idp/plugin/authn/duo/DuoOIDCModule.java        |   4 +
 .../idp/plugin/authn/duo/DuoOIDCPlugin.java        |  68 ++----
 .../flows/authn/DuoOIDC/duo-oidc-authn-beans.xml   |   1 -
 idp-duo-nimbus-client-impl/pom.xml                 |  34 +--
 .../idp/plugin/authn/duo/nimbus/NimbusClient.java  |   6 +-
 .../authn/duo/nimbus/NimbusClientSupport.java      | 255 +++++++++++++++++++++
 .../idp/plugin/authn/duo/nimbus/NimbusUtils.java   | 127 ----------
 7 files changed, 297 insertions(+), 198 deletions(-)

diff --git a/idp-duo-impl/src/main/java/net/shibboleth/idp/plugin/authn/duo/DuoOIDCModule.java b/idp-duo-impl/src/main/java/net/shibboleth/idp/plugin/authn/duo/DuoOIDCModule.java
index d03c3af..08aceba 100644
--- a/idp-duo-impl/src/main/java/net/shibboleth/idp/plugin/authn/duo/DuoOIDCModule.java
+++ b/idp-duo-impl/src/main/java/net/shibboleth/idp/plugin/authn/duo/DuoOIDCModule.java
@@ -2,9 +2,13 @@ package net.shibboleth.idp.plugin.authn.duo;
 
 import java.io.IOException;
 
+import net.shibboleth.idp.module.IdPModule;
 import net.shibboleth.idp.module.ModuleException;
 import net.shibboleth.idp.module.impl.PluginIdPModule;
 
+/**
+ * {@link IdPModule} implementation.
+ */
 public class DuoOIDCModule extends PluginIdPModule {
 
     /**
diff --git a/idp-duo-impl/src/main/java/net/shibboleth/idp/plugin/authn/duo/DuoOIDCPlugin.java b/idp-duo-impl/src/main/java/net/shibboleth/idp/plugin/authn/duo/DuoOIDCPlugin.java
index 9634607..b2273ab 100644
--- a/idp-duo-impl/src/main/java/net/shibboleth/idp/plugin/authn/duo/DuoOIDCPlugin.java
+++ b/idp-duo-impl/src/main/java/net/shibboleth/idp/plugin/authn/duo/DuoOIDCPlugin.java
@@ -18,69 +18,31 @@
 package net.shibboleth.idp.plugin.authn.duo;
 
 import java.io.IOException;
-import java.net.URL;
 import java.util.Collections;
-import java.util.List;
 
-import javax.annotation.Nonnull;
-
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-import org.springframework.core.io.ClassPathResource;
-
-import net.shibboleth.idp.plugin.AbstractIdPPlugin;
-import net.shibboleth.idp.plugin.PluginVersion;
-import net.shibboleth.utilities.java.support.annotation.constraint.NonnullElements;
-import net.shibboleth.utilities.java.support.annotation.constraint.NotEmpty;
+import net.shibboleth.idp.module.IdPModule;
+import net.shibboleth.idp.module.ModuleException;
+import net.shibboleth.idp.plugin.PluginException;
+import net.shibboleth.idp.plugin.impl.FirstPartyIdPPlugin;
 
 /**
  * Details about the Duo OIDC 2FA plugin.
  */
-public class DuoOIDCPlugin extends AbstractIdPPlugin{
+public class DuoOIDCPlugin extends FirstPartyIdPPlugin{
     
-    /** The version of this plugin. */
-    @Nonnull final private PluginVersion myVersion;
     
     /** Constructor.*/
-    public DuoOIDCPlugin() {
-        final String versionAsString = Version.getVersion();
-        if (versionAsString == null) {
-            final Logger log = LoggerFactory.getLogger(DuoOIDCPlugin.class);
-            myVersion = new PluginVersion(0,0,1);
-            log.warn("{} must be run from a jar, taking a version of {}.{}.{}", DuoOIDCPlugin.class,
-                    myVersion.getMajor(),myVersion.getMinor(),myVersion.getPatch());
-           
-        } else {
-            myVersion = new PluginVersion(versionAsString);
+    public DuoOIDCPlugin() throws IOException, PluginException{
+        super(DuoOIDCPlugin.class);
+        try {
+            final IdPModule module = new DuoOIDCModule();
+            setEnableOnInstall(Collections.singleton(module));
+            setDisableOnRemoval(Collections.singleton(module));
+        } catch (final IOException e) {
+            throw e;
+        } catch (final ModuleException e) {
+            throw new PluginException(e);
         }
     }
 
-    @Override
-    @Nonnull @NotEmpty public String getPluginId() {
-        return "net.shibboleth.idp.plugin.duo";
-    }
-    
-    /** {@inheritDoc} */
-    @Override
-    @Nonnull @NonnullElements public List<URL> getUpdateURLs() throws IOException {
-        return Collections.singletonList(new ClassPathResource("META-INF/plugins/plugin.props").getURL());
-    }
-
-
-    @Override
-    public int getMajorVersion() {
-        return myVersion.getMajor();
-    }
-
-    @Override
-    public int getMinorVersion() {
-        return myVersion.getMinor();
-    }
-
-    @Override
-    public int getPatchVersion() {
-        return myVersion.getPatch();
-    }
-
-
 }
diff --git a/idp-duo-impl/src/main/resources/META-INF/net/shibboleth/idp/flows/authn/DuoOIDC/duo-oidc-authn-beans.xml b/idp-duo-impl/src/main/resources/META-INF/net/shibboleth/idp/flows/authn/DuoOIDC/duo-oidc-authn-beans.xml
index e952ca9..f8161f3 100644
--- a/idp-duo-impl/src/main/resources/META-INF/net/shibboleth/idp/flows/authn/DuoOIDC/duo-oidc-authn-beans.xml
+++ b/idp-duo-impl/src/main/resources/META-INF/net/shibboleth/idp/flows/authn/DuoOIDC/duo-oidc-authn-beans.xml
@@ -50,7 +50,6 @@
 
     <!-- Can override one or more of the beans above. Note, the property override is mostly to allow tests
     to change the location of the user config file. -->
-    <!--  FIXME: Add this back in as conditional import-->
     <import resource="conditional:%{idp.home}%{idp.duo.oidc.user.config.home:/conf/authn/duo-oidc-authn-config.xml}" />
 
     <!-- Prototype per conversation beans -->
diff --git a/idp-duo-nimbus-client-impl/pom.xml b/idp-duo-nimbus-client-impl/pom.xml
index 99a2bd3..121a1e0 100644
--- a/idp-duo-nimbus-client-impl/pom.xml
+++ b/idp-duo-nimbus-client-impl/pom.xml
@@ -27,16 +27,8 @@
             <groupId>com.nimbusds</groupId>
             <artifactId>nimbus-jose-jwt</artifactId>
             <version>9.0</version>
-        </dependency>    
-        
-        <!-- REMOVE THIS FOR NIMBUS, USED TO GET SIGNATURES WORKING -->
-         <dependency>
-            <groupId>com.auth0</groupId>
-            <artifactId>java-jwt</artifactId>
-            <version>3.3.0</version>
         </dependency>
-        <!--  DONE -->
-            
+
         <!-- provided dependencies -->
         <dependency>
             <groupId>com.google.code.findbugs</groupId>
@@ -51,26 +43,40 @@
         <dependency>
             <groupId>com.fasterxml.jackson.core</groupId>
             <artifactId>jackson-databind</artifactId>
-              <scope>provided</scope>
+            <scope>provided</scope>
         </dependency>
         <dependency>
             <groupId>com.fasterxml.jackson.datatype</groupId>
             <artifactId>jackson-datatype-jsr310</artifactId>
-              <scope>provided</scope>
+            <scope>provided</scope>
         </dependency>
         <dependency> <!-- required for the DuoIntegration -->
             <groupId>${idp.groupId}</groupId>
             <artifactId>idp-authn-api</artifactId>
             <scope>provided</scope>
         </dependency>
-         <dependency>
+        <dependency>
             <groupId>ch.qos.logback</groupId>
             <artifactId>logback-classic</artifactId>
             <scope>provided</scope>
         </dependency>
         <!-- Test dependencies -->
-        
-       
+        <dependency>
+            <groupId>org.opensaml</groupId>
+            <artifactId>opensaml-security-impl</artifactId>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>net.shibboleth.idp</groupId>
+            <artifactId>idp-profile-spring</artifactId>
+            <scope>test</scope>
+        </dependency>
+         <dependency>
+            <groupId>org.springframework</groupId>
+            <artifactId>spring-core</artifactId>
+            <scope>test</scope>
+        </dependency>
+
 
     </dependencies>
 
diff --git a/idp-duo-nimbus-client-impl/src/main/java/net/shibboleth/idp/plugin/authn/duo/nimbus/NimbusClient.java b/idp-duo-nimbus-client-impl/src/main/java/net/shibboleth/idp/plugin/authn/duo/nimbus/NimbusClient.java
index 6ab0dc4..3d69b09 100644
--- a/idp-duo-nimbus-client-impl/src/main/java/net/shibboleth/idp/plugin/authn/duo/nimbus/NimbusClient.java
+++ b/idp-duo-nimbus-client-impl/src/main/java/net/shibboleth/idp/plugin/authn/duo/nimbus/NimbusClient.java
@@ -112,7 +112,7 @@ final class NimbusClient implements DuoOIDCClient{
             final RequestBuilder rb =
                     RequestBuilder.post().setUri(uri).addParameter("client_id",duoIntegration.getClientId())
                     .addParameter("client_assertion",
-                            NimbusUtils.createJWS(uri.toString(), duoIntegration));
+                            NimbusClientSupport.createJWS(uri.toString(), duoIntegration));
 
             return executeRequest(rb.build(), new TypeReference<DuoHealthCheck>() {});
            
@@ -131,7 +131,7 @@ final class NimbusClient implements DuoOIDCClient{
         Constraint.isLessThan(1025, state.length(),"State must be at maximum 1024 characters");
         
         try {
-            final String request = NimbusUtils.createJWSRequestObject(duoIntegration,state, username);
+            final String request = NimbusClientSupport.createJWSRequestObject(duoIntegration,state, username);
             
             final URI uri = new URIBuilder()
                     .setScheme(HTTPS)
@@ -169,7 +169,7 @@ final class NimbusClient implements DuoOIDCClient{
                     .addParameter("redirect_uri",duoIntegration.getRedirectURI())
                     .addParameter("client_assertion_type",CLIENT_ASSERTION_TYPE)
                     .addParameter("client_assertion",
-                            NimbusUtils.createJWS(uri.toString(),duoIntegration));
+                            NimbusClientSupport.createJWS(uri.toString(),duoIntegration));
             
             final TokenResponse response = executeRequest(rb.build(),new TypeReference<TokenResponse>() {});
             log.trace("Duo token response: '{}'",response);
diff --git a/idp-duo-nimbus-client-impl/src/main/java/net/shibboleth/idp/plugin/authn/duo/nimbus/NimbusClientSupport.java b/idp-duo-nimbus-client-impl/src/main/java/net/shibboleth/idp/plugin/authn/duo/nimbus/NimbusClientSupport.java
new file mode 100644
index 0000000..608cabf
--- /dev/null
+++ b/idp-duo-nimbus-client-impl/src/main/java/net/shibboleth/idp/plugin/authn/duo/nimbus/NimbusClientSupport.java
@@ -0,0 +1,255 @@
+/*
+ * 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.idp.plugin.authn.duo.nimbus;
+
+import java.nio.charset.StandardCharsets;
+import java.security.SecureRandom;
+import java.text.ParseException;
+import java.time.Duration;
+import java.util.Date;
+
+import javax.annotation.Nonnull;
+
+import com.nimbusds.jose.JOSEException;
+import com.nimbusds.jose.JOSEObjectType;
+import com.nimbusds.jose.JWSAlgorithm;
+import com.nimbusds.jose.JWSHeader;
+import com.nimbusds.jose.Payload;
+import com.nimbusds.jose.crypto.impl.AlgorithmSupportMessage;
+import com.nimbusds.jose.crypto.impl.HMAC;
+import com.nimbusds.jose.crypto.impl.MACProvider;
+import com.nimbusds.jose.util.Base64URL;
+import com.nimbusds.jwt.JWTClaimsSet;
+import com.nimbusds.jwt.SignedJWT;
+
+import net.shibboleth.idp.plugin.authn.duo.DuoClientException;
+import net.shibboleth.idp.plugin.authn.duo.DuoOIDCIntegration;
+import net.shibboleth.utilities.java.support.codec.EncodingException;
+import net.shibboleth.utilities.java.support.logic.Constraint;
+
+/** 
+ * Helper methods for working with Duo using Nimbus.
+ */
+public final class NimbusClientSupport {
+    
+    /** private constructor.*/
+    private NimbusClientSupport() {
+        
+    }
+    
+    /**
+     * Generate a cryptographically strong random JWT identifier. 
+     * 
+     * @param length the length of the ID. Can not be {@code null}.
+     * 
+     * @return a cryptographically strong random JWT identifier.
+     */
+    @Nonnull static String generateJWTId(@Nonnull final Integer length){
+        Constraint.isNotNull(length, "JWT length can not be null");
+        final SecureRandom secureRandom = new SecureRandom();
+        final StringBuilder sb = new StringBuilder();
+        while(sb.length() < length){
+            sb.append(Integer.toHexString(secureRandom.nextInt()));
+        }
+        return sb.toString().substring(0, length);
+    }
+    
+    /**
+     * Create a signed JWT Request object using the given parameters suitable for the Duo token endpoint.
+     * <p>
+     * Only supports the HS512 JWS algorithm.
+     * </p>
+     * 
+     * @param duoIntegration the integration used to construct the JWT
+     * @param state the state
+     * @param username the subject of the authentication
+     * 
+     * @return a signed JWT
+     */
+    //TODO this method and the below should be nimbus, inside oidc-commons, and merged into a single API   
+    @Nonnull static String createJWSRequestObject(@Nonnull final DuoOIDCIntegration duoIntegration, 
+            @Nonnull final String state, @Nonnull final String username) throws DuoClientException{
+        
+        Constraint.isNotNull(duoIntegration, "Duo Integration can not be null");
+        Constraint.isNotNull(state, "state can not be null");
+        Constraint.isNotNull(username, "username can not be null");
+        
+        final Date expiration = new Date();
+        expiration.setTime(expiration.getTime() + Duration.ofHours(1).toMillis());
+
+        try {            
+            final JWTClaimsSet claimsSet = new JWTClaimsSet.Builder()
+                    .expirationTime(expiration)
+                    .claim("scope", "openid")
+                    .claim("client_id", duoIntegration.getClientId())
+                    .claim("redirect_uri", duoIntegration.getRedirectURI())
+                    .claim("state", state)
+                    .claim("duo_uname", username)
+                    .claim("response_type", "code")
+                    .build();
+            
+            return assembleMacJws(JWSAlgorithm.HS512,claimsSet,getSecretBytes(duoIntegration.getSecretKey()));      
+  
+        } catch (final JOSEException | EncodingException | ParseException e) {
+            throw new DuoClientException(e);
+        }
+ 
+    }
+    
+    /**
+     * Create a signed JWT using the audience and Duo integration supplied. 
+     * <p>
+     * Only supports the HS512 JWS algorithm.
+     * </p>
+     * 
+     * @param aud the audience of the JWT.
+     * @param duoIntegration the integration used to construct the JWT.
+     * 
+     * @return a signed JWT.
+     * 
+     */
+    //TODO: replace with nimbus method inside of commons 
+    @Nonnull static String createJWS(@Nonnull final String aud, 
+            @Nonnull final DuoOIDCIntegration duoIntegration) throws DuoClientException{
+        
+        Constraint.isNotNull(duoIntegration, "Duo Integration can not be null");
+        Constraint.isNotNull(aud, "Audience can not be null");
+        
+        final Date expiration = new Date();
+        expiration.setTime(expiration.getTime() + Duration.ofHours(1).toMillis());
+       
+        try {            
+            final JWTClaimsSet claimsSet = new JWTClaimsSet.Builder()
+                    .expirationTime(expiration)
+                    .issuer(duoIntegration.getClientId())
+                    .subject(duoIntegration.getClientId())
+                    .audience(aud)
+                    .jwtID(NimbusClientSupport.generateJWTId(32))
+                    .build();
+            
+            return assembleMacJws(JWSAlgorithm.HS512,claimsSet,getSecretBytes(duoIntegration.getSecretKey())); 
+            
+        } catch (final EncodingException | JOSEException | ParseException e) {
+            throw new DuoClientException(e);
+        }        
+        
+    }
+    
+    /**
+     * Assemble a HMAC based JSON Web Signature token using the given algorithm, claims, and secret.
+     * 
+     * @param algorithm the JWA algorithm, **must** be one from the HMAC family.
+     * @param claimsSet the claims that form the payload.
+     * @param secret the pre-shared secret used to construct the HMAC.
+     * 
+     * @return a fully assembled JWS using the JSON compact serialisation.
+     * 
+     * @throws EncodingException On error during encoding.
+     * @throws JOSEException If the algorithm is not supported.
+     * @throws ParseException If an error occurs during serialisation.
+     */
+    @Nonnull private static String assembleMacJws(@Nonnull final JWSAlgorithm algorithm, 
+            @Nonnull final JWTClaimsSet claimsSet, @Nonnull final byte[] secret) throws 
+                    EncodingException, JOSEException, ParseException {
+        
+        Constraint.isNotNull(algorithm, "Algorithm can not be null");
+        Constraint.isNotNull(claimsSet, "JWT claims can not be null");
+        Constraint.isNotNull(secret, "Secret can not be null");
+        
+        final JWSHeader header = new JWSHeader.Builder(algorithm)
+                .type(JOSEObjectType.JWT)
+                .build();        
+        final Payload payload = new Payload(claimsSet.toJSONObject());
+        
+        final String signingInput = composeSigningInput(header,payload);
+      
+        final byte[] hmac = HMAC.compute(getJCAAlgorithmName(algorithm), secret, 
+                signingInput.getBytes(StandardCharsets.UTF_8), null);
+        
+        final SignedJWT signedJwt = new SignedJWT(header.toBase64URL(), payload.toBase64URL(), 
+                Base64URL.encode(hmac));
+
+        return signedJwt.serialize();
+        
+    }
+    
+    /**
+     * Gets the matching Java Cryptography Architecture (JCA) algorithm 
+     * name for the specified HMAC-based JSON Web Algorithm (JWA).
+     * <p>
+     * This is taken from the Nimbus {@link MACProvider} class.
+     * </p>
+     *
+     * @param alg The JSON Web Algorithm (JWA). Must be supported and not
+     *            {@code null}.
+     *
+     * @return The matching JCA algorithm name.
+     *
+     * @throws JOSEException If the algorithm is not supported.
+     */
+    @Nonnull private static String getJCAAlgorithmName(@Nonnull final JWSAlgorithm alg)
+        throws JOSEException {
+        Constraint.isNotNull(alg, "Algorithm can not be null");
+
+        if (alg.equals(JWSAlgorithm.HS256)) {
+            return "HMACSHA256";
+        } else if (alg.equals(JWSAlgorithm.HS384)) {
+            return "HMACSHA384";
+        } else if (alg.equals(JWSAlgorithm.HS512)) {
+            return "HMACSHA512";
+        } else {
+            throw new JOSEException(AlgorithmSupportMessage.unsupportedJWSAlgorithm(
+                alg,
+                MACProvider.SUPPORTED_ALGORITHMS));
+        }
+    }
+    
+    
+    /**
+     * Compose the message that is to be signed. 
+     * 
+     * @param header the header component of the message to be signed.
+     * @param payload the payload component of the message to be signed.
+     * 
+     * @return the message in its compact/serialised state ready to be signed.
+     * 
+     * @throws EncodingException if there is an error base64 encoding the components.
+     */
+    @Nonnull private static String composeSigningInput(@Nonnull final JWSHeader header,
+            @Nonnull final Payload payload) throws EncodingException {
+        Constraint.isNotNull(header, "JWS Header can not be null");
+        Constraint.isNotNull(payload, "JWT payload can not be null");
+        
+        return header.toBase64URL().toString() + "."+ payload.toBase64URL().toString();
+    }
+    
+    /**
+     * Convert the String secret into its byte representation assuming a UTF-8 encoding.
+     * 
+     * @param secret the secret as a UTF-8 encoding string, must not be {@code null}.
+     * 
+     * @return the UTF-8 byte representation of the secret.
+     */
+    @Nonnull private static byte[] getSecretBytes(@Nonnull final String secret) {
+        return secret.getBytes(StandardCharsets.UTF_8);
+    }
+    
+    
+
+}
diff --git a/idp-duo-nimbus-client-impl/src/main/java/net/shibboleth/idp/plugin/authn/duo/nimbus/NimbusUtils.java b/idp-duo-nimbus-client-impl/src/main/java/net/shibboleth/idp/plugin/authn/duo/nimbus/NimbusUtils.java
deleted file mode 100644
index df55569..0000000
--- a/idp-duo-nimbus-client-impl/src/main/java/net/shibboleth/idp/plugin/authn/duo/nimbus/NimbusUtils.java
+++ /dev/null
@@ -1,127 +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.idp.plugin.authn.duo.nimbus;
-
-import java.io.UnsupportedEncodingException;
-import java.security.SecureRandom;
-import java.time.Duration;
-import java.util.Collections;
-import java.util.Date;
-
-import javax.annotation.Nonnull;
-
-import com.auth0.jwt.JWT;
-import com.auth0.jwt.algorithms.Algorithm;
-import com.auth0.jwt.exceptions.JWTCreationException;
-
-import net.shibboleth.idp.plugin.authn.duo.DuoClientException;
-import net.shibboleth.idp.plugin.authn.duo.DuoOIDCIntegration;
-import net.shibboleth.utilities.java.support.logic.Constraint;
-
-/** 
- * Helper methods for working with Duo and Nimbus.
- */
-public final class NimbusUtils {
-    
-    /** private constructor.*/
-    private NimbusUtils() {
-        
-    }
-    
-    /**
-     * Generate a cryptographically strong random JWT identifier. 
-     * 
-     * @param length the length of the ID. Can not be {@code null}.
-     * 
-     * @return a cryptographically strong random JWT identifier.
-     */
-    @Nonnull static String generateJWTId(@Nonnull final Integer length){
-        Constraint.isNotNull(length, "JWT length can not be null");
-        final SecureRandom secureRandom = new SecureRandom();
-        final StringBuilder sb = new StringBuilder();
-        while(sb.length() < length){
-            sb.append(Integer.toHexString(secureRandom.nextInt()));
-        }
-        return sb.toString().substring(0, length);
-    }
-    
-    /**
-     * Create a signed JWT Request object using the given parameters suitable for the token endpoint.
-     * 
-     * @param duoIntegration the integration used to construct the JWT
-     * @param state the state
-     * @param username the subject of the authentication
-     * 
-     * @return a signed JWT
-     */
-    //TODO this method and the below should be nimbus, inside oidc-commons, and merged into a single API
-    @Nonnull static String createJWSRequestObject(@Nonnull final DuoOIDCIntegration duoIntegration, 
-            @Nonnull final String state, @Nonnull final String username) throws DuoClientException{
-        final Date expiration = new Date();
-        expiration.setTime(expiration.getTime() + Duration.ofHours(1).toMillis());
-
-        try {
-            return JWT.create()
-                        .withHeader(Collections.singletonMap("alg", "HS512"))
-                        .withExpiresAt(expiration)
-                        .withClaim("scope", "openid")
-                        .withClaim("client_id", duoIntegration.getClientId())
-                        .withClaim("redirect_uri", duoIntegration.getRedirectURI())
-                        .withClaim("state", state)
-                        .withClaim("duo_uname", username)
-                        .withClaim("response_type", "code")
-                        .sign(Algorithm.HMAC512(duoIntegration.getSecretKey()));
-        } catch (IllegalArgumentException | JWTCreationException | UnsupportedEncodingException e) {
-            throw new DuoClientException(e);
-        }
- 
-    }
-    
-    /**
-     * Create a signed JWT using the audience and duo integration supplied. 
-     * 
-     * @param aud the audience of the JWT
-     * @param duoIntegration the integration used to construct the JWT.
-     * 
-     * @return a signed JWT.
-     * 
-     */
-    //TODO: replace with nimbus method inside of commons 
-    @Nonnull static String createJWS(@Nonnull final String aud, 
-            @Nonnull final DuoOIDCIntegration duoIntegration) throws DuoClientException{
-        
-        final Date expiration = new Date();
-        expiration.setTime(expiration.getTime() + Duration.ofHours(1).toMillis());
-       
-        try {
-            return com.auth0.jwt.JWT.create()
-                        .withHeader(Collections.singletonMap("alg", "HS512"))
-                        .withIssuer(duoIntegration.getClientId())
-                        .withSubject(duoIntegration.getClientId())
-                        .withAudience(aud)
-                        .withExpiresAt(expiration)
-                        .withJWTId(NimbusUtils.generateJWTId(32))
-                        .sign(Algorithm.HMAC512(duoIntegration.getSecretKey()));
-        } catch (IllegalArgumentException | JWTCreationException | UnsupportedEncodingException e) {
-            throw new DuoClientException(e);
-        }        
-        
-    }
-
-}

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


More information about the commits mailing list