[java-identity-provider] branch master updated: IDP-1239 - Non-browser support for Duo authentication

Scott Cantor cantor.2 at osu.edu
Mon Aug 13 22:10:54 EDT 2018


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

scantor pushed a commit to branch master
in repository java-identity-provider.

View the commit online:
http://git.shibboleth.net/view/?p=java-identity-provider.git;a=commit;h=4845f544cc5e9a19ad7d71a207711c775035841e

The following commit(s) were added to refs/heads/master by this push:
       new  4845f54   IDP-1239 - Non-browser support for Duo authentication
4845f54 is described below

commit 4845f544cc5e9a19ad7d71a207711c775035841e
Author: Scott Cantor <cantor.2 at osu.edu>
AuthorDate: Mon Aug 13 22:10:47 2018 -0400

    IDP-1239 - Non-browser support for Duo authentication
    
    https://issues.shibboleth.net/jira/browse/IDP-1239
    
    Add pushinfo support.
---
 .../net/shibboleth/idp/authn/duo/DuoAuthAPI.java   |  5 ++-
 .../duo/context/DuoAuthenticationContext.java      | 22 +++++++++++
 idp-authn-impl/pom.xml                             |  5 +++
 .../idp/authn/duo/impl/DuoAuthAuthenticator.java   | 20 +++++++++-
 .../impl/ExtractDuoAuthenticationFromHeaders.java  | 43 +++++++++++++++++++++-
 .../system/flows/authn/duo-authn-beans.xml         |  3 +-
 6 files changed, 93 insertions(+), 5 deletions(-)

diff --git a/idp-authn-api/src/main/java/net/shibboleth/idp/authn/duo/DuoAuthAPI.java b/idp-authn-api/src/main/java/net/shibboleth/idp/authn/duo/DuoAuthAPI.java
index eb22e80..9eef29c 100644
--- a/idp-authn-api/src/main/java/net/shibboleth/idp/authn/duo/DuoAuthAPI.java
+++ b/idp-authn-api/src/main/java/net/shibboleth/idp/authn/duo/DuoAuthAPI.java
@@ -42,7 +42,10 @@ public final class DuoAuthAPI {
 
     /** Duo AuthAPI parameter name. */
     @Nonnull @NotEmpty public static final String DUO_PASSCODE = "passcode";
-    
+
+    /** Duo AuthAPI parameter name. */
+    @Nonnull @NotEmpty public static final String DUO_PUSHINFO = "pushinfo";
+
     /** Duo AuthAPI factor "auto" value. */
     @Nonnull @NotEmpty public static final String DUO_FACTOR_AUTO = "auto";
 
diff --git a/idp-authn-api/src/main/java/net/shibboleth/idp/authn/duo/context/DuoAuthenticationContext.java b/idp-authn-api/src/main/java/net/shibboleth/idp/authn/duo/context/DuoAuthenticationContext.java
index 696a82b..02a0a37 100644
--- a/idp-authn-api/src/main/java/net/shibboleth/idp/authn/duo/context/DuoAuthenticationContext.java
+++ b/idp-authn-api/src/main/java/net/shibboleth/idp/authn/duo/context/DuoAuthenticationContext.java
@@ -17,12 +17,17 @@
 
 package net.shibboleth.idp.authn.duo.context;
 
+import java.util.HashMap;
+import java.util.Map;
+
 import javax.annotation.Nonnull;
 import javax.annotation.Nullable;
 
 import org.opensaml.messaging.context.BaseContext;
 
 import net.shibboleth.idp.authn.context.AuthenticationContext;
+import net.shibboleth.utilities.java.support.annotation.constraint.Live;
+import net.shibboleth.utilities.java.support.annotation.constraint.NonnullElements;
 
 /**
  * Context that carries Duo factor and device or passcode to be used in validation.
@@ -49,7 +54,15 @@ public class DuoAuthenticationContext extends BaseContext {
 
     /** Passcode. */
     @Nullable private String duoPasscode;
+    
+    /** PushInfo data. */
+    @Nullable private Map<String,String> pushInfo;
 
+    /** Constructor. */
+    public DuoAuthenticationContext() {
+        pushInfo = new HashMap<>();
+    }
+    
     /**
      * Get the username.
      * 
@@ -155,4 +168,13 @@ public class DuoAuthenticationContext extends BaseContext {
         return this;
     }
 
+    /**
+     * Get the pushinfo.
+     * 
+     * @return the pushinfo
+     */
+    @Nonnull @NonnullElements @Live public Map<String,String> getPushInfo() {
+        return pushInfo;
+    }
+    
 }
\ No newline at end of file
diff --git a/idp-authn-impl/pom.xml b/idp-authn-impl/pom.xml
index c684074..01ed3f9 100644
--- a/idp-authn-impl/pom.xml
+++ b/idp-authn-impl/pom.xml
@@ -43,6 +43,11 @@
             <artifactId>idp-profile-api</artifactId>
             <version>${project.version}</version>
         </dependency>
