[java-identity-provider] branch master updated: IDP-1117 - Support for AuthenticatingAuthority

Scott Cantor cantor.2 at osu.edu
Wed Aug 22 12:39:37 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=8b966a5832a02163d750c9f024bb70349845a5fa

The following commit(s) were added to refs/heads/master by this push:
       new  8b966a5   IDP-1117 - Support for AuthenticatingAuthority
8b966a5 is described below

commit 8b966a5832a02163d750c9f024bb70349845a5fa
Author: Scott Cantor <cantor.2 at osu.edu>
AuthorDate: Wed Aug 22 12:38:21 2018 -0400

    IDP-1117 - Support for AuthenticatingAuthority
    
    https://issues.shibboleth.net/jira/browse/IDP-1117
---
 .../idp/authn/ExternalAuthentication.java          |  7 ++
 .../context/ExternalAuthenticationContext.java     | 82 +++++++++++++++++++---
 .../principal/ProxyAuthenticationPrincipal.java    | 20 +++++-
 .../idp/authn/impl/ExternalAuthenticationImpl.java |  5 ++
 .../idp/authn/impl/RemoteUserAuthServlet.java      | 47 ++++++++++++-
 .../authn/impl/ValidateExternalAuthentication.java |  7 ++
 .../impl/ValidateExternalAuthenticationTest.java   | 23 +++++-
 .../resources/system/conf/general-authn-system.xml |  1 +
 .../profile/impl/AddAuthnStatementToAssertion.java | 23 ++++++
 .../impl/AddAuthnStatementToAssertionTest.java     | 40 ++++++++---
 10 files changed, 232 insertions(+), 23 deletions(-)

