[java-identity-provider] branch master updated: IDP-1494 - Login flow for proxied SAML authentication
Scott Cantor
cantor.2 at osu.edu
Tue Nov 19 20:14:08 EST 2019
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=09ba5c2af7c4753a18b7863d8f92ef48c2ef5131
The following commit(s) were added to refs/heads/master by this push:
new 09ba5c2 IDP-1494 - Login flow for proxied SAML authentication
09ba5c2 is described below
commit 09ba5c2af7c4753a18b7863d8f92ef48c2ef5131
Author: Scott Cantor <cantor.2 at osu.edu>
AuthorDate: Tue Nov 19 20:09:12 2019 -0500
IDP-1494 - Login flow for proxied SAML authentication
https://issues.shibboleth.net/jira/browse/IDP-1494
Encode ProxyRestriction condition into Subject.
Enforce proxy restrictions generically during finalization.
---
idp-authn-impl/pom.xml | 16 ++-
.../idp/authn/impl/FinalizeAuthentication.java | 99 ++++++++++++++--
.../idp/authn/impl/FinalizeAuthenticationTest.java | 124 +++++++++++++++++++--
.../profile/impl/ValidateSAMLAuthentication.java | 56 ++++++++--
4 files changed, 261 insertions(+), 34 deletions(-)
diff --git a/idp-authn-impl/pom.xml b/idp-authn-impl/pom.xml
index 2e1fba2..106e461 100644
--- a/idp-authn-impl/pom.xml
+++ b/idp-authn-impl/pom.xml
@@ -24,6 +24,11 @@
<!-- Compile Dependencies -->
<dependency>
<groupId>${project.groupId}</groupId>
+ <artifactId>idp-admin-api</artifactId>
+ <version>${project.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>${project.groupId}</groupId>
<artifactId>idp-attribute-api</artifactId>
<version>${project.version}</version>
</dependency>
@@ -163,11 +168,6 @@
<artifactId>DuoWeb</artifactId>
<version>${duoweb.version}</version>
</dependency>
- <dependency>
- <groupId>org.jasig.cas.client</groupId>
- <artifactId>cas-client-core</artifactId>
- <version>${cas-client.version}</version>
- </dependency>
<!-- DEPRECATED - remove in V5 -->
@@ -197,6 +197,12 @@
<dependency>
<groupId>${opensaml.groupId}</groupId>
+ <artifactId>opensaml-saml-impl</artifactId>
+ <scope>test</scope>
+ </dependency>
+
+ <dependency>
+ <groupId>${opensaml.groupId}</groupId>
<artifactId>opensaml-security-impl</artifactId>
<scope>test</scope>
</dependency>
diff --git a/idp-authn-impl/src/main/java/net/shibboleth/idp/authn/impl/FinalizeAuthentication.java b/idp-authn-impl/src/main/java/net/shibboleth/idp/authn/impl/FinalizeAuthentication.java
index 83f7263..53dd433 100644
--- a/idp-authn-impl/src/main/java/net/shibboleth/idp/authn/impl/FinalizeAuthentication.java
+++ b/idp-authn-impl/src/main/java/net/shibboleth/idp/authn/impl/FinalizeAuthentication.java
@@ -22,10 +22,13 @@ import java.util.ArrayList;
import java.util.Collections;
import java.util.Map;
import java.util.Set;
+import java.util.function.Function;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
+import javax.security.auth.Subject;
+import net.shibboleth.idp.admin.AdministrativeFlowDescriptor;
import net.shibboleth.idp.authn.AbstractAuthenticationAction;
import net.shibboleth.idp.authn.AuthenticationFlowDescriptor;
import net.shibboleth.idp.authn.AuthenticationResult;
@@ -37,9 +40,14 @@ import net.shibboleth.idp.authn.context.SubjectContext;
import net.shibboleth.idp.authn.principal.PrincipalEvalPredicate;
import net.shibboleth.idp.authn.principal.PrincipalEvalPredicateFactory;
import net.shibboleth.idp.authn.principal.PrincipalSupportingComponent;
+import net.shibboleth.idp.authn.principal.ProxyAuthenticationPrincipal;
import net.shibboleth.idp.profile.IdPEventIds;
+import net.shibboleth.idp.profile.context.RelyingPartyContext;
import net.shibboleth.idp.session.context.SessionContext;
+import net.shibboleth.utilities.java.support.component.ComponentSupport;
+import net.shibboleth.utilities.java.support.logic.Constraint;
+import org.opensaml.messaging.context.navigate.ChildContextLookup;
import org.opensaml.profile.action.ActionSupport;
import org.opensaml.profile.context.ProfileRequestContext;
import org.slf4j.Logger;
@@ -50,6 +58,9 @@ import org.slf4j.LoggerFactory;
* of an active result) and transfers information from other contexts into a {@link SubjectContext}
* child of the {@link ProfileRequestContext}.
*
+ * <p>The action enforces any constraints on proxying that may be present in the result against
+ * the intended use based on the {@link RelyingPartyContext}.</p>
+ *
* <p>The action also cross-checks {@link RequestedPrincipalContext#getMatchingPrincipal()}, if set,
* against the {@link AuthenticationResult} to ensure that the result produced actually satisfies the
* request. This is redundant when reusing active results, but is necessary to prevent a flow from running
@@ -75,6 +86,7 @@ import org.slf4j.LoggerFactory;
*
* @event {@link org.opensaml.profile.action.EventIds#PROCEED_EVENT_ID}
* @event {@link IdPEventIds#INVALID_SUBJECT_CTX}
+ * @event {@link AuthnEventIds#INVALID_AUTHN_CTX}
* @event {@link AuthnEventIds#REQUEST_UNSUPPORTED}
*
* @pre <pre>ProfileRequestContext.getSubcontext(AuthenticationContext.class) != null</pre>
@@ -90,10 +102,31 @@ public class FinalizeAuthentication extends AbstractAuthenticationAction {
/** Class logger. */
@Nonnull private final Logger log = LoggerFactory.getLogger(FinalizeAuthentication.class);
+ /** Strategy used to look up a {@link RelyingPartyContext} for proxy validation. */
+ @Nonnull private Function<ProfileRequestContext,RelyingPartyContext> relyingPartyContextLookupStrategy;
+
/** The principal name extracted from the context tree. */
@Nullable private String canonicalPrincipalName;
-
-// Checkstyle: CyclomaticComplexity OFF
+
+ /** Constructor. */
+ public FinalizeAuthentication() {
+ relyingPartyContextLookupStrategy = new ChildContextLookup<>(RelyingPartyContext.class);
+ }
+
+ /**
+ * Set the strategy used to return the {@link RelyingPartyContext}.
+ *
+ * @param strategy lookup strategy
+ */
+ public void setRelyingPartyContextLookupStrategy(
+ @Nonnull final Function<ProfileRequestContext,RelyingPartyContext> strategy) {
+ ComponentSupport.ifInitializedThrowUnmodifiabledComponentException(this);
+
+ relyingPartyContextLookupStrategy =
+ Constraint.isNotNull(strategy, "RelyingPartyContext lookup strategy cannot be null");
+ }
+
+ // Checkstyle: CyclomaticComplexity OFF
/** {@inheritDoc} */
@Override
protected boolean doPreExecute(@Nonnull final ProfileRequestContext profileRequestContext,
@@ -119,6 +152,15 @@ public class FinalizeAuthentication extends AbstractAuthenticationAction {
canonicalPrincipalName);
}
}
+
+ final AuthenticationResult latest = authenticationContext.getAuthenticationResult();
+ if (latest == null) {
+ log.warn("{} Authentication result missing from context?", getLogPrefix());
+ ActionSupport.buildEvent(profileRequestContext, AuthnEventIds.INVALID_AUTHN_CTX);
+ return false;
+ } else if (!checkProxyRestrictions(profileRequestContext, latest.getSubject())) {
+ return false;
+ }
// Check for requested Principal criteria and make sure the result accomodates the criteria.
// This is required because flow selection is based (generally) on statically-defined information
@@ -126,12 +168,6 @@ public class FinalizeAuthentication extends AbstractAuthenticationAction {
final RequestedPrincipalContext requestedPrincipalCtx =
authenticationContext.getSubcontext(RequestedPrincipalContext.class);
if (requestedPrincipalCtx != null) {
- final AuthenticationResult latest = authenticationContext.getAuthenticationResult();
- if (latest == null) {
- log.warn("{} Authentication result missing from context?", getLogPrefix());
- ActionSupport.buildEvent(profileRequestContext, AuthnEventIds.REQUEST_UNSUPPORTED);
- return false;
- }
// If a matching principal is set, re-verify it. Normally this will work.
final Principal match = requestedPrincipalCtx.getMatchingPrincipal();
@@ -221,7 +257,7 @@ public class FinalizeAuthentication extends AbstractAuthenticationAction {
p.getClass(), requestedPrincipalCtx.getOperator());
if (factory != null) {
final PrincipalEvalPredicate predicate = factory.getPredicate(p);
-
+
// For unweighted results, we'd just apply the predicate to the AuthenticationResult, but
// we won't be able to honor weighting, so we have to walk the supported principals one
// at a time, wrap it to apply the predicate, and then record it if it succeeds.
@@ -261,4 +297,49 @@ public class FinalizeAuthentication extends AbstractAuthenticationAction {
return flowDescriptor.getHighestWeighted(matches);
}
+// Checkstyle: CyclomaticComplexity OFF
+ /**
+ * Check for proxy restrictions and evaluate them against the request.
+ *
+ * @param profileRequestContext current profile request context
+ * @param subject the authentication result's subject
+ *
+ * @return true iff processing should continue
+ */
+ private boolean checkProxyRestrictions(@Nonnull final ProfileRequestContext profileRequestContext,
+ @Nonnull final Subject subject) {
+
+ final Set<ProxyAuthenticationPrincipal> proxieds = subject.getPrincipals(ProxyAuthenticationPrincipal.class);
+ if (proxieds == null || proxieds.isEmpty()) {
+ return true;
+ }
+
+ // Check for admin flow as relying party.
+ final RelyingPartyContext rpCtx = relyingPartyContextLookupStrategy.apply(profileRequestContext);
+ if (rpCtx == null || rpCtx.getRelyingPartyId() == null) {
+ log.debug("{} No RelyingParty identity, ignoring proxy restrictions on result", getLogPrefix());
+ return true;
+ } else if (rpCtx.getProfileConfig() instanceof AdministrativeFlowDescriptor) {
+ log.debug("{} Relying party is an admin flow, ignoring proxy restrictions on result",
+ getLogPrefix());
+ return true;
+ }
+
+ for (final ProxyAuthenticationPrincipal proxied : proxieds) {
+ if (proxied.getProxyCount() != null && proxied.getProxyCount() == 0) {
+ log.warn("{} Result contains a proxy count of zero, disallowing use", getLogPrefix());
+ ActionSupport.buildEvent(profileRequestContext, AuthnEventIds.REQUEST_UNSUPPORTED);
+ return false;
+ } else if (!proxied.getAudiences().isEmpty() &&
+ !proxied.getAudiences().contains(rpCtx.getRelyingPartyId())) {
+ log.warn("{} Result contains a proxy restriction disallowing relying party '{}'",
+ getLogPrefix(), rpCtx.getRelyingPartyId());
+ ActionSupport.buildEvent(profileRequestContext, AuthnEventIds.REQUEST_UNSUPPORTED);
+ return false;
+ }
+ }
+
+ return true;
+ }
+// Checkstyle: CyclomaticComplexity ON
}
\ No newline at end of file
diff --git a/idp-authn-impl/src/test/java/net/shibboleth/idp/authn/impl/FinalizeAuthenticationTest.java b/idp-authn-impl/src/test/java/net/shibboleth/idp/authn/impl/FinalizeAuthenticationTest.java
index f7cb47f..0bd663c 100644
--- a/idp-authn-impl/src/test/java/net/shibboleth/idp/authn/impl/FinalizeAuthenticationTest.java
+++ b/idp-authn-impl/src/test/java/net/shibboleth/idp/authn/impl/FinalizeAuthenticationTest.java
@@ -17,22 +17,24 @@
package net.shibboleth.idp.authn.impl;
-import java.security.Principal;
import java.util.Arrays;
import java.util.Collections;
import javax.security.auth.Subject;
+import net.shibboleth.idp.admin.BasicAdministrativeFlowDescriptor;
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.context.SubjectCanonicalizationContext;
import net.shibboleth.idp.authn.context.SubjectContext;
+import net.shibboleth.idp.authn.principal.ProxyAuthenticationPrincipal;
import net.shibboleth.idp.authn.principal.TestPrincipal;
import net.shibboleth.idp.authn.principal.impl.ExactPrincipalEvalPredicateFactory;
import net.shibboleth.idp.profile.ActionTestingSupport;
import net.shibboleth.idp.profile.IdPEventIds;
+import net.shibboleth.idp.profile.context.RelyingPartyContext;
import org.springframework.webflow.execution.Event;
import org.testng.Assert;
@@ -54,13 +56,19 @@ public class FinalizeAuthenticationTest extends BaseAuthenticationContextTest {
@Test public void testNotSet() {
final Event event = action.execute(src);
- ActionTestingSupport.assertProceedEvent(event);
+ ActionTestingSupport.assertEvent(event, AuthnEventIds.INVALID_AUTHN_CTX);
Assert.assertNull(prc.getSubcontext(SubjectContext.class));
}
@Test public void testMismatch() {
prc.getSubcontext(SubjectContext.class, true).setPrincipalName("foo");
prc.getSubcontext(SubjectCanonicalizationContext.class, true).setPrincipalName("bar");
+
+ final AuthenticationResult active = new AuthenticationResult("test2", new Subject());
+ active.getSubject().getPrincipals().add(new TestPrincipal("bar2"));
+
+ final AuthenticationContext authCtx = prc.getSubcontext(AuthenticationContext.class);
+ authCtx.setAuthenticationResult(active);
final Event event = action.execute(src);
@@ -81,7 +89,7 @@ public class FinalizeAuthenticationTest extends BaseAuthenticationContextTest {
TestPrincipal.class, "florp", new ExactPrincipalEvalPredicateFactory());
rpCtx.setMatchingPrincipal(new TestPrincipal("bar1"));
rpCtx.setOperator("florp");
- rpCtx.setRequestedPrincipals(Collections.<Principal>singletonList(new TestPrincipal("bar1")));
+ rpCtx.setRequestedPrincipals(Collections.singletonList(new TestPrincipal("bar1")));
authCtx.addSubcontext(rpCtx);
final Event event = action.execute(src);
@@ -103,7 +111,7 @@ public class FinalizeAuthenticationTest extends BaseAuthenticationContextTest {
TestPrincipal.class, "florp", new ExactPrincipalEvalPredicateFactory());
rpCtx.setMatchingPrincipal(new TestPrincipal("bar1"));
rpCtx.setOperator("florp");
- rpCtx.setRequestedPrincipals(Collections.<Principal>singletonList(new TestPrincipal("bar2")));
+ rpCtx.setRequestedPrincipals(Collections.singletonList(new TestPrincipal("bar2")));
authCtx.addSubcontext(rpCtx);
final Event event = action.execute(src);
@@ -121,14 +129,14 @@ public class FinalizeAuthenticationTest extends BaseAuthenticationContextTest {
final Event event = action.execute(src);
- ActionTestingSupport.assertProceedEvent(event);
- SubjectContext sc = prc.getSubcontext(SubjectContext.class);
- Assert.assertNotNull(sc);
- Assert.assertEquals(sc.getPrincipalName(), "foo");
+ ActionTestingSupport.assertEvent(event, AuthnEventIds.INVALID_AUTHN_CTX);
+ Assert.assertNull(prc.getSubcontext(SubjectContext.class));
}
@Test public void testOneActive() {
final AuthenticationResult active = new AuthenticationResult("test2", new Subject());
+ active.getSubject().getPrincipals().add(
+ new ProxyAuthenticationPrincipal(Collections.singletonList(ActionTestingSupport.OUTBOUND_MSG_ISSUER)));
final AuthenticationContext authCtx = prc.getSubcontext(AuthenticationContext.class);
authCtx.setActiveResults(Arrays.asList(active));
authCtx.setAuthenticationResult(active);
@@ -159,4 +167,104 @@ public class FinalizeAuthenticationTest extends BaseAuthenticationContextTest {
Assert.assertEquals(sc.getPrincipalName(), "foo");
Assert.assertEquals(sc.getAuthenticationResults().size(), 2);
}
+
+ @Test public void testZeroProxyCount() {
+ final AuthenticationResult active = new AuthenticationResult("test2", new Subject());
+ final ProxyAuthenticationPrincipal proxy =
+ new ProxyAuthenticationPrincipal(Collections.singletonList(ActionTestingSupport.OUTBOUND_MSG_ISSUER));
+ proxy.setProxyCount(0);
+ active.getSubject().getPrincipals().add(proxy);
+ final AuthenticationContext authCtx = prc.getSubcontext(AuthenticationContext.class);
+ authCtx.setActiveResults(Arrays.asList(active));
+ authCtx.setAuthenticationResult(active);
+ prc.getSubcontext(SubjectCanonicalizationContext.class, true).setPrincipalName("foo");
+
+ final Event event = action.execute(src);
+ ActionTestingSupport.assertEvent(event, AuthnEventIds.REQUEST_UNSUPPORTED);
+ Assert.assertNull(prc.getSubcontext(SubjectContext.class));
+ }
+
+ @Test public void testZeroProxyCountAdminFlow() {
+ final AuthenticationResult active = new AuthenticationResult("test2", new Subject());
+ final ProxyAuthenticationPrincipal proxy =
+ new ProxyAuthenticationPrincipal(Collections.singletonList(ActionTestingSupport.OUTBOUND_MSG_ISSUER));
+ proxy.setProxyCount(0);
+ active.getSubject().getPrincipals().add(proxy);
+ final AuthenticationContext authCtx = prc.getSubcontext(AuthenticationContext.class);
+ authCtx.setActiveResults(Arrays.asList(active));
+ authCtx.setAuthenticationResult(active);
+ prc.getSubcontext(SubjectCanonicalizationContext.class, true).setPrincipalName("foo");
+
+ prc.getSubcontext(RelyingPartyContext.class).setProfileConfig(new BasicAdministrativeFlowDescriptor("admin/test"));
+
+ final Event event = action.execute(src);
+
+ ActionTestingSupport.assertProceedEvent(event);
+ SubjectContext sc = prc.getSubcontext(SubjectContext.class);
+ Assert.assertNotNull(sc);
+ Assert.assertEquals(sc.getPrincipalName(), "foo");
+ Assert.assertEquals(sc.getAuthenticationResults().size(), 1);
+ }
+
+ @Test public void testZeroProxyCountNoRP() {
+ final AuthenticationResult active = new AuthenticationResult("test2", new Subject());
+ final ProxyAuthenticationPrincipal proxy =
+ new ProxyAuthenticationPrincipal(Collections.singletonList(ActionTestingSupport.OUTBOUND_MSG_ISSUER));
+ proxy.setProxyCount(0);
+ active.getSubject().getPrincipals().add(proxy);
+ final AuthenticationContext authCtx = prc.getSubcontext(AuthenticationContext.class);
+ authCtx.setActiveResults(Arrays.asList(active));
+ authCtx.setAuthenticationResult(active);
+ prc.getSubcontext(SubjectCanonicalizationContext.class, true).setPrincipalName("foo");
+
+ prc.removeSubcontext(RelyingPartyContext.class);
+
+ final Event event = action.execute(src);
+
+ ActionTestingSupport.assertProceedEvent(event);
+ SubjectContext sc = prc.getSubcontext(SubjectContext.class);
+ Assert.assertNotNull(sc);
+ Assert.assertEquals(sc.getPrincipalName(), "foo");
+ Assert.assertEquals(sc.getAuthenticationResults().size(), 1);
+ }
+
+ @Test public void testValidProxyAudience() {
+ final AuthenticationResult active = new AuthenticationResult("test2", new Subject());
+ final ProxyAuthenticationPrincipal proxy =
+ new ProxyAuthenticationPrincipal(Collections.singletonList(ActionTestingSupport.OUTBOUND_MSG_ISSUER));
+ proxy.setProxyCount(10);
+ proxy.getAudiences().add(ActionTestingSupport.INBOUND_MSG_ISSUER);
+ active.getSubject().getPrincipals().add(proxy);
+ final AuthenticationContext authCtx = prc.getSubcontext(AuthenticationContext.class);
+ authCtx.setActiveResults(Arrays.asList(active));
+ authCtx.setAuthenticationResult(active);
+ prc.getSubcontext(SubjectCanonicalizationContext.class, true).setPrincipalName("foo");
+
+ final Event event = action.execute(src);
+
+ ActionTestingSupport.assertProceedEvent(event);
+ SubjectContext sc = prc.getSubcontext(SubjectContext.class);
+ Assert.assertNotNull(sc);
+ Assert.assertEquals(sc.getPrincipalName(), "foo");
+ Assert.assertEquals(sc.getAuthenticationResults().size(), 1);
+ }
+
+ @Test public void testInvalidProxyAudience() {
+ final AuthenticationResult active = new AuthenticationResult("test2", new Subject());
+ final ProxyAuthenticationPrincipal proxy =
+ new ProxyAuthenticationPrincipal(Collections.singletonList(ActionTestingSupport.OUTBOUND_MSG_ISSUER));
+ proxy.setProxyCount(10);
+ proxy.getAudiences().add(ActionTestingSupport.OUTBOUND_MSG_ISSUER);
+ active.getSubject().getPrincipals().add(proxy);
+ final AuthenticationContext authCtx = prc.getSubcontext(AuthenticationContext.class);
+ authCtx.setActiveResults(Arrays.asList(active));
+ authCtx.setAuthenticationResult(active);
+ prc.getSubcontext(SubjectCanonicalizationContext.class, true).setPrincipalName("foo");
+
+ final Event event = action.execute(src);
+
+ ActionTestingSupport.assertEvent(event, AuthnEventIds.REQUEST_UNSUPPORTED);
+ Assert.assertNull(prc.getSubcontext(SubjectContext.class));
+ }
+
}
\ No newline at end of file
diff --git a/idp-saml-impl/src/main/java/net/shibboleth/idp/saml/saml2/profile/impl/ValidateSAMLAuthentication.java b/idp-saml-impl/src/main/java/net/shibboleth/idp/saml/saml2/profile/impl/ValidateSAMLAuthentication.java
index 391213b..390d1ac 100644
--- a/idp-saml-impl/src/main/java/net/shibboleth/idp/saml/saml2/profile/impl/ValidateSAMLAuthentication.java
+++ b/idp-saml-impl/src/main/java/net/shibboleth/idp/saml/saml2/profile/impl/ValidateSAMLAuthentication.java
@@ -67,8 +67,10 @@ import org.opensaml.saml.metadata.resolver.MetadataResolver;
import org.opensaml.saml.saml2.core.Assertion;
import org.opensaml.saml.saml2.core.Attribute;
import org.opensaml.saml.saml2.core.AttributeStatement;
+import org.opensaml.saml.saml2.core.Audience;
import org.opensaml.saml.saml2.core.AuthenticatingAuthority;
import org.opensaml.saml.saml2.core.AuthnContext;
+import org.opensaml.saml.saml2.core.ProxyRestriction;
import org.opensaml.saml.saml2.core.Response;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -291,7 +293,8 @@ public class ValidateSAMLAuthentication extends AbstractValidationAction {
}
}
}
-
+
+// Checkstyle: CyclomaticComplexity OFF
/** {@inheritDoc} */
@Override
@Nonnull protected Subject populateSubject(@Nonnull final Subject subject) {
@@ -327,9 +330,35 @@ public class ValidateSAMLAuthentication extends AbstractValidationAction {
log.warn("{} No AuthnContext information usable from assertion", getLogPrefix());
}
+ subject.getPrincipals().add(buildProxyPrincipal(authnContext));
+
+ if (attributeContext != null && !attributeContext.getIdPAttributes().isEmpty()) {
+ log.debug("{} Adding filtered inbound attributes to Subject", getLogPrefix());
+ subject.getPrincipals().addAll(
+ attributeContext.getIdPAttributes().values()
+ .stream()
+ .map(a -> new IdPAttributePrincipal(a))
+ .collect(Collectors.toUnmodifiableList()));
+ }
+
+ return subject;
+ }
+// Checkstyle: CyclomaticComplexity ON
+
+ /**
+ * Construct a populated {@link ProxyAuthenticationPrincipal} based on the inbound assertion.
+ *
+ * @param authnContext the SAML {@link AuthnContext} issued by the proxied IdP
+ *
+ * @return a constructed {@link ProxyAuthenticationPrincipal} to include in the {@link Subject}
+ */
+ @Nonnull private ProxyAuthenticationPrincipal buildProxyPrincipal(@Nonnull final AuthnContext authnContext) {
+
final ProxyAuthenticationPrincipal proxied = new ProxyAuthenticationPrincipal();
- proxied.getAuthorities().add(
- ((Assertion) samlAuthnContext.getAuthnStatement().getParent()).getIssuer().getValue());
+
+ final Assertion assertion = (Assertion) samlAuthnContext.getAuthnStatement().getParent();
+
+ proxied.getAuthorities().add(assertion.getIssuer().getValue());
if (!authnContext.getAuthenticatingAuthorities().isEmpty()) {
proxied.getAuthorities().addAll(
@@ -339,18 +368,21 @@ public class ValidateSAMLAuthentication extends AbstractValidationAction {
.filter(aa -> !Strings.isNullOrEmpty(aa))
.collect(Collectors.toUnmodifiableList()));
}
- subject.getPrincipals().add(proxied);
- if (attributeContext != null && !attributeContext.getIdPAttributes().isEmpty()) {
- log.debug("{} Adding filtered inbound attributes to Subject", getLogPrefix());
- subject.getPrincipals().addAll(
- attributeContext.getIdPAttributes().values()
- .stream()
- .map(a -> new IdPAttributePrincipal(a))
- .collect(Collectors.toUnmodifiableList()));
+ final ProxyRestriction condition = assertion.getConditions().getProxyRestriction();
+ if (condition != null) {
+ proxied.setProxyCount(condition.getProxyCount());
+ if (condition.getAudiences() != null) {
+ proxied.getAudiences().addAll(
+ condition.getAudiences()
+ .stream()
+ .map(Audience::getURI)
+ .filter(a -> !Strings.isNullOrEmpty(a))
+ .collect(Collectors.toUnmodifiableList()));
+ }
}
- return subject;
+ return proxied;
}
/**
--
To stop receiving notification emails like this one, please contact
the administrator of this repository.
More information about the commits
mailing list