+        <dependency>
+            <groupId>${project.groupId}</groupId>
+            <artifactId>idp-ui</artifactId>
+            <version>${project.version}</version>
+        </dependency>
 
         <dependency>
             <groupId>${opensaml.groupId}</groupId>
diff --git a/idp-authn-impl/src/main/java/net/shibboleth/idp/authn/duo/impl/DuoAuthAuthenticator.java b/idp-authn-impl/src/main/java/net/shibboleth/idp/authn/duo/impl/DuoAuthAuthenticator.java
index 04523ca..573b8d9 100644
--- a/idp-authn-impl/src/main/java/net/shibboleth/idp/authn/duo/impl/DuoAuthAuthenticator.java
+++ b/idp-authn-impl/src/main/java/net/shibboleth/idp/authn/duo/impl/DuoAuthAuthenticator.java
@@ -22,6 +22,8 @@ import java.net.URI;
 import java.net.URISyntaxException;
 import java.security.InvalidKeyException;
 import java.security.NoSuchAlgorithmException;
+import java.util.ArrayList;
+import java.util.Map;
 
 import javax.annotation.Nonnull;
 
@@ -31,24 +33,31 @@ import org.apache.http.client.utils.URIBuilder;
 
 import com.duosecurity.duoweb.DuoWebException;
 import com.fasterxml.jackson.core.type.TypeReference;
+import com.google.common.escape.Escaper;
+import com.google.common.net.UrlEscapers;
 
 import net.shibboleth.idp.authn.duo.DuoAuthAPI;
 import net.shibboleth.idp.authn.duo.DuoIntegration;
 import net.shibboleth.idp.authn.duo.context.DuoAuthenticationContext;