diff --git a/idp-authn-api/src/main/java/net/shibboleth/idp/authn/ExternalAuthentication.java b/idp-authn-api/src/main/java/net/shibboleth/idp/authn/ExternalAuthentication.java
index 66e6001..586911f 100644
--- a/idp-authn-api/src/main/java/net/shibboleth/idp/authn/ExternalAuthentication.java
+++ b/idp-authn-api/src/main/java/net/shibboleth/idp/authn/ExternalAuthentication.java
@@ -48,6 +48,13 @@ public class ExternalAuthentication {
     /** Request attribute to which an authentication timestamp may be bound. */
     @Nonnull @NotEmpty public static final String AUTHENTICATION_INSTANT_KEY = "authnInstant";
     
+    /** 
+     * Request attribute to which a collection of authenticating authorities may be bound.
+     * 
+     * @since 3.4.0
+     */
+    @Nonnull @NotEmpty public static final String AUTHENTICATING_AUTHORITIES_KEY = "authnAuthorities";
+    
     /** Request attribute to which an error message may be bound. */
     @Nonnull @NotEmpty public static final String AUTHENTICATION_ERROR_KEY = "authnError";
 
diff --git a/idp-authn-api/src/main/java/net/shibboleth/idp/authn/context/ExternalAuthenticationContext.java b/idp-authn-api/src/main/java/net/shibboleth/idp/authn/context/ExternalAuthenticationContext.java
index 56921f6..5eb5f06 100644
--- a/idp-authn-api/src/main/java/net/shibboleth/idp/authn/context/ExternalAuthenticationContext.java
+++ b/idp-authn-api/src/main/java/net/shibboleth/idp/authn/context/ExternalAuthenticationContext.java
@@ -18,13 +18,18 @@
 package net.shibboleth.idp.authn.context;
 
 import java.security.Principal;
+import java.util.ArrayList;
+import java.util.Collection;
 
+import javax.annotation.Nonnull;
 import javax.annotation.Nullable;
 import javax.security.auth.Subject;
 
 import org.joda.time.DateTime;
 import org.opensaml.messaging.context.BaseContext;
 
+import net.shibboleth.utilities.java.support.annotation.constraint.Live;
+
 /**
  * A context representing the state of an externalized authentication attempt,
  * a case where authentication happens outside of a web flow.
@@ -49,6 +54,9 @@ public final class ExternalAuthenticationContext extends BaseContext {
     /** Time of authentication. */
     @Nullable private DateTime authnInstant;
     
+    /** Proxied authenticating sources. */
+    @Nonnull private Collection<String> authenticatingAuthorities;
+    
     /** Error message. */
     @Nullable private String authnError;
     
@@ -61,6 +69,11 @@ public final class ExternalAuthenticationContext extends BaseContext {
     /** Flag indicating this "new" result is really "old". */
     private boolean previousResult;
     
+    /** Constructor. */
+    public ExternalAuthenticationContext() {
+        authenticatingAuthorities = new ArrayList<>();
+    }
+    
     /**
      * Get the flow execution URL to return control to.
      * 
@@ -75,9 +88,13 @@ public final class ExternalAuthenticationContext extends BaseContext {
      * Set the flow execution URL to return control to.
      * 
      * @param url   return location
+     * 
+     * @return this context
      */
-    public void setFlowExecutionUrl(@Nullable final String url) {
+    @Nonnull public ExternalAuthenticationContext setFlowExecutionUrl(@Nullable final String url) {
         flowExecutionUrl = url;
+        
+        return this;
     }
 
     /**
@@ -93,9 +110,13 @@ public final class ExternalAuthenticationContext extends BaseContext {
      * Set a {@link Principal} that was authenticated.
      * 
      * @param prin principal to set
+     * 
+     * @return this context
      */
-    public void setPrincipal(@Nullable final Principal prin) {
+    @Nonnull public ExternalAuthenticationContext setPrincipal(@Nullable final Principal prin) {
         principal = prin;
+        
+        return this;
     }
 
     /**
@@ -111,9 +132,13 @@ public final class ExternalAuthenticationContext extends BaseContext {
      * Set the name of a principal that was authenticated.
      * 
      * @param name name of principal to set
+     * 
+     * @return this context
      */
-    public void setPrincipalName(@Nullable final String name) {
+    @Nonnull public ExternalAuthenticationContext setPrincipalName(@Nullable final String name) {
         principalName = name;
+        
+        return this;
     }
 
     /**
@@ -128,10 +153,14 @@ public final class ExternalAuthenticationContext extends BaseContext {
     /**
      * Set a {@link Subject} that was authenticated.
      * 
-     * @param sub The subject to set.
+     * @param sub The subject to set
+     * 
+     * @return this context
      */
-    public void setSubject(@Nullable final Subject sub) {
+    @Nonnull public ExternalAuthenticationContext setSubject(@Nullable final Subject sub) {
         subject = sub;
+        
+        return this;
     }
 
     /**
@@ -147,9 +176,24 @@ public final class ExternalAuthenticationContext extends BaseContext {
      * Set the time of authentication.
      * 
      * @param instant time of authentication to set
+     * 
+     * @return this context
      */
-    public void setAuthnInstant(final DateTime instant) {
+    @Nonnull public ExternalAuthenticationContext setAuthnInstant(@Nullable final DateTime instant) {
         authnInstant = instant;
+        
+        return this;
+    }
+    
+    /**
+     * Get a mutable, ordered list of proxied authentication sources.
+     * 
+     * @return proxied authentication sources
+     * 
+     * @since 3.4.0
+     */
+    @Nonnull @Live public Collection<String> getAuthenticatingAuthorities() {
+        return authenticatingAuthorities;
     }
 
     /**
@@ -165,9 +209,13 @@ public final class ExternalAuthenticationContext extends BaseContext {
      * Set an error message from the authentication process.
      * 
      * @param message message to set
+     * 
+     * @return this context
      */
-    public void setAuthnError(final String message) {
+    @Nonnull public ExternalAuthenticationContext setAuthnError(@Nullable final String message) {
         authnError = message;
+        
+        return this;
     }
 
     /**
@@ -183,9 +231,13 @@ public final class ExternalAuthenticationContext extends BaseContext {
      * Set an exception from the authentication process.
      * 
      * @param exception exception to set
+     * 
+     * @return this context
      */
-    public void setAuthnException(final Exception exception) {
+    @Nonnull public ExternalAuthenticationContext setAuthnException(@Nullable final Exception exception) {
         authnException = exception;
+        
+        return this;
     }
     
     /**
@@ -200,10 +252,14 @@ public final class ExternalAuthenticationContext extends BaseContext {
     /**
      * Set the "do not cache" flag.
      * 
-     * @param flag flag to set 
+     * @param flag flag to set
+     * 
+     * @return this context
      */
-    public void setDoNotCache(final boolean flag) {
+    @Nonnull public ExternalAuthenticationContext setDoNotCache(final boolean flag) {
         doNotCache = flag;
+        
+        return this;
     }
     
     /**
@@ -224,9 +280,13 @@ public final class ExternalAuthenticationContext extends BaseContext {
      * 
      * @param flag flag to set
      * 
+     * @return this context
+     * 
      * @since 3.3.0
      */
-    public void setPreviousResult(final boolean flag) {
+    @Nonnull public ExternalAuthenticationContext setPreviousResult(final boolean flag) {
         previousResult = flag;
+        
+        return this;
     }
 }
\ No newline at end of file
diff --git a/idp-authn-api/src/main/java/net/shibboleth/idp/authn/principal/ProxyAuthenticationPrincipal.java b/idp-authn-api/src/main/java/net/shibboleth/idp/authn/principal/ProxyAuthenticationPrincipal.java
index bb782c3..b26e4fa 100644
--- a/idp-authn-api/src/main/java/net/shibboleth/idp/authn/principal/ProxyAuthenticationPrincipal.java
+++ b/idp-authn-api/src/main/java/net/shibboleth/idp/authn/principal/ProxyAuthenticationPrincipal.java
@@ -26,10 +26,17 @@ import javax.annotation.Nonnull;
 import net.shibboleth.utilities.java.support.annotation.constraint.Live;
 import net.shibboleth.utilities.java.support.annotation.constraint.NonnullElements;
 import net.shibboleth.utilities.java.support.annotation.constraint.NotEmpty;
+import net.shibboleth.utilities.java.support.logic.Constraint;
 
 import com.google.common.base.MoreObjects;
+import com.google.common.base.Predicates;
+import com.google.common.collect.Collections2;
 
-/** Principal that wraps a set of proxied authentication authorities. */
+/**
+ * Principal that wraps a set of proxied authentication authorities.
+ * 
+ * @since 3.4.0
+ */
 public class ProxyAuthenticationPrincipal implements Principal {
 
     /** The authorities. */
@@ -40,6 +47,17 @@ public class ProxyAuthenticationPrincipal implements Principal {
         authorities = new ArrayList<>();
     }
 
+    /**
+     * Constructor.
+     *
+     * @param proxiedAuthorities initial set of authorities
+     */
+    public ProxyAuthenticationPrincipal(@Nonnull @NonnullElements final Collection<String> proxiedAuthorities) {
+        Constraint.isNotNull(proxiedAuthorities, "Proxied authority collection cannot be null");
+        
+        authorities = new ArrayList<>(Collections2.filter(proxiedAuthorities, Predicates.notNull()));
+    }
+
     /** {@inheritDoc} */
     @Nonnull @NotEmpty public String getName() {
         return authorities.toString();
diff --git a/idp-authn-impl/src/main/java/net/shibboleth/idp/authn/impl/ExternalAuthenticationImpl.java b/idp-authn-impl/src/main/java/net/shibboleth/idp/authn/impl/ExternalAuthenticationImpl.java
index 4aca5f2..d942a58 100644
--- a/idp-authn-impl/src/main/java/net/shibboleth/idp/authn/impl/ExternalAuthenticationImpl.java
+++ b/idp-authn-impl/src/main/java/net/shibboleth/idp/authn/impl/ExternalAuthenticationImpl.java
@@ -160,6 +160,11 @@ public class ExternalAuthenticationImpl extends ExternalAuthentication {
             extContext.setAuthnInstant((DateTime) attr);
         }
         
+        attr = request.getAttribute(AUTHENTICATING_AUTHORITIES_KEY);
+        if (attr != null && attr instanceof Collection<?>) {
+            extContext.getAuthenticatingAuthorities().addAll((Collection<String>) attr);
+        }
+        
         attr = request.getAttribute(AUTHENTICATION_ERROR_KEY);
         if (attr != null && attr instanceof String) {
             extContext.setAuthnError((String) attr);
diff --git a/idp-authn-impl/src/main/java/net/shibboleth/idp/authn/impl/RemoteUserAuthServlet.java b/idp-authn-impl/src/main/java/net/shibboleth/idp/authn/impl/RemoteUserAuthServlet.java
index 12305f3..e265a96 100644
--- a/idp-authn-impl/src/main/java/net/shibboleth/idp/authn/impl/RemoteUserAuthServlet.java
+++ b/idp-authn-impl/src/main/java/net/shibboleth/idp/authn/impl/RemoteUserAuthServlet.java
@@ -82,7 +82,10 @@ public class RemoteUserAuthServlet extends HttpServlet {
 
     /** Init parameter identifying a header to check for one or more authentication method strings. */
     @Nonnull @NotEmpty private static final String AUTHN_METHOD_HEADER_PARAM = "authnMethodHeader";
-    
+
+    /** Init parameter identifying a header to check for one or more proxied authenticating authority strings. */
+    @Nonnull @NotEmpty private static final String AUTHN_AUTHORITY_HEADER_PARAM = "authnAuthorityHeader";
+
     /** Class logger. */
     @Nonnull private final Logger log = LoggerFactory.getLogger(RemoteUserAuthServlet.class);
     
@@ -101,6 +104,9 @@ public class RemoteUserAuthServlet extends HttpServlet {
     /** Header to check for authentication method strings. */
     @Nullable @NotEmpty private String authnMethodHeader;
 
+    /** Header to check for proxied authenticating authority strings. */
+    @Nullable @NotEmpty private String authnAuthorityHeader;
+
     /** Constructor. */
     public RemoteUserAuthServlet() {
         checkRemoteUser = true;
@@ -153,6 +159,17 @@ public class RemoteUserAuthServlet extends HttpServlet {
         authnMethodHeader = StringSupport.trimOrNull(header);
     }
 
+    /**
+     * Set the name of a request header to check for authenticating authority strings.
+     * 
+     * @param header request header name
+     * 
+     * @since 3.4.0
+     */
+    public void setAuthnAuthorityHeader(@Nullable @NotEmpty final String header) {
+        authnAuthorityHeader = StringSupport.trimOrNull(header);
+    }
+
 // Checkstyle: CyclomaticComplexity OFF
     /** {@inheritDoc} */
     @Override
@@ -189,7 +206,12 @@ public class RemoteUserAuthServlet extends HttpServlet {
         if (param != null) {
             setAuthnMethodHeader(param);
         }
-        
+
+        param = config.getInitParameter(AUTHN_AUTHORITY_HEADER_PARAM);
+        if (param != null) {
+            setAuthnAuthorityHeader(param);
+        }
+
         log.info("RemoteUserAuthServlet {} process REMOTE_USER, along with attributes {} and headers {}",
                 new Object[] {checkRemoteUser ? "will" : "will not", checkAttributes, checkHeaders,});
         if (subjectAttribute != null) {
@@ -199,6 +221,10 @@ public class RemoteUserAuthServlet extends HttpServlet {
         if (authnMethodHeader != null) {
             log.info("RemoteUserAuthServlet will check for authentication methods in header: {}", authnMethodHeader);
         }
+        if (authnAuthorityHeader != null) {
+            log.info("RemoteUserAuthServlet will check for authenticating authorities in header: {}",
+                    authnAuthorityHeader);
+        }
     }
 
     // Checkstyle: MethodLength|ReturnCount OFF
@@ -259,6 +285,23 @@ public class RemoteUserAuthServlet extends HttpServlet {
                 return;
             }
             
+            if (authnAuthorityHeader != null) {
+                // Check for proxied authorities.
+                final Enumeration<String> authorities = httpRequest.getHeaders(authnAuthorityHeader);
+                if (authorities != null && authorities.hasMoreElements()) {
+                    final Collection<String> copied = new ArrayList<>();
+                    while (authorities.hasMoreElements()) {
+                        final String authority = authorities.nextElement();
+                        if (!Strings.isNullOrEmpty(authority)) {
+                            copied.add(authority);
+                        }
+                    }
+                    if (!copied.isEmpty()) {
+                        httpRequest.setAttribute(ExternalAuthentication.AUTHENTICATING_AUTHORITIES_KEY, copied);
+                    }
+                }
+            }
+            
             if (authnMethodHeader != null) {
                 // Check for authentication methods.
                 final Enumeration<String> methods = httpRequest.getHeaders(authnMethodHeader);
diff --git a/idp-authn-impl/src/main/java/net/shibboleth/idp/authn/impl/ValidateExternalAuthentication.java b/idp-authn-impl/src/main/java/net/shibboleth/idp/authn/impl/ValidateExternalAuthentication.java
index 0a40cea..d0a4819 100644
--- a/idp-authn-impl/src/main/java/net/shibboleth/idp/authn/impl/ValidateExternalAuthentication.java
+++ b/idp-authn-impl/src/main/java/net/shibboleth/idp/authn/impl/ValidateExternalAuthentication.java
@@ -29,6 +29,7 @@ import net.shibboleth.idp.authn.AbstractValidationAction;
 import net.shibboleth.idp.authn.AuthnEventIds;
 import net.shibboleth.idp.authn.context.AuthenticationContext;
 import net.shibboleth.idp.authn.context.ExternalAuthenticationContext;
+import net.shibboleth.idp.authn.principal.ProxyAuthenticationPrincipal;
 import net.shibboleth.idp.authn.principal.UsernamePrincipal;
 import net.shibboleth.utilities.java.support.annotation.constraint.NotEmpty;
 import net.shibboleth.utilities.java.support.component.ComponentSupport;
@@ -165,6 +166,12 @@ public class ValidateExternalAuthentication extends AbstractValidationAction {
         
         recordSuccess();
         
+        if (!extContext.getAuthenticatingAuthorities().isEmpty()) {
+            final ProxyAuthenticationPrincipal proxied =
+                    new ProxyAuthenticationPrincipal(extContext.getAuthenticatingAuthorities());
+            extContext.getSubject().getPrincipals().add(proxied);
+        }
+        
         if (extContext.doNotCache()) {
             log.debug("{} Disabling caching of authentication result", getLogPrefix());
             authenticationContext.setResultCacheable(false);
diff --git a/idp-authn-impl/src/test/java/net/shibboleth/idp/authn/impl/ValidateExternalAuthenticationTest.java b/idp-authn-impl/src/test/java/net/shibboleth/idp/authn/impl/ValidateExternalAuthenticationTest.java
index f4cbe03..a73aba0 100644
--- a/idp-authn-impl/src/test/java/net/shibboleth/idp/authn/impl/ValidateExternalAuthenticationTest.java
+++ b/idp-authn-impl/src/test/java/net/shibboleth/idp/authn/impl/ValidateExternalAuthenticationTest.java
@@ -17,6 +17,9 @@
 
 package net.shibboleth.idp.authn.impl;
 
+import java.util.Arrays;
+import java.util.Set;
+
 import javax.security.auth.Subject;
 import javax.security.auth.login.LoginException;
 import javax.servlet.http.HttpServletRequest;
@@ -25,6 +28,7 @@ import net.shibboleth.idp.authn.AuthnEventIds;
 import net.shibboleth.idp.authn.context.AuthenticationContext;
 import net.shibboleth.idp.authn.context.AuthenticationErrorContext;
 import net.shibboleth.idp.authn.context.ExternalAuthenticationContext;
+import net.shibboleth.idp.authn.principal.ProxyAuthenticationPrincipal;
 import net.shibboleth.idp.authn.principal.TestPrincipal;
 import net.shibboleth.idp.authn.principal.UsernamePrincipal;
 import net.shibboleth.idp.profile.ActionTestingSupport;
@@ -126,7 +130,24 @@ public class ValidateExternalAuthenticationTest extends BaseAuthenticationContex
         Assert.assertTrue(ac.getAuthenticationResult().isPreviousResult());
         Assert.assertEquals(ts.getMillis(), ac.getAuthenticationResult().getAuthenticationInstant());
     }
-    
+
+    @Test public void testAuthnAuthorities() {
+        final AuthenticationContext ac = prc.getSubcontext(AuthenticationContext.class);
+        final ExternalAuthenticationContext eac = ac.getSubcontext(ExternalAuthenticationContext.class, true);
+        eac.setPrincipalName("foo");
+        eac.getAuthenticatingAuthorities().addAll(Arrays.asList("foo", "bar", "baz"));
+        eac.setPreviousResult(true);
+        
+        final Event event = action.execute(src);
+        ActionTestingSupport.assertProceedEvent(event);
+        Assert.assertNotNull(ac.getAuthenticationResult());
+        Assert.assertTrue(ac.getAuthenticationResult().isPreviousResult());
+        final Set<ProxyAuthenticationPrincipal> prin =
+                ac.getAuthenticationResult().getSubject().getPrincipals(ProxyAuthenticationPrincipal.class);
+        Assert.assertEquals(prin.size(), 1);
+        Assert.assertEquals(prin.iterator().next().getAuthorities(), Arrays.asList("foo", "bar", "baz"));
+    }
+
     @Test public void testException() {
         final AuthenticationContext ac = prc.getSubcontext(AuthenticationContext.class);
         final ExternalAuthenticationContext eac = ac.getSubcontext(ExternalAuthenticationContext.class, true);
diff --git a/idp-conf/src/main/resources/system/conf/general-authn-system.xml b/idp-conf/src/main/resources/system/conf/general-authn-system.xml
index dc00594..47d7d52 100644
--- a/idp-conf/src/main/resources/system/conf/general-authn-system.xml
+++ b/idp-conf/src/main/resources/system/conf/general-authn-system.xml
@@ -57,6 +57,7 @@
                 <bean class="net.shibboleth.idp.authn.principal.impl.IdPAttributePrincipalSerializer" />
                 <bean class="net.shibboleth.idp.authn.principal.impl.PasswordPrincipalSerializer"
                     p:dataSealer="#{'%{idp.sealer.storeResource:}'.trim().length() > 0 ? getObject('shibboleth.DataSealer') : null}" />
+                <bean class="net.shibboleth.idp.authn.principal.impl.ProxyAuthenticationPrincipalSerializer" />                    
             </list>
         </property>
     </bean>
diff --git a/idp-saml-impl/src/main/java/net/shibboleth/idp/saml/saml2/profile/impl/AddAuthnStatementToAssertion.java b/idp-saml-impl/src/main/java/net/shibboleth/idp/saml/saml2/profile/impl/AddAuthnStatementToAssertion.java
index 760d87c..ec2c9e5 100644
--- a/idp-saml-impl/src/main/java/net/shibboleth/idp/saml/saml2/profile/impl/AddAuthnStatementToAssertion.java
+++ b/idp-saml-impl/src/main/java/net/shibboleth/idp/saml/saml2/profile/impl/AddAuthnStatementToAssertion.java
@@ -18,6 +18,7 @@
 package net.shibboleth.idp.saml.saml2.profile.impl;
 
 import java.security.Principal;
+import java.util.Set;
 
 import javax.annotation.Nonnull;
 import javax.annotation.Nullable;
@@ -25,6 +26,7 @@ import javax.annotation.Nullable;
 import net.shibboleth.idp.authn.context.AuthenticationContext;
 import net.shibboleth.idp.authn.context.RequestedPrincipalContext;
 import net.shibboleth.idp.authn.principal.DefaultPrincipalDeterminationStrategy;
+import net.shibboleth.idp.authn.principal.ProxyAuthenticationPrincipal;
 
 import org.opensaml.profile.action.ActionSupport;
 import org.opensaml.profile.action.EventIds;
@@ -45,6 +47,7 @@ import org.opensaml.core.xml.config.XMLObjectProviderRegistrySupport;
 import org.opensaml.saml.common.SAMLObjectBuilder;
 import org.opensaml.saml.saml2.core.SubjectLocality;
 import org.opensaml.saml.saml2.core.Assertion;
+import org.opensaml.saml.saml2.core.AuthenticatingAuthority;
 import org.opensaml.saml.saml2.core.AuthnContext;
 import org.opensaml.saml.saml2.core.AuthnStatement;
 import org.opensaml.saml.saml2.core.Response;
@@ -165,6 +168,7 @@ public class AddAuthnStatementToAssertion extends BaseAddAuthenticationStatement
         log.debug("{} Added AuthenticationStatement to Assertion {}", getLogPrefix(), assertion.getID());
     }
 
+// Checkstyle: CyclomaticComplexity OFF
     /**
      * Build the {@link AuthnStatement} to be added to the {@link Response}.
      * 
@@ -208,6 +212,24 @@ public class AddAuthnStatementToAssertion extends BaseAddAuthenticationStatement
                     classRefLookupStrategy.apply(profileRequestContext).getAuthnContextClassRef());
         }
         
+        final Set<ProxyAuthenticationPrincipal> proxyPrincipals =
+                getAuthenticationResult().getSubject().getPrincipals(ProxyAuthenticationPrincipal.class);
+        if (proxyPrincipals != null && !proxyPrincipals.isEmpty()) {
+            if (proxyPrincipals.size() == 1) {
+                final SAMLObjectBuilder<AuthenticatingAuthority> authorityBuilder =
+                        (SAMLObjectBuilder<AuthenticatingAuthority>) bf.<AuthenticatingAuthority>getBuilderOrThrow(
+                                AuthenticatingAuthority.DEFAULT_ELEMENT_NAME);
+                for (final String authority : proxyPrincipals.iterator().next().getAuthorities()) {
+                    final AuthenticatingAuthority aa = authorityBuilder.buildObject();
+                    aa.setURI(authority);
+                    authnContext.getAuthenticatingAuthorities().add(aa);
+                }
+            } else {
+                log.warn("{} Multiple ProxyAuthenticationPrincipals, skipping AuthenticatingAuthority population",
+                        getLogPrefix());
+            }
+        }
+        
         if (sessionLifetimeLookupStrategy != null) {
             final Long lifetime = sessionLifetimeLookupStrategy.apply(profileRequestContext);
             if (lifetime != null && lifetime > 0) {
@@ -227,6 +249,7 @@ public class AddAuthnStatementToAssertion extends BaseAddAuthenticationStatement
         
         return statement;
     }
+// Checkstyle: CyclomaticComplexity ON
     
     /**
      * Default strategy for obtaining assertion to modify.
diff --git a/idp-saml-impl/src/test/java/net/shibboleth/idp/saml/saml2/profile/impl/AddAuthnStatementToAssertionTest.java b/idp-saml-impl/src/test/java/net/shibboleth/idp/saml/saml2/profile/impl/AddAuthnStatementToAssertionTest.java
index 9c3d813..f11b5d6 100644
--- a/idp-saml-impl/src/test/java/net/shibboleth/idp/saml/saml2/profile/impl/AddAuthnStatementToAssertionTest.java
+++ b/idp-saml-impl/src/test/java/net/shibboleth/idp/saml/saml2/profile/impl/AddAuthnStatementToAssertionTest.java
@@ -17,12 +17,15 @@
 
 package net.shibboleth.idp.saml.saml2.profile.impl;
 
+import java.util.Arrays;
+
 import javax.security.auth.Subject;
 
 import net.shibboleth.idp.authn.AuthenticationResult;
 import net.shibboleth.idp.authn.AuthnEventIds;
 import net.shibboleth.idp.authn.context.AuthenticationContext;
 import net.shibboleth.idp.authn.context.RequestedPrincipalContext;
+import net.shibboleth.idp.authn.principal.ProxyAuthenticationPrincipal;
 import net.shibboleth.idp.profile.ActionTestingSupport;
 
 import org.opensaml.profile.action.EventIds;
@@ -69,13 +72,13 @@ public class AddAuthnStatementToAssertionTest extends OpenSAMLInitBaseTestCase {
     }
     
     /** Test that the action errors out properly if there is no authentication context. */
-    @Test public void testNoAuthnContext() throws Exception {
+    @Test public void testNoAuthnContext() {
         final Event event = action.execute(rc);
         ActionTestingSupport.assertEvent(event, AuthnEventIds.INVALID_AUTHN_CTX);
     }
 
     /** Test that the action errors out properly if there is no relying party context. */
-    @Test public void testNoRelyingPartyContext() throws Exception {
+    @Test public void testNoRelyingPartyContext() {
         prc.getSubcontext(AuthenticationContext.class, true);
         prc.removeSubcontext(RelyingPartyContext.class);
 
@@ -84,7 +87,7 @@ public class AddAuthnStatementToAssertionTest extends OpenSAMLInitBaseTestCase {
     }
 
     /** Test that the action errors out properly if there is no context. */
-    @Test public void testNoContext() throws Exception {
+    @Test public void testNoContext() {
         prc.setOutboundMessageContext(null);
         prc.getSubcontext(AuthenticationContext.class, true).setAuthenticationResult(
                 new AuthenticationResult("Test", new AuthnContextClassRefPrincipal("Test")));
@@ -101,8 +104,9 @@ public class AddAuthnStatementToAssertionTest extends OpenSAMLInitBaseTestCase {
         ActionTestingSupport.assertEvent(event, AuthnEventIds.INVALID_AUTHN_CTX);
     }
 
-    /** Test that the authentication statement is properly added. */
-    @Test public void testAddAuthenticationStatement() throws Exception {
+    /** Test that the authentication statement is properly added. 
+     * @throws InterruptedException */
+    @Test public void testAddAuthenticationStatement() throws InterruptedException {
         final long now = System.currentTimeMillis();
         // this is here to allow the event's creation time to deviate from the 'start' time
         Thread.sleep(50);
@@ -138,10 +142,11 @@ public class AddAuthnStatementToAssertionTest extends OpenSAMLInitBaseTestCase {
         Assert.assertNotNull(authnContext);
         Assert.assertNotNull(authnContext.getAuthnContextClassRef());
         Assert.assertEquals(authnContext.getAuthnContextClassRef().getAuthnContextClassRef(), "Test");
+        Assert.assertTrue(authnContext.getAuthenticatingAuthorities().isEmpty());
     }
 
     /** Test that the authentication statement is properly added. */
-    @Test public void testSessionNotOnOrAfter() throws Exception {
+    @Test public void testSessionNotOnOrAfter() {
         final BrowserSSOProfileConfiguration ssoConfig = new BrowserSSOProfileConfiguration();
         ssoConfig.setMaximumSPSessionLifetime(60 * 60 * 1000);
         ssoConfig.setSecurityConfiguration(new SecurityConfiguration());
@@ -160,7 +165,7 @@ public class AddAuthnStatementToAssertionTest extends OpenSAMLInitBaseTestCase {
     }
     
     /** Test that the authentication statement is properly added with the right method. */
-    @Test public void testAddAuthenticationStatementAndMethod() throws Exception {
+    @Test public void testAddAuthenticationStatementAndMethod() {
         final Subject subject = new Subject();
         subject.getPrincipals().add(new AuthnContextClassRefPrincipal("Foo"));
         subject.getPrincipals().add(new AuthnContextClassRefPrincipal("Bar"));
@@ -180,7 +185,7 @@ public class AddAuthnStatementToAssertionTest extends OpenSAMLInitBaseTestCase {
         Assert.assertEquals(response.getAssertions().size(), 1);
         Assert.assertNotNull(response.getAssertions().get(0));
 
-        Assertion assertion = response.getAssertions().get(0);
+        final Assertion assertion = response.getAssertions().get(0);
         Assert.assertEquals(assertion.getAuthnStatements().size(), 1);
         Assert.assertNotNull(assertion.getAuthnStatements().get(0));
 
@@ -189,6 +194,25 @@ public class AddAuthnStatementToAssertionTest extends OpenSAMLInitBaseTestCase {
         Assert.assertNotNull(authnContext);
         Assert.assertNotNull(authnContext.getAuthnContextClassRef());
         Assert.assertEquals(authnContext.getAuthnContextClassRef().getAuthnContextClassRef(), "Bar");
+        Assert.assertTrue(authnContext.getAuthenticatingAuthorities().isEmpty());
     }
     
+    @Test public void testAuthenticatingAuthorities() {
+        prc.getSubcontext(AuthenticationContext.class, true).setAuthenticationResult(
+                new AuthenticationResult("Test", new ProxyAuthenticationPrincipal(Arrays.asList("foo", "bar", "baz"))));
+        
+        final Event event = action.execute(rc);
+        ActionTestingSupport.assertProceedEvent(event);
+
+        final Response response = (Response) prc.getOutboundMessageContext().getMessage();
+        final Assertion assertion = response.getAssertions().get(0);
+        final AuthnStatement authenticationStatement = assertion.getAuthnStatements().get(0);
+        final AuthnContext authnContext = authenticationStatement.getAuthnContext();
+        Assert.assertNotNull(authnContext);
+        Assert.assertEquals(authnContext.getAuthenticatingAuthorities().size(), 3);
+        Assert.assertEquals(authnContext.getAuthenticatingAuthorities().get(0).getURI(), "foo");
+        Assert.assertEquals(authnContext.getAuthenticatingAuthorities().get(1).getURI(), "bar");
+        Assert.assertEquals(authnContext.getAuthenticatingAuthorities().get(2).getURI(), "baz");
+    }
+
 }
\ No newline at end of file

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


More information about the commits mailing list