+import net.shibboleth.utilities.java.support.primitive.StringSupport;
 
 /**
  * Implementation of the the Duo AuthApi /v2/auth endpoint.
  */
 public class DuoAuthAuthenticator extends AbstractDuoAuthenticator {
+    
+    /** pushinfo escaper. */
+    @Nonnull private final Escaper paramEscaper;
 
     /** a TypeReference for the repsonse generated by the endpoint. */
     @Nonnull private final TypeReference<DuoResponseWrapper<DuoAuthResponse>> wrapperTypeRef;
-
+    
     /** Constructor. */
     public DuoAuthAuthenticator() {
         wrapperTypeRef = new TypeReference<DuoResponseWrapper<DuoAuthResponse>>() {};
+        paramEscaper = UrlEscapers.urlFormParameterEscaper();
     }
-
+    
     /**
      * Perform an authentication action via the Duo AuthApi /auth endpoint.
      * 
@@ -80,6 +89,13 @@ public class DuoAuthAuthenticator extends AbstractDuoAuthenticator {
             if (duoContext.getPasscode() != null) {
                 rb.addParameter(DuoAuthAPI.DUO_PASSCODE, duoContext.getPasscode());
             }
+            if (!duoContext.getPushInfo().isEmpty()) {
+                final ArrayList<String> pushinfo = new ArrayList<String>(duoContext.getPushInfo().size());
+                for (final Map.Entry<String,String> entry : duoContext.getPushInfo().entrySet()) {
+                    pushinfo.add(paramEscaper.escape(entry.getKey()) + "=" + paramEscaper.escape(entry.getValue()));
+                }
+                rb.addParameter(DuoAuthAPI.DUO_PUSHINFO, StringSupport.listToStringValue(pushinfo, "&"));
+            }
             DuoSupport.signRequest(rb, duoIntegration);
             final HttpUriRequest request = rb.build();
 
diff --git a/idp-authn-impl/src/main/java/net/shibboleth/idp/authn/duo/impl/ExtractDuoAuthenticationFromHeaders.java b/idp-authn-impl/src/main/java/net/shibboleth/idp/authn/duo/impl/ExtractDuoAuthenticationFromHeaders.java
index fc9fea3..d475471 100644
--- a/idp-authn-impl/src/main/java/net/shibboleth/idp/authn/duo/impl/ExtractDuoAuthenticationFromHeaders.java
+++ b/idp-authn-impl/src/main/java/net/shibboleth/idp/authn/duo/impl/ExtractDuoAuthenticationFromHeaders.java
@@ -17,7 +17,10 @@
 
 package net.shibboleth.idp.authn.duo.impl;
 
+import java.util.Map;
+
 import javax.annotation.Nonnull;
+import javax.annotation.Nullable;
 import javax.servlet.http.HttpServletRequest;
 
 import org.opensaml.profile.action.ActionSupport;
@@ -25,11 +28,14 @@ import org.opensaml.profile.context.ProfileRequestContext;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
+import com.google.common.base.Function;
+
 import net.shibboleth.idp.authn.AbstractAuthenticationAction;
 import net.shibboleth.idp.authn.AuthnEventIds;
 import net.shibboleth.idp.authn.context.AuthenticationContext;
 import net.shibboleth.idp.authn.duo.DuoAuthAPI;
 import net.shibboleth.idp.authn.duo.context.DuoAuthenticationContext;
+import net.shibboleth.idp.ui.context.RelyingPartyUIContext;
 import net.shibboleth.utilities.java.support.annotation.constraint.NotEmpty;
 import net.shibboleth.utilities.java.support.component.ComponentSupport;
 import net.shibboleth.utilities.java.support.logic.Constraint;
@@ -72,6 +78,9 @@ public class ExtractDuoAuthenticationFromHeaders<InboundMessageType,OutboundMess
 
     /** Header name for passcode. */
     @Nonnull @NotEmpty private String passcodeHeaderName;
+    
+    /** Strategy function for populating pushinfo AuthAPI parameter. */
+    @Nullable private Function<ProfileRequestContext,Map<String,String>> pushInfoLookupStrategy;
 
     /** Constructor. */
     ExtractDuoAuthenticationFromHeaders() {
@@ -154,9 +163,23 @@ public class ExtractDuoAuthenticationFromHeaders<InboundMessageType,OutboundMess
      * @param flag flag to set
      */
     public void setAutoAuthenticationSupported(final boolean flag) {
+        ComponentSupport.ifInitializedThrowUnmodifiabledComponentException(this);
+        
         autoAuthenticationSupported = flag;
     }
     
+    /**
+     * Set lookup strategy for AuthAPI pushinfo parameter.
+     * 
+     * @param strategy lookup strategy
+     */
+    public void setPushInfoLookupStrategy(
+            @Nullable final Function<ProfileRequestContext,Map<String,String>> strategy) {
+        ComponentSupport.ifInitializedThrowUnmodifiabledComponentException(this);
+        
+        pushInfoLookupStrategy = strategy;
+    }
+    
     /** {@inheritDoc} */
     @Override
     protected boolean doPreExecute(
@@ -169,6 +192,7 @@ public class ExtractDuoAuthenticationFromHeaders<InboundMessageType,OutboundMess
         return true;
     }
 
+// Checkstyle: CyclomaticComplexity OFF
     /** {@inheritDoc} */
     @Override protected void doExecute(
             @Nonnull final ProfileRequestContext<InboundMessageType,OutboundMessageType> profileRequestContext,
@@ -207,13 +231,30 @@ public class ExtractDuoAuthenticationFromHeaders<InboundMessageType,OutboundMess
             duoCtx.setDeviceID(DuoAuthAPI.DUO_DEVICE_AUTO);
         }
 
+        // Populate pushinfo either customized or just with service name.
+        if (pushInfoLookupStrategy != null) {
+            final Map<String,String> pushinfo = pushInfoLookupStrategy.apply(profileRequestContext);
+            if (pushinfo != null) {
+                duoCtx.getPushInfo().putAll(pushinfo);
+            }
+        } else {
+            final RelyingPartyUIContext uiCtx = authenticationContext.getSubcontext(RelyingPartyUIContext.class);
+            if (uiCtx != null) {
+                final String name = uiCtx.getServiceName();
+                if (name != null) {
+                    duoCtx.getPushInfo().put("service", uiCtx.getServiceName());
+                }
+            }
+        }
+        
         authenticationContext.addSubcontext(duoCtx, true);
 
         log.debug("{} Duo AuthAPI parameters extracted from request (Factor: {}, Device: {}, Passcode: {})",
                 getLogPrefix(), duoCtx.getFactor(), duoCtx.getDeviceID(),
                 duoCtx.getPasscode() != null ? "set" : "not set");
     }
-
+ // Checkstyle: CyclomaticComplexity ON
+    
     /**
      * Extracts the Duo API arguments passed in via the request headers.
      * 
diff --git a/idp-conf/src/main/resources/system/flows/authn/duo-authn-beans.xml b/idp-conf/src/main/resources/system/flows/authn/duo-authn-beans.xml
index ef64f53..bf65567 100644
--- a/idp-conf/src/main/resources/system/flows/authn/duo-authn-beans.xml
+++ b/idp-conf/src/main/resources/system/flows/authn/duo-authn-beans.xml
@@ -57,7 +57,8 @@
         p:clientAdddressTrusted="%{idp.duo.nonbrowser.clientAddressTrusted:true}"
         p:factorHeader="%{idp.duo.nonbrowser.header.factor:X-Shibboleth-Duo-Factor}"
         p:deviceHeader="%{idp.duo.nonbrowser.header.device:X-Shibboleth-Duo-Device}"
-        p:passcodeHeader="%{idp.duo.nonbrowser.header.passcode:X-Shibboleth-Duo-Passcode}" />
+        p:passcodeHeader="%{idp.duo.nonbrowser.header.passcode:X-Shibboleth-Duo-Passcode}"
+        p:pushInfoLookupStrategy="#{getObject('shibboleth.authn.Duo.PushInfoLookupStrategy')}" />
 
     <bean id="DuoPreauthAuthenticator" lazy-init="true"
         class="net.shibboleth.idp.authn.duo.impl.DuoPreauthAuthenticator"

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


More information about the commits mailing list