[java-identity-provider] branch main updated: IDP-2353 - C14n flow that runs a deployer-defined bean
Scott Cantor
cantor.2 at osu.edu
Wed Feb 26 19:57:22 UTC 2025
This is an automated email from the git hooks/post-receive script.
scantor pushed a commit to branch main
in repository java-identity-provider.
View the commit online:
http://git.shibboleth.net/view/?p=java-identity-provider.git;a=commit;h=cabf928bdd28d23a6d4e8dc1a5d9ded0477f5076
The following commit(s) were added to refs/heads/main by this push:
new cabf928bd IDP-2353 - C14n flow that runs a deployer-defined bean
cabf928bd is described below
commit cabf928bdd28d23a6d4e8dc1a5d9ded0477f5076
Author: Scott Cantor <cantor.2 at osu.edu>
AuthorDate: Wed Feb 26 14:57:19 2025 -0500
IDP-2353 - C14n flow that runs a deployer-defined bean
https://shibboleth.atlassian.net/browse/IDP-2353
Reimplement NameID c14n on top of new API to eliminate webflow.
Adjust signaling and error handling around much of c14n layer.
Improve logging for clarity.
Eliminate excess use of c14n flow activation conditions.
---
.../idp/authn/AbstractSubjectCanonicalizer.java | 6 +-
.../net/shibboleth/idp/authn/AuthnEventIds.java | 10 +-
.../shibboleth/idp/authn/SubjectCanonicalizer.java | 3 +-
.../idp/authn/impl/FinalizeAuthentication.java | 20 +-
.../impl/SelectSubjectCanonicalizationFlow.java | 24 +--
.../authn/impl/SimpleSubjectCanonicalization.java | 38 +---
.../authn/impl/X500SubjectCanonicalization.java | 40 +---
.../impl/SimpleSubjectCanonicalizationTest.java | 20 +-
.../impl/X500SubjectCanonicalizationTest.java | 15 +-
.../shibboleth/idp/conf/subject-c14n-system.xml | 151 +++++++++-----
.../net/shibboleth/idp/conf/webflow-config.xml | 14 --
.../idp/flows/c14n/subject-c14n-flow.xml | 5 +-
.../flows/c14n/subject-c14n-saml-default-beans.xml | 83 --------
.../flows/c14n/subject-c14n-saml-default-flow.xml | 23 ---
.../src/test/resources/test/override-beans.xml | 35 +---
.../shibboleth/idp/saml/nameid/NameIDDecoder.java | 2 +
.../nameid/impl/BaseCryptoTransientDecoder.java | 44 ++--
.../nameid/impl/CryptoTransientNameIDDecoder.java | 3 +-
.../impl/CryptoTransientNameIdentifierDecoder.java | 3 +-
.../saml/nameid/impl/NameIDCanonicalization.java | 228 ++++++++-------------
.../impl/NameIdentifierCanonicalization.java | 228 ++++++++-------------
.../nameid/impl/StoredPersistentIdDecoder.java | 13 +-
.../impl/CryptoTransientNameIDDecoderTest.java | 17 +-
.../CryptoTransientNameIdentifierDecoderTest.java | 8 +-
.../nameid/impl/NameIDCanonicalizationTest.java | 77 +++----
.../impl/NameIdentifierCanonicalizationTest.java | 91 +++-----
.../idp/saml/nameid/impl/TransientDecoderTest.java | 8 +-
27 files changed, 454 insertions(+), 755 deletions(-)
diff --git a/idp-authn-api/src/main/java/net/shibboleth/idp/authn/AbstractSubjectCanonicalizer.java b/idp-authn-api/src/main/java/net/shibboleth/idp/authn/AbstractSubjectCanonicalizer.java
index 0e1e36f15..fb374930d 100644
--- a/idp-authn-api/src/main/java/net/shibboleth/idp/authn/AbstractSubjectCanonicalizer.java
+++ b/idp-authn-api/src/main/java/net/shibboleth/idp/authn/AbstractSubjectCanonicalizer.java
@@ -141,8 +141,8 @@ public abstract class AbstractSubjectCanonicalizer extends AbstractIdentifiableI
}
if (c14nContext.getSubject() == null) {
- c14nContext.setException(new SubjectCanonicalizationException("No Subject found in context"));
- return AuthnEventIds.INVALID_SUBJECT;
+ log.error("{} No Subject found in context", getLogPrefix());
+ return AuthnEventIds.INVALID_SUBJECT_C14N_CTX;
}
return doApply(c14nContext);
@@ -155,7 +155,7 @@ public abstract class AbstractSubjectCanonicalizer extends AbstractIdentifiableI
*
* @return event indicating result of function
*/
- @Nonnull protected abstract String doApply(@Nonnull final SubjectCanonicalizationContext c14nContext);
+ protected abstract @Nullable String doApply(@Nonnull final SubjectCanonicalizationContext c14nContext);
/**
diff --git a/idp-authn-api/src/main/java/net/shibboleth/idp/authn/AuthnEventIds.java b/idp-authn-api/src/main/java/net/shibboleth/idp/authn/AuthnEventIds.java
index c6d777e01..894e4165c 100644
--- a/idp-authn-api/src/main/java/net/shibboleth/idp/authn/AuthnEventIds.java
+++ b/idp-authn-api/src/main/java/net/shibboleth/idp/authn/AuthnEventIds.java
@@ -16,6 +16,8 @@ package net.shibboleth.idp.authn;
import javax.annotation.Nonnull;
+import net.shibboleth.idp.authn.context.AuthenticationContext;
+import net.shibboleth.idp.authn.context.SubjectCanonicalizationContext;
import net.shibboleth.shared.annotation.constraint.NotEmpty;
/**
@@ -26,7 +28,7 @@ import net.shibboleth.shared.annotation.constraint.NotEmpty;
public final class AuthnEventIds {
/**
- * ID of event returned if the {@link net.shibboleth.idp.authn.context.AuthenticationContext} is missing or invalid.
+ * ID of event returned if the {@link AuthenticationContext} is missing or invalid.
*/
@Nonnull @NotEmpty public static final String INVALID_AUTHN_CTX = "InvalidAuthenticationContext";
@@ -64,8 +66,7 @@ public final class AuthnEventIds {
@Nonnull @NotEmpty public static final String RESTART_AUTHN = "RestartAuthentication";
/**
- * ID of event returned if the {@link net.shibboleth.idp.authn.context.SubjectCanonicalizationContext}
- * is missing or invalid.
+ * ID of event returned if the {@link SubjectCanonicalizationContext} is missing or invalid.
*/
@Nonnull @NotEmpty public static final String INVALID_SUBJECT_C14N_CTX = "InvalidSubjectCanonicalizationContext";
@@ -75,6 +76,9 @@ public final class AuthnEventIds {
/** ID of event returned if an error occurs canonicalizing a Subject. */
@Nonnull @NotEmpty public static final String SUBJECT_C14N_ERROR = "SubjectCanonicalizationError";
+ /** ID of event returned to signal the completion of subject c14n. */
+ @Nonnull @NotEmpty public static final String SUBJECT_C14N_COMPLETED = "SubjectCanonicalizationCompleted";
+
/** ID of event returned if an authenticated subject doesn't match the identity in an existing session. */
@Nonnull @NotEmpty public static final String IDENTITY_SWITCH = "IdentitySwitch";
diff --git a/idp-authn-api/src/main/java/net/shibboleth/idp/authn/SubjectCanonicalizer.java b/idp-authn-api/src/main/java/net/shibboleth/idp/authn/SubjectCanonicalizer.java
index 6c218ac6c..7b0060ff0 100644
--- a/idp-authn-api/src/main/java/net/shibboleth/idp/authn/SubjectCanonicalizer.java
+++ b/idp-authn-api/src/main/java/net/shibboleth/idp/authn/SubjectCanonicalizer.java
@@ -31,7 +31,8 @@ import net.shibboleth.idp.authn.context.SubjectCanonicalizationContext;
* it for code modularity or reuse reasons.</p>
*
* <p>The output of this function is a SWF event string ({@link EventIds#PROCEED_EVENT_ID}
- * on success).</p>
+ * on success), an event string on failure, or null to indicate this implementaton
+ * is inapplicable to the input and so did not run.</p>
*
* @since 5.2.0
*/
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 aa2ac7ec4..cb80489ba 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
@@ -185,14 +185,18 @@ public class FinalizeAuthentication extends AbstractAuthenticationAction {
protected void doExecute(@Nonnull final ProfileRequestContext profileRequestContext,
@Nonnull final AuthenticationContext authenticationContext) {
- final String canonicalPrincipalName = this.canonicalPrincipalName;
- if (canonicalPrincipalName != null) {
- if (authenticationContext.getRequiredName() != null &&
- !canonicalPrincipalName.equals(authenticationContext.getRequiredName())) {
- log.warn("{} Result of authentication ({}) does not match existing subject in context ({})",
- getLogPrefix(), canonicalPrincipalName, authenticationContext.getRequiredName());
- ActionSupport.buildEvent(profileRequestContext, AuthnEventIds.INVALID_SUBJECT);
- return;
+ final String localCanonicalPrincipalName = canonicalPrincipalName;
+ if (localCanonicalPrincipalName != null) {
+ if (authenticationContext.getRequiredName() != null) {
+ if (localCanonicalPrincipalName.equals(authenticationContext.getRequiredName())) {
+ log.debug("{} Result of authentication ({}) matched existing subject in context", getLogPrefix(),
+ canonicalPrincipalName);
+ } else {
+ log.warn("{} Result of authentication ({}) does not match existing subject in context ({})",
+ getLogPrefix(), localCanonicalPrincipalName, authenticationContext.getRequiredName());
+ ActionSupport.buildEvent(profileRequestContext, AuthnEventIds.INVALID_SUBJECT);
+ return;
+ }
}
final SubjectContext sc = profileRequestContext.ensureSubcontext(SubjectContext.class);
diff --git a/idp-authn-impl/src/main/java/net/shibboleth/idp/authn/impl/SelectSubjectCanonicalizationFlow.java b/idp-authn-impl/src/main/java/net/shibboleth/idp/authn/impl/SelectSubjectCanonicalizationFlow.java
index c8c2b054e..f73c824b3 100644
--- a/idp-authn-impl/src/main/java/net/shibboleth/idp/authn/impl/SelectSubjectCanonicalizationFlow.java
+++ b/idp-authn-impl/src/main/java/net/shibboleth/idp/authn/impl/SelectSubjectCanonicalizationFlow.java
@@ -69,8 +69,6 @@ public class SelectSubjectCanonicalizationFlow extends AbstractSubjectCanonicali
// This will prevent re-selecting the same (probably failed) flow again.
final SubjectCanonicalizationFlowDescriptor flow = c14nContext.getAttemptedFlow();
if (flow != null) {
- log.info("{} Moving incomplete c14n flow descriptor {} to intermediate set, reselecting different one",
- getLogPrefix(), flow.getId());
c14nContext.getIntermediateFlows().put(flow.ensureId(), c14nContext.getAttemptedFlow());
}
@@ -93,12 +91,17 @@ public class SelectSubjectCanonicalizationFlow extends AbstractSubjectCanonicali
if (inline != null) {
log.debug("{} Selecting c14n descriptor {} (Inline implementation)", getLogPrefix(), flow.ensureId());
final String event = inline.apply(c14nContext);
- if (event == EventIds.PROCEED_EVENT_ID || event == AuthnEventIds.INVALID_SUBJECT) {
- ActionSupport.buildEvent(profileRequestContext, event);
- } else {
+ if (EventIds.PROCEED_EVENT_ID.equals(event)) {
+ // This event has to be remapped because of our poor choice of using an empty string to signal proceed.
+ log.debug("{} Inline c14n implementation {} completed successfully", getLogPrefix(), flow.ensureId());
+ ActionSupport.buildEvent(profileRequestContext, AuthnEventIds.SUBJECT_C14N_COMPLETED);
+ } else if (event != null) {
log.warn("{} Inline c14n implementation {} failed with event: {}", getLogPrefix(), flow.ensureId(),
event);
- // As with flow events, we remap anything else to a reselect signal to iterate the loop
+ // As with flow events, we echo anything else back for transition.
+ ActionSupport.buildEvent(profileRequestContext, event);
+ } else {
+ log.debug("{} Inline c14n implementation {} was not applicable", getLogPrefix(), flow.ensureId());
ActionSupport.buildEvent(profileRequestContext, AuthnEventIds.RESELECT_FLOW);
}
} else {
@@ -124,16 +127,13 @@ public class SelectSubjectCanonicalizationFlow extends AbstractSubjectCanonicali
for (final SubjectCanonicalizationFlowDescriptor flow : c14nContext.getPotentialFlows().values()) {
if (!c14nContext.getIntermediateFlows().containsKey(flow.ensureId())) {
- log.debug("{} Checking c14n flow descriptor {} for applicability...", getLogPrefix(),
- flow.getId());
c14nContext.setAttemptedFlow(flow);
if (flow.test(profileRequestContext)) {
+ c14nContext.setException(null);
return flow;
+ } else {
+ log.info("{} Flow descriptor {} was not active", getLogPrefix(), flow.getId());
}
- final Exception ctxException = c14nContext.getException();
- log.debug("{} C14N flow descriptor {} was not applicable: {}", getLogPrefix(), flow.ensureId(),
- ctxException!= null ? ctxException.getMessage() : "reason unknown");
- c14nContext.setException(null);
// Note that we don't exclude this flow from possible future selection, since one flow
// could in theory do partial work and change the context such that this flow then applies.
diff --git a/idp-authn-impl/src/main/java/net/shibboleth/idp/authn/impl/SimpleSubjectCanonicalization.java b/idp-authn-impl/src/main/java/net/shibboleth/idp/authn/impl/SimpleSubjectCanonicalization.java
index 9846c23ab..790531245 100644
--- a/idp-authn-impl/src/main/java/net/shibboleth/idp/authn/impl/SimpleSubjectCanonicalization.java
+++ b/idp-authn-impl/src/main/java/net/shibboleth/idp/authn/impl/SimpleSubjectCanonicalization.java
@@ -15,21 +15,19 @@
package net.shibboleth.idp.authn.impl;
import java.util.Set;
-import java.util.function.Predicate;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import javax.security.auth.Subject;
import org.opensaml.profile.action.EventIds;
-import org.opensaml.profile.context.ProfileRequestContext;
+import org.slf4j.Logger;
import net.shibboleth.idp.authn.AbstractSubjectCanonicalizer;
-import net.shibboleth.idp.authn.AuthnEventIds;
-import net.shibboleth.idp.authn.SubjectCanonicalizationException;
import net.shibboleth.idp.authn.SubjectCanonicalizer;
import net.shibboleth.idp.authn.context.SubjectCanonicalizationContext;
import net.shibboleth.idp.authn.principal.UsernamePrincipal;
+import net.shibboleth.shared.primitive.LoggerFactory;
/**
* A {@link SubjectCanonicalizer} that transforms the input {@link javax.security.auth.Subject}
@@ -37,12 +35,15 @@ import net.shibboleth.idp.authn.principal.UsernamePrincipal;
*/
public class SimpleSubjectCanonicalization extends AbstractSubjectCanonicalizer {
+ /** Class logger. */
+ @Nonnull private final Logger log = LoggerFactory.getLogger(SimpleSubjectCanonicalization.class);
+
/** {@inheritDoc} */
- @Nonnull public String doApply(@Nonnull final SubjectCanonicalizationContext c14nContext) {
+ @Nullable public String doApply(@Nonnull final SubjectCanonicalizationContext c14nContext) {
final UsernamePrincipal usernamePrincipal = getUsernamePrincipal(c14nContext);
if (usernamePrincipal == null) {
- return AuthnEventIds.INVALID_SUBJECT;
+ return null;
}
c14nContext.setPrincipalName(applyTransforms(usernamePrincipal.getName()));
@@ -57,17 +58,16 @@ public class SimpleSubjectCanonicalization extends AbstractSubjectCanonicalizer
*
* @return the only matching principal or null
*/
- @Nullable private static UsernamePrincipal getUsernamePrincipal(
+ @Nullable private UsernamePrincipal getUsernamePrincipal(
@Nonnull final SubjectCanonicalizationContext c14nContext) {
final Subject subject = c14nContext.getSubject();
if (subject != null) {
final Set<UsernamePrincipal> prins = subject.getPrincipals(UsernamePrincipal.class);
if (prins == null || prins.isEmpty()) {
- c14nContext.setException(new SubjectCanonicalizationException("No UsernamePrincipals were found"));
+ log.debug("{} No UsernamePrincipals were found", getLogPrefix());
} else if (prins.size() > 1) {
- c14nContext.setException(
- new SubjectCanonicalizationException("Multiple UsernamePrincipals were found"));
+ log.debug("{} Multiple UsernamePrincipals were found", getLogPrefix());
} else {
return prins.iterator().next();
}
@@ -75,23 +75,5 @@ public class SimpleSubjectCanonicalization extends AbstractSubjectCanonicalizer
return null;
}
-
- /** A predicate that determines if this action can run or not. */
- public static class ActivationCondition implements Predicate<ProfileRequestContext> {
-
- /** {@inheritDoc} */
- public boolean test(@Nullable final ProfileRequestContext input) {
-
- if (input != null) {
- final SubjectCanonicalizationContext c14nContext =
- input.getSubcontext(SubjectCanonicalizationContext.class);
- if (c14nContext != null) {
- return getUsernamePrincipal(c14nContext) != null;
- }
- }
-
- return false;
- }
- }
}
\ No newline at end of file
diff --git a/idp-authn-impl/src/main/java/net/shibboleth/idp/authn/impl/X500SubjectCanonicalization.java b/idp-authn-impl/src/main/java/net/shibboleth/idp/authn/impl/X500SubjectCanonicalization.java
index e3b0dbe5a..2e59477d3 100644
--- a/idp-authn-impl/src/main/java/net/shibboleth/idp/authn/impl/X500SubjectCanonicalization.java
+++ b/idp-authn-impl/src/main/java/net/shibboleth/idp/authn/impl/X500SubjectCanonicalization.java
@@ -17,7 +17,6 @@ package net.shibboleth.idp.authn.impl;
import java.security.cert.X509Certificate;
import java.util.List;
import java.util.Set;
-import java.util.function.Predicate;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
@@ -29,13 +28,11 @@ import org.cryptacular.x509.dn.NameReader;
import org.cryptacular.x509.dn.RDN;
import org.cryptacular.x509.dn.RDNSequence;
import org.opensaml.profile.action.EventIds;
-import org.opensaml.profile.context.ProfileRequestContext;
import org.opensaml.security.x509.X509Support;
import org.slf4j.Logger;
import net.shibboleth.idp.authn.AbstractSubjectCanonicalizer;
import net.shibboleth.idp.authn.AuthnEventIds;
-import net.shibboleth.idp.authn.SubjectCanonicalizationException;
import net.shibboleth.idp.authn.SubjectCanonicalizer;
import net.shibboleth.idp.authn.context.SubjectCanonicalizationContext;
import net.shibboleth.shared.annotation.constraint.NotEmpty;
@@ -56,7 +53,7 @@ import net.shibboleth.shared.primitive.StringSupport;
* over the subject, if a match is found.</p>
*/
public class X500SubjectCanonicalization extends AbstractSubjectCanonicalizer {
-
+
/** Common Name (CN) OID. */
@Nonnull @NotEmpty private static final String CN_OID = "2.5.4.3";
@@ -101,8 +98,7 @@ public class X500SubjectCanonicalization extends AbstractSubjectCanonicalizer {
/** {@inheritDoc} */
@Override
- @Nonnull protected String doApply(@Nonnull final SubjectCanonicalizationContext c14nContext) {
-
+ @Nullable protected String doApply(@Nonnull final SubjectCanonicalizationContext c14nContext) {
final X500Principal x500Principal;
final X509Certificate certificate = getCertificate(c14nContext);
@@ -113,9 +109,8 @@ public class X500SubjectCanonicalization extends AbstractSubjectCanonicalizer {
}
if (x500Principal == null) {
- c14nContext.setException(new SubjectCanonicalizationException(
- "Neither a single X509Certificate nor X500Principal were found"));
- return AuthnEventIds.INVALID_SUBJECT;
+ log.debug("{} Neither a single X509Certificate nor X500Principal were found", getLogPrefix());
+ return null;
}
@@ -186,7 +181,7 @@ public class X500SubjectCanonicalization extends AbstractSubjectCanonicalizer {
*
* @return the only matching principal or null
*/
- @Nullable private static X500Principal getX500Principal(@Nonnull final SubjectCanonicalizationContext c14nContext) {
+ @Nullable private X500Principal getX500Principal(@Nonnull final SubjectCanonicalizationContext c14nContext) {
final Subject subject = c14nContext.getSubject();
if (subject != null) {
@@ -206,7 +201,7 @@ public class X500SubjectCanonicalization extends AbstractSubjectCanonicalizer {
*
* @return the only certificate or null
*/
- @Nullable private static X509Certificate getCertificate(
+ @Nullable private X509Certificate getCertificate(
@Nonnull final SubjectCanonicalizationContext c14nContext) {
final Subject subject = c14nContext.getSubject();
@@ -220,27 +215,4 @@ public class X500SubjectCanonicalization extends AbstractSubjectCanonicalizer {
return null;
}
- /** A predicate that determines if this action can run or not. */
- public static class ActivationCondition implements Predicate<ProfileRequestContext> {
-
- /** {@inheritDoc} */
- public boolean test(@Nullable final ProfileRequestContext input) {
-
- if (input != null) {
- final SubjectCanonicalizationContext c14nContext =
- input.getSubcontext(SubjectCanonicalizationContext.class);
- if (c14nContext != null) {
- if (getCertificate(c14nContext) != null || getX500Principal(c14nContext) != null) {
- return true;
- }
-
- c14nContext.setException(new SubjectCanonicalizationException(
- "Neither a single X509Certificate nor X500Principal were found"));
- }
- }
-
- return false;
- }
- }
-
}
\ No newline at end of file
diff --git a/idp-authn-impl/src/test/java/net/shibboleth/idp/authn/impl/SimpleSubjectCanonicalizationTest.java b/idp-authn-impl/src/test/java/net/shibboleth/idp/authn/impl/SimpleSubjectCanonicalizationTest.java
index d5fbeb398..686331420 100644
--- a/idp-authn-impl/src/test/java/net/shibboleth/idp/authn/impl/SimpleSubjectCanonicalizationTest.java
+++ b/idp-authn-impl/src/test/java/net/shibboleth/idp/authn/impl/SimpleSubjectCanonicalizationTest.java
@@ -56,10 +56,8 @@ public class SimpleSubjectCanonicalizationTest extends BaseAuthenticationContext
final String event = action.apply(c14n);
- Assert.assertEquals(event, AuthnEventIds.INVALID_SUBJECT);
- final SubjectCanonicalizationContext scc = prc.getSubcontext(SubjectCanonicalizationContext.class);
- assert scc != null;
- Assert.assertNotNull(scc.getException());
+ Assert.assertNull(event);
+ Assert.assertNull(c14n.getPrincipalName());
}
@Test public void testMultiPrincipals() {
@@ -70,10 +68,8 @@ public class SimpleSubjectCanonicalizationTest extends BaseAuthenticationContext
final String event = action.apply(c14n);
- Assert.assertEquals(event, AuthnEventIds.INVALID_SUBJECT);
- final SubjectCanonicalizationContext scc = prc.getSubcontext(SubjectCanonicalizationContext.class);
- assert scc != null;
- Assert.assertNotNull(scc.getException());
+ Assert.assertNull(event);
+ Assert.assertNull(c14n.getPrincipalName());
}
@Test public void testSuccess() {
@@ -84,9 +80,7 @@ public class SimpleSubjectCanonicalizationTest extends BaseAuthenticationContext
final String event = action.apply(c14n);
Assert.assertEquals(event, EventIds.PROCEED_EVENT_ID);
- SubjectCanonicalizationContext sc = prc.getSubcontext(SubjectCanonicalizationContext.class);
- assert sc != null;
- Assert.assertEquals(sc.getPrincipalName(), "foo");
+ Assert.assertEquals(c14n.getPrincipalName(), "foo");
}
@Test public void testTransform() {
@@ -97,9 +91,7 @@ public class SimpleSubjectCanonicalizationTest extends BaseAuthenticationContext
final String event = action.apply(c14n);
Assert.assertEquals(event, EventIds.PROCEED_EVENT_ID);
- SubjectCanonicalizationContext sc = prc.getSubcontext(SubjectCanonicalizationContext.class);
- assert sc != null;
- Assert.assertEquals(sc.getPrincipalName(), "foo");
+ Assert.assertEquals(c14n.getPrincipalName(), "foo");
}
}
\ No newline at end of file
diff --git a/idp-authn-impl/src/test/java/net/shibboleth/idp/authn/impl/X500SubjectCanonicalizationTest.java b/idp-authn-impl/src/test/java/net/shibboleth/idp/authn/impl/X500SubjectCanonicalizationTest.java
index 3dbfc72a6..695400dac 100644
--- a/idp-authn-impl/src/test/java/net/shibboleth/idp/authn/impl/X500SubjectCanonicalizationTest.java
+++ b/idp-authn-impl/src/test/java/net/shibboleth/idp/authn/impl/X500SubjectCanonicalizationTest.java
@@ -47,7 +47,6 @@ public class X500SubjectCanonicalizationTest extends BaseAuthenticationContextTe
@Test public void testNoContext() {
final String event = action.apply(null);
-
Assert.assertEquals(event, AuthnEventIds.INVALID_SUBJECT_C14N_CTX);
}
@@ -57,10 +56,8 @@ public class X500SubjectCanonicalizationTest extends BaseAuthenticationContextTe
final String event = action.apply(ctx);
- Assert.assertEquals(event, AuthnEventIds.INVALID_SUBJECT);
- final SubjectCanonicalizationContext scc = prc.getSubcontext(SubjectCanonicalizationContext.class);
- assert scc != null;
- Assert.assertNotNull(scc.getException());
+ Assert.assertNull(event);
+ Assert.assertNull(ctx.getPrincipalName());
}
@Test public void testMultiPrincipals() {
@@ -70,11 +67,9 @@ public class X500SubjectCanonicalizationTest extends BaseAuthenticationContextTe
final var ctx = prc.ensureSubcontext(SubjectCanonicalizationContext.class).setSubject(subject);
final String event = action.apply(ctx);
-
- Assert.assertEquals(event, AuthnEventIds.INVALID_SUBJECT);
- final SubjectCanonicalizationContext scc = prc.getSubcontext(SubjectCanonicalizationContext.class);
- assert scc != null;
- Assert.assertNotNull(scc.getException());
+
+ Assert.assertNull(event);
+ Assert.assertNull(ctx.getPrincipalName());
}
@Test public void testNone() {
diff --git a/idp-conf-impl/src/main/resources/net/shibboleth/idp/conf/subject-c14n-system.xml b/idp-conf-impl/src/main/resources/net/shibboleth/idp/conf/subject-c14n-system.xml
index 635d9eae0..3266d9b96 100644
--- a/idp-conf-impl/src/main/resources/net/shibboleth/idp/conf/subject-c14n-system.xml
+++ b/idp-conf-impl/src/main/resources/net/shibboleth/idp/conf/subject-c14n-system.xml
@@ -34,25 +34,32 @@
<import resource="conditional:%{idp.home}/conf/c14n/simple-subject-c14n-config.xml" />
<import resource="conditional:%{idp.home}/conf/c14n/x500-subject-c14n-config.xml" />
+ <!-- Parent beans for defining flows of the three typical types. -->
+
<bean id="shibboleth.PostLoginSubjectCanonicalizationFlow" abstract="true"
class="net.shibboleth.idp.authn.SubjectCanonicalizationFlowDescriptor" />
+ <bean id="shibboleth.AbstractSAML1C14NFlowBean" abstract="true"
+ class="net.shibboleth.idp.saml.nameid.NameIDCanonicalizationFlowDescriptor" />
+
+ <bean id="shibboleth.AbstractSAML2C14NFlowBean" abstract="true"
+ class="net.shibboleth.idp.saml.nameid.NameIDCanonicalizationFlowDescriptor" />
+
+ <!-- Basic definitioms of post-login c14n flows with property and legacy bean config support. -->
+
<bean id="c14n/simple" parent="shibboleth.PostLoginSubjectCanonicalizationFlow">
<property name="implementation">
- <bean class="net.shibboleth.idp.authn.impl.SimpleSubjectCanonicalization"
+ <bean id="SimpleSubjectCanonicalization" class="net.shibboleth.idp.authn.impl.SimpleSubjectCanonicalization"
p:lowercase="#{getObject('shibboleth.c14n.simple.Lowercase') ?: %{idp.c14n.simple.lowercase:false}}"
p:uppercase="#{getObject('shibboleth.c14n.simple.Uppercase') ?: %{idp.c14n.simple.uppercase:false}}"
p:trim="#{getObject('shibboleth.c14n.simple.Trim') ?: %{idp.c14n.simple.trim:true}}"
p:transforms="#{getObject('shibboleth.c14n.simple.Transforms')}" />
</property>
- <property name="activationCondition">
- <bean class="net.shibboleth.idp.authn.impl.SimpleSubjectCanonicalization.ActivationCondition" />
- </property>
</bean>
<bean id="c14n/x500" parent="shibboleth.PostLoginSubjectCanonicalizationFlow">
<property name="implementation">
- <bean class="net.shibboleth.idp.authn.impl.X500SubjectCanonicalization"
+ <bean id="X500SubjectCanonicalization" class="net.shibboleth.idp.authn.impl.X500SubjectCanonicalization"
p:subjectAltNameTypes-ref="shibboleth.c14n.x500.SubjectAltNameTypes"
p:objectIds-ref="shibboleth.c14n.x500.ObjectIDs"
p:lowercase="#{getObject('shibboleth.c14n.x500.Lowercase') ?: %{idp.c14n.x500.lowercase:false}}"
@@ -60,80 +67,114 @@
p:trim="#{getObject('shibboleth.c14n.x500.Trim') ?: %{idp.c14n.x500.trim:true}}"
p:transforms="#{getObject('shibboleth.c14n.x500.Transforms')}" />
</property>
- <property name="activationCondition">
- <bean class="net.shibboleth.idp.authn.impl.X500SubjectCanonicalization.ActivationCondition" />
- </property>
</bean>
- <bean id="shibboleth.AbstractSAML1C14NFlowBean" abstract="true"
- class="net.shibboleth.idp.saml.nameid.NameIDCanonicalizationFlowDescriptor">
- <property name="activationCondition">
- <bean class="net.shibboleth.idp.saml.nameid.impl.NameIdentifierCanonicalization.ActivationCondition" />
+ <!-- The rest are machinery for handling NameIDs, mostly in protocol requests, also for proxying. -->
+
+ <bean id="c14n/SAML2Persistent" parent="shibboleth.AbstractSAML2C14NFlowBean"
+ p:formats="#{ {'urn:oasis:names:tc:SAML:2.0:nameid-format:persistent'} }">
+ <property name="implementation">
+ <bean id="NameIDCanonicalization/SAML2Persistent" class="net.shibboleth.idp.saml.nameid.impl.NameIDCanonicalization">
+ <property name="decoder">
+ <bean class="net.shibboleth.idp.saml.nameid.impl.StoredPersistentIdDecoder"
+ p:persistentIdStore="#{getObject('%{idp.persistentId.store:undefined}'.trim())}"
+ p:dataSource="#{getObject('%{idp.persistentId.dataSource:undefined}'.trim())}" />
+ </property>
+ </bean>
</property>
</bean>
- <bean id="shibboleth.AbstractSAML2C14NFlowBean" abstract="true"
- class="net.shibboleth.idp.saml.nameid.NameIDCanonicalizationFlowDescriptor">
- <property name="activationCondition">
- <bean class="net.shibboleth.idp.saml.nameid.impl.NameIDCanonicalization.ActivationCondition" />
+ <bean id="c14n/SAML2Transient" parent="shibboleth.AbstractSAML2C14NFlowBean"
+ p:formats="#{ {'urn:oasis:names:tc:SAML:2.0:nameid-format:transient'} }">
+ <property name="implementation">
+ <bean id="NameIDCanonicalization/SAML2Transient" class="net.shibboleth.idp.saml.nameid.impl.NameIDCanonicalization">
+ <property name="decoder">
+ <bean class="net.shibboleth.idp.saml.nameid.impl.TransientNameIDDecoder"
+ p:idStore-ref="shibboleth.StorageService" />
+ </property>
+ </bean>
</property>
</bean>
-
- <bean id="c14n/SAML2Persistent" parent="shibboleth.AbstractSAML2C14NFlowBean"
- p:formats="#{ {'urn:oasis:names:tc:SAML:2.0:nameid-format:persistent'} }" />
-
- <bean id="c14n/SAML2Transient" parent="shibboleth.AbstractSAML2C14NFlowBean"
- p:formats="#{ {'urn:oasis:names:tc:SAML:2.0:nameid-format:transient'} }" />
<bean id="c14n/SAML2CryptoTransient" parent="shibboleth.AbstractSAML2C14NFlowBean"
- p:formats="#{ {'urn:oasis:names:tc:SAML:2.0:nameid-format:transient'} }" />
+ p:formats="#{ {'urn:oasis:names:tc:SAML:2.0:nameid-format:transient'} }">
+ <property name="implementation">
+ <bean id="NameIDCanonicalization/SAML2CryptoTransient" class="net.shibboleth.idp.saml.nameid.impl.NameIDCanonicalization">
+ <property name="decoder">
+ <bean class="net.shibboleth.idp.saml.nameid.impl.CryptoTransientNameIDDecoder"
+ p:dataSealer="#{(environment.containsProperty('idp.sealer.storeResource') or environment.containsProperty('idp.sealer.keyStrategy')) ? getObject('shibboleth.DataSealer') : null}" />
+ </property>
+ </bean>
+ </property>
+ </bean>
<bean id="c14n/SAML1Transient" parent="shibboleth.AbstractSAML1C14NFlowBean"
- p:formats="#{ {'urn:mace:shibboleth:1.0:nameIdentifier'} }" />
+ p:formats="#{ {'urn:mace:shibboleth:1.0:nameIdentifier'} }">
+ <property name="implementation">
+ <bean id="NameIdentifierCanonicalization/SAML1Transient" class="net.shibboleth.idp.saml.nameid.impl.NameIdentifierCanonicalization">
+ <property name="decoder">
+ <bean class="net.shibboleth.idp.saml.nameid.impl.TransientNameIdentifierDecoder"
+ p:idStore-ref="shibboleth.StorageService" />
+ </property>
+ </bean>
+ </property>
+ </bean>
+
+ <bean id="c14n/SAML1CryptoTransient" parent="shibboleth.AbstractSAML1C14NFlowBean"
+ p:formats="#{ {'urn:mace:shibboleth:1.0:nameIdentifier'} }">
+ <property name="implementation">
+ <bean id="NameIdentifierCanonicalization/SAML1CryptoTransient" class="net.shibboleth.idp.saml.nameid.impl.NameIdentifierCanonicalization">
+ <property name="decoder">
+ <bean class="net.shibboleth.idp.saml.nameid.impl.CryptoTransientNameIdentifierDecoder"
+ p:dataSealer="#{(environment.containsProperty('idp.sealer.storeResource') or environment.containsProperty('idp.sealer.keyStrategy')) ? getObject('shibboleth.DataSealer') : null}" />
+ </property>
+ </bean>
+ </property>
+ </bean>
- <bean id="c14n/SAML1CryptoTransient" parent="shibboleth.AbstractSAML1C14NFlowBean"
- p:formats="#{ {'urn:mace:shibboleth:1.0:nameIdentifier'} }" />
+ <bean id="TransformingNameIDDecoder" lazy-init="true"
+ class="net.shibboleth.idp.saml.nameid.impl.TransformingNameIDDecoder"
+ p:lowercase="%{idp.c14n.saml.lowercase:false}"
+ p:uppercase="%{idp.c14n.saml.uppercase:false}"
+ p:transforms-ref="shibboleth.NameTransforms" />
<bean id="c14n/SAML2Transform" parent="shibboleth.AbstractSAML2C14NFlowBean"
+ p:activationCondition-ref="shibboleth.NameTransformPredicate"
p:formats-ref="shibboleth.NameTransformFormats">
- <property name="activationCondition">
- <bean parent="shibboleth.Conditions.AND">
- <constructor-arg>
- <list>
- <bean class="net.shibboleth.idp.saml.nameid.impl.NameIDCanonicalization.ActivationCondition" />
- <ref bean="shibboleth.NameTransformPredicate" />
- </list>
- </constructor-arg>
- </bean>
+ <property name="implementation">
+ <bean id="NameIDCanonicalization/SAML2Transform" class="net.shibboleth.idp.saml.nameid.impl.NameIDCanonicalization"
+ p:decoder="#{getObject('shibboleth.SAML2Transform.NameIDDecoder') ?: getObject('TransformingNameIDDecoder')}" />
</property>
</bean>
+ <bean id="ProxyTransformingNameIDDecoder" lazy-init="true"
+ class="net.shibboleth.idp.saml.nameid.impl.TransformingNameIDDecoder"
+ p:lowercase="%{idp.c14n.saml.proxy.lowercase:false}"
+ p:uppercase="%{idp.c14n.saml.proxy.uppercase:false}"
+ p:transforms-ref="shibboleth.ProxyNameTransforms" />
+
<bean id="c14n/SAML2ProxyTransform" parent="shibboleth.AbstractSAML2C14NFlowBean"
+ p:activationCondition-ref="shibboleth.ProxyNameTransformPredicate"
p:formats-ref="shibboleth.ProxyNameTransformFormats">
- <property name="activationCondition">
- <bean parent="shibboleth.Conditions.AND">
- <constructor-arg>
- <list>
- <bean class="net.shibboleth.idp.saml.nameid.impl.NameIDCanonicalization.ActivationCondition" />
- <ref bean="shibboleth.ProxyNameTransformPredicate" />
- </list>
- </constructor-arg>
- </bean>
+ <property name="implementation">
+ <bean id="NameIDCanonicalization/SAML2ProxyTransform" class="net.shibboleth.idp.saml.nameid.impl.NameIDCanonicalization"
+ p:decoder="#{getObject('shibboleth.SAML2ProxyTransform.NameIDDecoder') ?: getObject('ProxyTransformingNameIDDecoder')}" />
</property>
</bean>
+ <bean id="TransformingNameIdentifierDecoder" lazy-init="true"
+ class="net.shibboleth.idp.saml.nameid.impl.TransformingNameIdentifierDecoder"
+ p:lowercase="%{idp.c14n.saml.lowercase:false}"
+ p:uppercase="%{idp.c14n.saml.uppercase:false}"
+ p:transforms-ref="shibboleth.NameTransforms" />
+
<bean id="c14n/SAML1Transform" parent="shibboleth.AbstractSAML1C14NFlowBean"
- p:formats-ref="shibboleth.NameTransformFormats">
- <property name="activationCondition">
- <bean parent="shibboleth.Conditions.AND">
- <constructor-arg>
- <list>
- <bean class="net.shibboleth.idp.saml.nameid.impl.NameIdentifierCanonicalization.ActivationCondition" />
- <ref bean="shibboleth.NameTransformPredicate" />
- </list>
- </constructor-arg>
- </bean>
+ p:activationCondition-ref="shibboleth.NameTransformPredicate"
+ p:formats-ref="shibboleth.NameTransformFormats">
+ <property name="implementation">
+ <bean id="NameIdentifierCanonicalization/SAML1Transform" class="net.shibboleth.idp.saml.nameid.impl.NameIdentifierCanonicalization"
+ p:decoder="#{getObject('shibboleth.SAML1Transform.NameIdentifierDecoder') ?: getObject('TransformingNameIdentifierDecoder')}" />
</property>
</bean>
-
+
</beans>
diff --git a/idp-conf-impl/src/main/resources/net/shibboleth/idp/conf/webflow-config.xml b/idp-conf-impl/src/main/resources/net/shibboleth/idp/conf/webflow-config.xml
index 8f0935180..421246a1c 100644
--- a/idp-conf-impl/src/main/resources/net/shibboleth/idp/conf/webflow-config.xml
+++ b/idp-conf-impl/src/main/resources/net/shibboleth/idp/conf/webflow-config.xml
@@ -101,20 +101,6 @@
<!-- Standard post-login C14N methods. -->
<entry key="c14n/attribute" value="classpath:/net/shibboleth/idp/flows/c14n/attribute-sourced-subject-c14n-flow.xml" />
- <!--
- Standard SAML C14N methods, including one supporting legacy use of the attribute resolver.
- These all map to the same flow, and they derive the bean ID of an action to run based on the
- flow id after the slash.
- -->
- <entry key="c14n/SAML2Transient" value="classpath:/net/shibboleth/idp/flows/c14n/subject-c14n-saml-default-flow.xml" />
- <entry key="c14n/SAML2CryptoTransient" value="classpath:/net/shibboleth/idp/flows/c14n/subject-c14n-saml-default-flow.xml" />
- <entry key="c14n/SAML2Persistent" value="classpath:/net/shibboleth/idp/flows/c14n/subject-c14n-saml-default-flow.xml" />
- <entry key="c14n/SAML2Transform" value="classpath:/net/shibboleth/idp/flows/c14n/subject-c14n-saml-default-flow.xml" />
- <entry key="c14n/SAML2ProxyTransform" value="classpath:/net/shibboleth/idp/flows/c14n/subject-c14n-saml-default-flow.xml" />
- <entry key="c14n/SAML1Transient" value="classpath:/net/shibboleth/idp/flows/c14n/subject-c14n-saml-default-flow.xml" />
- <entry key="c14n/SAML1CryptoTransient" value="classpath:/net/shibboleth/idp/flows/c14n/subject-c14n-saml-default-flow.xml" />
- <entry key="c14n/SAML1Transform" value="classpath:/net/shibboleth/idp/flows/c14n/subject-c14n-saml-default-flow.xml" />
-
<!-- Main interceptor flow. -->
<entry key="intercept.events" value="%{idp.home}/conf/intercept/intercept-events-flow.xml" />
<entry key="intercept.abstract" value="classpath:/net/shibboleth/idp/flows/intercept/intercept-abstract-flow.xml" />
diff --git a/idp-conf-impl/src/main/resources/net/shibboleth/idp/flows/c14n/subject-c14n-flow.xml b/idp-conf-impl/src/main/resources/net/shibboleth/idp/flows/c14n/subject-c14n-flow.xml
index d7e0bb0ab..33925238b 100644
--- a/idp-conf-impl/src/main/resources/net/shibboleth/idp/flows/c14n/subject-c14n-flow.xml
+++ b/idp-conf-impl/src/main/resources/net/shibboleth/idp/flows/c14n/subject-c14n-flow.xml
@@ -16,15 +16,16 @@
<evaluate expression="SelectSubjectCanonicalizationFlow" />
<!-- Indicates an inline implementation succeeded. -->
- <transition on="proceed" to="proceed" />
+ <transition on="SubjectCanonicalizationCompleted" to="proceed" />
<!-- Call a subflow with the same ID as the event. -->
<transition on="#{currentEvent.id.startsWith('c14n/')}" to="CallSubjectCanonicalizationFlow" />
<!-- Remap the case of no flows to run into a more recognizeable fatal error. -->
<transition on="NoPotentialFlow" to="SubjectCanonicalizationError" />
-
+
<!-- Signals us to loop back for another flow. -->
+ <transition on="InvalidSubject" to="SelectSubjectCanonicalizationFlow" />
<transition on="ReselectFlow" to="SelectSubjectCanonicalizationFlow" />
</action-state>
diff --git a/idp-conf-impl/src/main/resources/net/shibboleth/idp/flows/c14n/subject-c14n-saml-default-beans.xml b/idp-conf-impl/src/main/resources/net/shibboleth/idp/flows/c14n/subject-c14n-saml-default-beans.xml
deleted file mode 100644
index df70b4c17..000000000
--- a/idp-conf-impl/src/main/resources/net/shibboleth/idp/flows/c14n/subject-c14n-saml-default-beans.xml
+++ /dev/null
@@ -1,83 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<beans xmlns="http://www.springframework.org/schema/beans"
- xmlns:context="http://www.springframework.org/schema/context"
- xmlns:util="http://www.springframework.org/schema/util" xmlns:p="http://www.springframework.org/schema/p"
- xmlns:c="http://www.springframework.org/schema/c" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
- xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
- http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd
- http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util.xsd"
-
- default-init-method="initialize" default-destroy-method="destroy">
-
- <bean id="Shibboleth.C14N.SAML2Transient"
- class="net.shibboleth.idp.saml.nameid.impl.NameIDCanonicalization" scope="prototype">
- <property name="decoder">
- <bean class="net.shibboleth.idp.saml.nameid.impl.TransientNameIDDecoder"
- p:idStore-ref="shibboleth.StorageService" />
- </property>
- </bean>
-
- <bean id="Shibboleth.C14N.SAML2CryptoTransient"
- class="net.shibboleth.idp.saml.nameid.impl.NameIDCanonicalization" scope="prototype">
- <property name="decoder">
- <bean class="net.shibboleth.idp.saml.nameid.impl.CryptoTransientNameIDDecoder"
- p:dataSealer-ref="shibboleth.DataSealer" />
- </property>
- </bean>
-
- <bean id="Shibboleth.C14N.SAML2Persistent"
- class="net.shibboleth.idp.saml.nameid.impl.NameIDCanonicalization" scope="prototype">
- <property name="decoder">
- <bean class="net.shibboleth.idp.saml.nameid.impl.StoredPersistentIdDecoder"
- p:persistentIdStore="#{getObject('%{idp.persistentId.store:undefined}'.trim())}"
- p:dataSource="#{getObject('%{idp.persistentId.dataSource:undefined}'.trim())}" />
- </property>
- </bean>
-
- <bean id="TransformingNameIDDecoder" lazy-init="true"
- class="net.shibboleth.idp.saml.nameid.impl.TransformingNameIDDecoder"
- p:lowercase="%{idp.c14n.saml.lowercase:false}"
- p:uppercase="%{idp.c14n.saml.uppercase:false}"
- p:transforms-ref="shibboleth.NameTransforms" />
-
- <bean id="Shibboleth.C14N.SAML2Transform"
- class="net.shibboleth.idp.saml.nameid.impl.NameIDCanonicalization" scope="prototype"
- p:decoder="#{getObject('shibboleth.SAML2Transform.NameIDDecoder') ?: getObject('TransformingNameIDDecoder')}" />
-
- <bean id="ProxyTransformingNameIDDecoder" lazy-init="true"
- class="net.shibboleth.idp.saml.nameid.impl.TransformingNameIDDecoder"
- p:lowercase="%{idp.c14n.saml.proxy.lowercase:false}"
- p:uppercase="%{idp.c14n.saml.proxy.uppercase:false}"
- p:transforms-ref="shibboleth.ProxyNameTransforms" />
-
- <bean id="Shibboleth.C14N.SAML2ProxyTransform"
- class="net.shibboleth.idp.saml.nameid.impl.NameIDCanonicalization" scope="prototype"
- p:decoder="#{getObject('shibboleth.SAML2ProxyTransform.NameIDDecoder') ?: getObject('ProxyTransformingNameIDDecoder')}" />
-
- <bean id="Shibboleth.C14N.SAML1Transient"
- class="net.shibboleth.idp.saml.nameid.impl.NameIdentifierCanonicalization" scope="prototype">
- <property name="decoder">
- <bean class="net.shibboleth.idp.saml.nameid.impl.TransientNameIdentifierDecoder"
- p:idStore-ref="shibboleth.StorageService" />
- </property>
- </bean>
-
- <bean id="Shibboleth.C14N.SAML1CryptoTransient"
- class="net.shibboleth.idp.saml.nameid.impl.NameIdentifierCanonicalization" scope="prototype">
- <property name="decoder">
- <bean class="net.shibboleth.idp.saml.nameid.impl.CryptoTransientNameIdentifierDecoder"
- p:dataSealer-ref="shibboleth.DataSealer" />
- </property>
- </bean>
-
- <bean id="TransformingNameIdentifierDecoder" lazy-init="true"
- class="net.shibboleth.idp.saml.nameid.impl.TransformingNameIdentifierDecoder"
- p:lowercase="%{idp.c14n.saml.lowercase:false}"
- p:uppercase="%{idp.c14n.saml.uppercase:false}"
- p:transforms-ref="shibboleth.NameTransforms" />
-
- <bean id="Shibboleth.C14N.SAML1Transform"
- class="net.shibboleth.idp.saml.nameid.impl.NameIdentifierCanonicalization" scope="prototype"
- p:decoder="#{getObject('shibboleth.SAML1Transform.NameIdentifierDecoder') ?: getObject('TransformingNameIdentifierDecoder')}" />
-
-</beans>
diff --git a/idp-conf-impl/src/main/resources/net/shibboleth/idp/flows/c14n/subject-c14n-saml-default-flow.xml b/idp-conf-impl/src/main/resources/net/shibboleth/idp/flows/c14n/subject-c14n-saml-default-flow.xml
deleted file mode 100644
index 09c05337a..000000000
--- a/idp-conf-impl/src/main/resources/net/shibboleth/idp/flows/c14n/subject-c14n-saml-default-flow.xml
+++ /dev/null
@@ -1,23 +0,0 @@
-<flow xmlns="http://www.springframework.org/schema/webflow"
- xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
- xsi:schemaLocation="http://www.springframework.org/schema/webflow http://www.springframework.org/schema/webflow/spring-webflow.xsd"
- parent="c14n.abstract">
-
- <!--
- This is a one-step subflow that uses the subflow ID to derive a bean name to invoke, the bean being
- an action that performs SAML subject canonicalization of some type. This is used to run the built-in
- canonicalization capabilities pre-defined in the software.
- -->
-
- <action-state id="DoCanonicalization">
- <on-entry>
- <set name="requestScope.beanId" value="'Shibboleth.C14N.' + flowRequestContext.getActiveFlow().getId().split('/')[1]" />
- </on-entry>
- <evaluate expression="flowRequestContext.getActiveFlow().getApplicationContext().getBean(beanId).execute(flowRequestContext)" />
-
- <transition on="success" to="proceed" />
- </action-state>
-
- <bean-import resource="subject-c14n-saml-default-beans.xml" />
-
-</flow>
diff --git a/idp-conf-impl/src/test/resources/test/override-beans.xml b/idp-conf-impl/src/test/resources/test/override-beans.xml
index 4c33373e9..1eeb1e09a 100644
--- a/idp-conf-impl/src/test/resources/test/override-beans.xml
+++ b/idp-conf-impl/src/test/resources/test/override-beans.xml
@@ -9,34 +9,15 @@
default-init-method="initialize" default-destroy-method="destroy">
- <!-- Override beans from system/conf/subject-c14n-system.xml. -->
+ <!-- Override beans from conf/subject-c14n.xml. -->
- <bean id="c14n/SAML2Transform" parent="shibboleth.AbstractSAML2C14NFlowBean"
- p:formats-ref="shibboleth.NameTransformFormats">
- <property name="activationCondition">
- <bean class="net.shibboleth.shared.logic.PredicateSupport" factory-method="and">
- <constructor-arg>
- <list>
- <bean class="net.shibboleth.idp.saml.nameid.impl.NameIDCanonicalization.ActivationCondition" />
- <bean parent="shibboleth.Conditions.RelyingPartyId" c:candidates="#{{'https://sp.example.org'}}" />
- </list>
- </constructor-arg>
- </bean>
- </property>
- </bean>
-
- <bean id="c14n/SAML1Transform" parent="shibboleth.AbstractSAML1C14NFlowBean"
- p:formats-ref="shibboleth.NameTransformFormats">
- <property name="activationCondition">
- <bean class="net.shibboleth.shared.logic.PredicateSupport" factory-method="and">
- <constructor-arg>
- <list>
- <bean class="net.shibboleth.idp.saml.nameid.impl.NameIdentifierCanonicalization.ActivationCondition" />
- <bean parent="shibboleth.Conditions.RelyingPartyId" c:candidates="#{{'https://sp.example.org'}}" />
- </list>
- </constructor-arg>
- </bean>
- </property>
+ <bean id="shibboleth.NameTransformPredicate" parent="shibboleth.Conditions.RelyingPartyId">
+ <constructor-arg name="candidates">
+ <list>
+ <value>https://sp.example.org</value>
+ </list>
+ </constructor-arg>
</bean>
+
</beans>
\ No newline at end of file
diff --git a/idp-saml-api/src/main/java/net/shibboleth/idp/saml/nameid/NameIDDecoder.java b/idp-saml-api/src/main/java/net/shibboleth/idp/saml/nameid/NameIDDecoder.java
index fb3c3fa07..6a06c036c 100644
--- a/idp-saml-api/src/main/java/net/shibboleth/idp/saml/nameid/NameIDDecoder.java
+++ b/idp-saml-api/src/main/java/net/shibboleth/idp/saml/nameid/NameIDDecoder.java
@@ -16,12 +16,14 @@ package net.shibboleth.idp.saml.nameid;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
+import javax.annotation.concurrent.ThreadSafe;
import net.shibboleth.idp.authn.context.SubjectCanonicalizationContext;
import org.opensaml.saml.saml2.core.NameID;
/** Interface for converting a {@link NameID} back into a principal name. */
+ at ThreadSafe
public interface NameIDDecoder {
/**
diff --git a/idp-saml-impl/src/main/java/net/shibboleth/idp/saml/nameid/impl/BaseCryptoTransientDecoder.java b/idp-saml-impl/src/main/java/net/shibboleth/idp/saml/nameid/impl/BaseCryptoTransientDecoder.java
index f6384da97..320346dd4 100644
--- a/idp-saml-impl/src/main/java/net/shibboleth/idp/saml/nameid/impl/BaseCryptoTransientDecoder.java
+++ b/idp-saml-impl/src/main/java/net/shibboleth/idp/saml/nameid/impl/BaseCryptoTransientDecoder.java
@@ -21,8 +21,6 @@ import org.slf4j.Logger;
import com.google.common.base.Strings;
-import net.shibboleth.idp.saml.nameid.NameDecoderException;
-import net.shibboleth.shared.annotation.constraint.NonnullAfterInit;
import net.shibboleth.shared.annotation.constraint.NotEmpty;
import net.shibboleth.shared.component.AbstractIdentifiableInitializableComponent;
import net.shibboleth.shared.component.ComponentInitializationException;
@@ -42,7 +40,7 @@ public abstract class BaseCryptoTransientDecoder extends AbstractIdentifiableIni
@Nonnull private final Logger log = LoggerFactory.getLogger(BaseCryptoTransientDecoder.class);
/** Object used to protect and encrypt the data. */
- @NonnullAfterInit private DataSealer dataSealer;
+ @Nullable private DataSealer dataSealer;
/** cache for the log prefix - to save multiple recalculations. */
@Nullable private String logPrefix;
@@ -52,7 +50,7 @@ public abstract class BaseCryptoTransientDecoder extends AbstractIdentifiableIni
*
* @return the Data Sealer we are using.
*/
- @NonnullAfterInit public DataSealer getDataSealer() {
+ @Nullable public DataSealer getDataSealer() {
return dataSealer;
}
@@ -61,11 +59,21 @@ public abstract class BaseCryptoTransientDecoder extends AbstractIdentifiableIni
*
* @param sealer the Data Sealer to use.
*/
- public void setDataSealer(@Nonnull final DataSealer sealer) {
+ public void setDataSealer(@Nullable final DataSealer sealer) {
checkSetterPreconditions();
dataSealer = Constraint.isNotNull(sealer, "DataSealer cannot be null");
}
+ /** {@inheritDoc} */
+ @Override
+ protected void doInitialize() throws ComponentInitializationException {
+ super.doInitialize();
+
+ if (null == dataSealer) {
+ log.debug("{} No DataSealer available, decoder will be non-functional", getLogPrefix());
+ }
+ }
+
/**
* Convert the transient Id into the principal.
*
@@ -73,20 +81,26 @@ public abstract class BaseCryptoTransientDecoder extends AbstractIdentifiableIni
* @param requesterId the requester ID
*
* @return the decoded entity.
- * @throws NameDecoderException if a decode error occurs.
*/
@Nullable @NotEmpty protected String decode(@Nonnull final String transientId,
- @Nonnull @NotEmpty final String requesterId) throws NameDecoderException {
+ @Nonnull @NotEmpty final String requesterId) {
checkComponentActive();
+ if (dataSealer == null) {
+ log.error("{} DataSealer is not configured", getLogPrefix());
+ return null;
+ }
+
final String decodedId;
try {
+ assert dataSealer != null;
decodedId = dataSealer.unwrap(transientId);
} catch (final DataExpiredException e) {
- throw new NameDecoderException(getLogPrefix() + " Principal identifier has expired");
+ log.info("{} Principal identifier has expired", getLogPrefix());
+ return null;
} catch (final DataSealerException e) {
- throw new NameDecoderException(getLogPrefix() + " Caught exception unwrapping sealed transient identifier",
- e);
+ log.info("{} Caught exception unwrapping sealed transient identifier", getLogPrefix(), e);
+ return null;
}
if (Strings.isNullOrEmpty(decodedId)) {
@@ -109,16 +123,6 @@ public abstract class BaseCryptoTransientDecoder extends AbstractIdentifiableIni
return parts[1];
}
- /** {@inheritDoc} */
- @Override
- protected void doInitialize() throws ComponentInitializationException {
- super.doInitialize();
-
- if (null == dataSealer) {
- throw new ComponentInitializationException(getLogPrefix() + " no data sealer set");
- }
- }
-
/**
* Return a prefix for logging messages for this component.
*
diff --git a/idp-saml-impl/src/main/java/net/shibboleth/idp/saml/nameid/impl/CryptoTransientNameIDDecoder.java b/idp-saml-impl/src/main/java/net/shibboleth/idp/saml/nameid/impl/CryptoTransientNameIDDecoder.java
index 38fe3975b..aa68942a4 100644
--- a/idp-saml-impl/src/main/java/net/shibboleth/idp/saml/nameid/impl/CryptoTransientNameIDDecoder.java
+++ b/idp-saml-impl/src/main/java/net/shibboleth/idp/saml/nameid/impl/CryptoTransientNameIDDecoder.java
@@ -18,7 +18,6 @@ import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import net.shibboleth.idp.authn.context.SubjectCanonicalizationContext;
-import net.shibboleth.idp.saml.nameid.NameDecoderException;
import net.shibboleth.idp.saml.nameid.NameIDDecoder;
import net.shibboleth.shared.annotation.constraint.NotEmpty;
@@ -35,7 +34,7 @@ public class CryptoTransientNameIDDecoder extends BaseCryptoTransientDecoder imp
/** {@inheritDoc} */
@Override
@Nullable @NotEmpty public String decode(@Nonnull final SubjectCanonicalizationContext c14nContext,
- @Nonnull final NameID nameID) throws NameDecoderException {
+ @Nonnull final NameID nameID) {
final String value = nameID.getValue();
final String requesterId = c14nContext.getRequesterId();
diff --git a/idp-saml-impl/src/main/java/net/shibboleth/idp/saml/nameid/impl/CryptoTransientNameIdentifierDecoder.java b/idp-saml-impl/src/main/java/net/shibboleth/idp/saml/nameid/impl/CryptoTransientNameIdentifierDecoder.java
index b95d3389a..097453ba1 100644
--- a/idp-saml-impl/src/main/java/net/shibboleth/idp/saml/nameid/impl/CryptoTransientNameIdentifierDecoder.java
+++ b/idp-saml-impl/src/main/java/net/shibboleth/idp/saml/nameid/impl/CryptoTransientNameIdentifierDecoder.java
@@ -18,7 +18,6 @@ import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import net.shibboleth.idp.authn.context.SubjectCanonicalizationContext;
-import net.shibboleth.idp.saml.nameid.NameDecoderException;
import net.shibboleth.idp.saml.nameid.NameIdentifierDecoder;
import net.shibboleth.shared.annotation.constraint.NotEmpty;
@@ -34,7 +33,7 @@ public class CryptoTransientNameIdentifierDecoder extends BaseCryptoTransientDec
/** {@inheritDoc} */
@Override
@Nullable @NotEmpty public String decode(@Nonnull final SubjectCanonicalizationContext c14nContext,
- @Nonnull final NameIdentifier nameIdentifier) throws NameDecoderException {
+ @Nonnull final NameIdentifier nameIdentifier){
final String val = nameIdentifier.getValue();
final String id = c14nContext.getRequesterId();
diff --git a/idp-saml-impl/src/main/java/net/shibboleth/idp/saml/nameid/impl/NameIDCanonicalization.java b/idp-saml-impl/src/main/java/net/shibboleth/idp/saml/nameid/impl/NameIDCanonicalization.java
index ce8e7ffef..4dadff45b 100644
--- a/idp-saml-impl/src/main/java/net/shibboleth/idp/saml/nameid/impl/NameIDCanonicalization.java
+++ b/idp-saml-impl/src/main/java/net/shibboleth/idp/saml/nameid/impl/NameIDCanonicalization.java
@@ -15,23 +15,21 @@
package net.shibboleth.idp.saml.nameid.impl;
import java.util.Set;
-import java.util.function.Predicate;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import javax.security.auth.Subject;
-import org.opensaml.profile.action.ActionSupport;
-import org.opensaml.profile.context.ProfileRequestContext;
+import org.opensaml.profile.action.EventIds;
import org.opensaml.saml.saml2.core.NameID;
import org.opensaml.saml.saml2.core.NameIDType;
import org.opensaml.saml.saml2.profile.SAML2ObjectSupport;
import org.slf4j.Logger;
-import net.shibboleth.idp.authn.AbstractSubjectCanonicalizationAction;
+import net.shibboleth.idp.authn.AbstractSubjectCanonicalizer;
import net.shibboleth.idp.authn.AuthnEventIds;
-import net.shibboleth.idp.authn.SubjectCanonicalizationException;
import net.shibboleth.idp.authn.SubjectCanonicalizationFlowDescriptor;
+import net.shibboleth.idp.authn.SubjectCanonicalizer;
import net.shibboleth.idp.authn.context.SubjectCanonicalizationContext;
import net.shibboleth.idp.saml.authn.principal.NameIDPrincipal;
import net.shibboleth.idp.saml.nameid.NameDecoderException;
@@ -43,35 +41,18 @@ import net.shibboleth.shared.logic.Constraint;
import net.shibboleth.shared.primitive.LoggerFactory;
/**
- * Action to perform subject canonicalization, transforming the input {@link javax.security.auth.Subject}
+ * A {@link SubjectCanonicalizer} that transforms the input {@link javax.security.auth.Subject}
* into a principal name by searching for one and only one {@link NameIDPrincipal} custom principal,
* using an injected {@link NameIDDecoder} to carry out the process.
- *
- * @event {@link org.opensaml.profile.action.EventIds#PROCEED_EVENT_ID}
- * @event {@link AuthnEventIds#INVALID_SUBJECT}
- * @pre <pre>
- * ProfileRequestContext.getSubcontext(SubjectCanonicalizationContext.class, false) != null
- * </pre>
- * @post <pre>
- * SubjectCanonicalizationContext.getPrincipalName() != null || SubjectCanonicalizationContext.getException() != null
- * </pre>
*/
-public class NameIDCanonicalization extends AbstractSubjectCanonicalizationAction {
-
- /** Supplies logic for pre-execute test. */
- @Nonnull private final ActivationCondition embeddedPredicate;
+public class NameIDCanonicalization extends AbstractSubjectCanonicalizer {
+
+ /** Class logger. */
+ @Nonnull private Logger log = LoggerFactory.getLogger(NameIDCanonicalization.class);
/** Supplies logic for decoding the {@link NameID} into a principal. */
@NonnullAfterInit private NameIDDecoder decoder;
- /**
- * Constructor.
- *
- */
- public NameIDCanonicalization() {
- embeddedPredicate = new ActivationCondition();
- }
-
/**
* Get the class responsible for decoding the {@link NameID#getValue()} into a principal.
*
@@ -86,7 +67,7 @@ public class NameIDCanonicalization extends AbstractSubjectCanonicalizationActio
*
* @param theDecoder the decoder
*/
- @NonnullAfterInit public void setDecoder(@Nonnull final NameIDDecoder theDecoder) {
+ public void setDecoder(@Nonnull final NameIDDecoder theDecoder) {
checkSetterPreconditions();
decoder = Constraint.isNotNull(theDecoder, "Name ID decoder cannot be null");
}
@@ -100,148 +81,103 @@ public class NameIDCanonicalization extends AbstractSubjectCanonicalizationActio
}
/** {@inheritDoc} */
- @Override protected boolean doPreExecute(@Nonnull final ProfileRequestContext profileRequestContext,
- @Nonnull final SubjectCanonicalizationContext c14nContext) {
+ @Override
+ @Nullable protected String doApply(@Nonnull final SubjectCanonicalizationContext c14nContext) {
- if (!embeddedPredicate.apply(profileRequestContext, c14nContext, true)) {
- return false;
+ final NameIDPrincipal prin = getNameIDPrincipal(c14nContext);
+ if (prin == null) {
+ return null;
}
- return super.doPreExecute(profileRequestContext, c14nContext);
- }
-
- /** {@inheritDoc} */
- @Override protected void doExecute(@Nonnull final ProfileRequestContext profileRequestContext,
- @Nonnull final SubjectCanonicalizationContext c14nContext) {
-
- final Subject subject = c14nContext.getSubject();
- assert subject != null;
- final Set<NameIDPrincipal> nameIDs = subject.getPrincipals(NameIDPrincipal.class);
- final NameID nameID = nameIDs.iterator().next().getNameID();
-
try {
- c14nContext.setPrincipalName(decoder.decode(c14nContext, nameID));
+ c14nContext.setPrincipalName(decoder.decode(c14nContext, prin.getNameID()));
if (c14nContext.getPrincipalName() == null) {
- ActionSupport.buildEvent(profileRequestContext, AuthnEventIds.INVALID_SUBJECT);
+ return AuthnEventIds.INVALID_SUBJECT;
}
+ return EventIds.PROCEED_EVENT_ID;
} catch (final NameDecoderException e) {
c14nContext.setException(e);
- ActionSupport.buildEvent(profileRequestContext, AuthnEventIds.SUBJECT_C14N_ERROR);
+ return AuthnEventIds.SUBJECT_C14N_ERROR;
+ }
+ }
+
+ /**
+ * Helper method that returns the first and only {@link NameIDPrincipal} provided it matches a valid Format,
+ * returning null otherwise.
+ *
+ * @param c14nContext input context
+ *
+ * @return the only matching principal or null
+ */
+ @Nullable private NameIDPrincipal getNameIDPrincipal(
+ @Nonnull final SubjectCanonicalizationContext c14nContext) {
+
+ if (c14nContext.getSubject() != null) {
+ final Subject subject = c14nContext.getSubject();
+ assert subject != null;
+ final Set<NameIDPrincipal> nameIDs = subject.getPrincipals(NameIDPrincipal.class);
+ if (nameIDs == null || nameIDs.isEmpty()) {
+ log.debug("{} No NameIDPrincipals were found", getLogPrefix());
+ return null;
+ } else if (nameIDs.size() > 1) {
+ log.debug("{} Multiple NameIDPrincipals were found", getLogPrefix());
+ return null;
+ }
+ final NameIDPrincipal prin = nameIDs.iterator().next();
+ String format = prin.getNameID().getFormat();
+ if (format == null) {
+ format = NameIDType.UNSPECIFIED;
+ }
+ if (formatMatches(c14nContext, format)) {
+ return prin;
+ } else {
+ log.debug("{} Format not supported", getLogPrefix());
+ }
}
+
+ return null;
}
- /** A predicate that determines if this action can run or not. */
- public static class ActivationCondition implements Predicate<ProfileRequestContext> {
- /** Class logger. */
- @Nonnull private Logger log = LoggerFactory.getLogger(ActivationCondition.class);
+ /**
+ * Check the format against the relevant flow descriptor's format list.
+ *
+ * @param c14nContext the current c14n context
+ * @param format the format to check
+ *
+ * @return true iff the format matches
+ */
+ private boolean formatMatches(@Nonnull final SubjectCanonicalizationContext c14nContext,
+ @Nonnull final String format) {
- /** {@inheritDoc} */
- public boolean test(@Nullable final ProfileRequestContext input) {
+ final SubjectCanonicalizationFlowDescriptor flowDescriptor = c14nContext.getAttemptedFlow();
- if (input != null) {
- final SubjectCanonicalizationContext c14nContext =
- input.getSubcontext(SubjectCanonicalizationContext.class);
- if (c14nContext != null) {
- return apply(input, c14nContext, false);
- }
- }
+ log.debug("{} Attempting to match format '{}'", getLogPrefix(), format);
+ if (null == flowDescriptor) {
+ log.error("{} Supplied Context has no active FlowDescriptor", getLogPrefix());
return false;
}
- /**
- * Check the format against the format list. If we are in the action then we log the error into the C14N context
- * and add the appropriate event to the profile request context.
- *
- * @param format the format to check
- * @param c14nContext the current c14n context
- *
- * @return true iff the format matches
- */
- protected boolean formatMatches(@Nonnull final String format,
- @Nonnull final SubjectCanonicalizationContext c14nContext) {
-
- final SubjectCanonicalizationFlowDescriptor flowDescriptor = c14nContext.getAttemptedFlow();
-
- log.debug("Attempting to match format '{}'", format);
-
- if (null == flowDescriptor) {
- log.error("Supplied Context has no active FlowDescriptor");
- return false;
- }
-
- if (!(flowDescriptor instanceof NameIDCanonicalizationFlowDescriptor)) {
- log.error("Flow Descriptor named {} is not appropriate for NameID canonicalization. Use class=\"{}\"",
- flowDescriptor.getId(), NameIDCanonicalizationFlowDescriptor.class.getCanonicalName());
- return false;
- }
-
- final NameIDCanonicalizationFlowDescriptor nameIDDescriptor =
- (NameIDCanonicalizationFlowDescriptor) flowDescriptor;
-
- for (final String testFormat : nameIDDescriptor.getFormats()) {
- if (SAML2ObjectSupport.areNameIDFormatsEquivalent(testFormat, format)) {
- log.debug("NameIDCanonicalizationFlowDescriptor {}: format matches {}",
- nameIDDescriptor.getId(), testFormat);
- return true;
- }
- }
-
- log.debug("NameIDCanonicalizationFlowDescriptor {}: no format matches", nameIDDescriptor.getId());
+ if (!(flowDescriptor instanceof NameIDCanonicalizationFlowDescriptor)) {
+ log.error("{} Flow Descriptor named {} is not appropriate for NameID canonicalization. Use class=\"{}\"",
+ getLogPrefix(), flowDescriptor.getId(),
+ NameIDCanonicalizationFlowDescriptor.class.getCanonicalName());
return false;
}
- /**
- * Helper method that runs either as part of the {@link Predicate} or directly from the
- * {@link NameIDCanonicalization#doPreExecute(ProfileRequestContext, SubjectCanonicalizationContext)} method
- * above.
- *
- * @param profileRequestContext the current profile request context
- * @param c14nContext the current c14n context
- * @param duringAction true iff the method is run from the action above
- *
- * @return true iff the action can operate successfully on the candidate contexts
- */
- public boolean apply(@Nonnull final ProfileRequestContext profileRequestContext,
- @Nonnull final SubjectCanonicalizationContext c14nContext, final boolean duringAction) {
-
- Set<NameIDPrincipal> nameIDs = null;
- if (c14nContext.getSubject() != null) {
- final Subject subject = c14nContext.getSubject();
- assert subject != null;
- nameIDs = subject.getPrincipals(NameIDPrincipal.class);
- }
+ final NameIDCanonicalizationFlowDescriptor nameIDDescriptor =
+ (NameIDCanonicalizationFlowDescriptor) flowDescriptor;
- if (nameIDs == null || nameIDs.isEmpty()) {
- c14nContext.setException(new SubjectCanonicalizationException("No NameIDPrincipals were found"));
- if (duringAction) {
- ActionSupport.buildEvent(profileRequestContext, AuthnEventIds.INVALID_SUBJECT);
- }
- return false;
- } else if (nameIDs.size() > 1) {
- c14nContext.setException(
- new SubjectCanonicalizationException("Multiple NameIDPrincipals were found"));
- if (duringAction) {
- ActionSupport.buildEvent(profileRequestContext, AuthnEventIds.INVALID_SUBJECT);
- }
- return false;
- }
-
- String format = nameIDs.iterator().next().getNameID().getFormat();
- if (format == null) {
- format = NameIDType.UNSPECIFIED;
- }
- if (!formatMatches(format, c14nContext)) {
- c14nContext.setException(new SubjectCanonicalizationException("Format not supported"));
- if (duringAction) {
- ActionSupport.buildEvent(profileRequestContext, AuthnEventIds.INVALID_SUBJECT);
- }
- return false;
+ for (final String testFormat : nameIDDescriptor.getFormats()) {
+ if (SAML2ObjectSupport.areNameIDFormatsEquivalent(testFormat, format)) {
+ log.debug("{} Format matches {}", getLogPrefix(), testFormat);
+ return true;
}
-
- return true;
}
+
+ log.debug("{} No format matches", getLogPrefix());
+ return false;
}
}
\ No newline at end of file
diff --git a/idp-saml-impl/src/main/java/net/shibboleth/idp/saml/nameid/impl/NameIdentifierCanonicalization.java b/idp-saml-impl/src/main/java/net/shibboleth/idp/saml/nameid/impl/NameIdentifierCanonicalization.java
index 2716d3b28..cb6bfd641 100644
--- a/idp-saml-impl/src/main/java/net/shibboleth/idp/saml/nameid/impl/NameIdentifierCanonicalization.java
+++ b/idp-saml-impl/src/main/java/net/shibboleth/idp/saml/nameid/impl/NameIdentifierCanonicalization.java
@@ -15,60 +15,43 @@
package net.shibboleth.idp.saml.nameid.impl;
import java.util.Set;
-import java.util.function.Predicate;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import javax.security.auth.Subject;
-import org.opensaml.profile.action.ActionSupport;
-import org.opensaml.profile.context.ProfileRequestContext;
+import org.opensaml.profile.action.EventIds;
import org.opensaml.saml.saml1.core.NameIdentifier;
import org.opensaml.saml.saml1.profile.SAML1ObjectSupport;
import org.slf4j.Logger;
-import net.shibboleth.idp.authn.AbstractSubjectCanonicalizationAction;
+import net.shibboleth.idp.authn.AbstractSubjectCanonicalizer;
import net.shibboleth.idp.authn.AuthnEventIds;
-import net.shibboleth.idp.authn.SubjectCanonicalizationException;
import net.shibboleth.idp.authn.SubjectCanonicalizationFlowDescriptor;
+import net.shibboleth.idp.authn.SubjectCanonicalizer;
import net.shibboleth.idp.authn.context.SubjectCanonicalizationContext;
import net.shibboleth.idp.saml.authn.principal.NameIdentifierPrincipal;
import net.shibboleth.idp.saml.nameid.NameDecoderException;
import net.shibboleth.idp.saml.nameid.NameIDCanonicalizationFlowDescriptor;
import net.shibboleth.idp.saml.nameid.NameIdentifierDecoder;
import net.shibboleth.shared.annotation.constraint.NonnullAfterInit;
-import net.shibboleth.shared.annotation.constraint.NotEmpty;
import net.shibboleth.shared.component.ComponentInitializationException;
import net.shibboleth.shared.logic.Constraint;
import net.shibboleth.shared.primitive.LoggerFactory;
/**
- * Action to perform subject canonicalization, transforming the input {@link javax.security.auth.Subject}
+ * A {@link SubjectCanonicalizer} that transforms the input {@link javax.security.auth.Subject}
* into a principal name by searching for one and only one {@link NameIdentifierPrincipal} custom principal,
* using an injected {@link NameIdentifierDecoder} to carry out the process.
- *
- * @event {@link org.opensaml.profile.action.EventIds#PROCEED_EVENT_ID}
- * @event {@link AuthnEventIds#INVALID_SUBJECT}
- * @pre <pre>
- * ProfileRequestContext.getSubcontext(SubjectCanonicalizationContext.class, false) != null
- * </pre>
- * @post <pre>
- * SubjectCanonicalizationContext.getPrincipalName() != null || SubjectCanonicalizationContext.getException() != null
- * </pre>
*/
-public class NameIdentifierCanonicalization extends AbstractSubjectCanonicalizationAction {
-
- /** Supplies logic for pre-execute test. */
- @Nonnull private final ActivationCondition embeddedPredicate;
+public class NameIdentifierCanonicalization extends AbstractSubjectCanonicalizer {
+
+ /** Class logger. */
+ @Nonnull private final Logger log = LoggerFactory.getLogger(NameIdentifierCanonicalization.class);
/** Supplies logic for decoding the {@link NameIdentifier} into a principal. */
@NonnullAfterInit private NameIdentifierDecoder decoder;
- /** Constructor. */
- public NameIdentifierCanonicalization() {
- embeddedPredicate = new ActivationCondition();
- }
-
/**
* Get the class responsible for decoding the {@link NameIdentifier} into a principal.
*
@@ -98,151 +81,102 @@ public class NameIdentifierCanonicalization extends AbstractSubjectCanonicalizat
}
/** {@inheritDoc} */
- @Override protected boolean doPreExecute(@Nonnull final ProfileRequestContext profileRequestContext,
- @Nonnull final SubjectCanonicalizationContext c14nContext) {
+ @Override
+ @Nullable protected String doApply(@Nonnull final SubjectCanonicalizationContext c14nContext) {
- if (!embeddedPredicate.apply(profileRequestContext, c14nContext, true)) {
- return false;
+ final NameIdentifierPrincipal prin = getNameIdentifierPrincipal(c14nContext);
+ if (prin == null) {
+ return null;
}
-
- return super.doPreExecute(profileRequestContext, c14nContext);
- }
-
- /** {@inheritDoc} */
- @Override protected void doExecute(@Nonnull final ProfileRequestContext profileRequestContext,
- @Nonnull final SubjectCanonicalizationContext c14nContext) {
-
- final Subject subject = c14nContext.getSubject();
- assert subject != null;
- final Set<NameIdentifierPrincipal> nameIdentifiers =
- subject.getPrincipals(NameIdentifierPrincipal.class);
- final NameIdentifier nameIdentifier = nameIdentifiers.iterator().next().getNameIdentifier();
-
+
try {
- c14nContext.setPrincipalName(decoder.decode(c14nContext, nameIdentifier));
+ c14nContext.setPrincipalName(decoder.decode(c14nContext, prin.getNameIdentifier()));
if (c14nContext.getPrincipalName() == null) {
- ActionSupport.buildEvent(profileRequestContext, AuthnEventIds.INVALID_SUBJECT);
+ return AuthnEventIds.INVALID_SUBJECT;
}
+ return EventIds.PROCEED_EVENT_ID;
} catch (final NameDecoderException e) {
c14nContext.setException(e);
- ActionSupport.buildEvent(profileRequestContext, AuthnEventIds.SUBJECT_C14N_ERROR);
+ return AuthnEventIds.SUBJECT_C14N_ERROR;
}
}
- /** A predicate that determines if this action can run or not. */
- public static class ActivationCondition implements Predicate<ProfileRequestContext> {
-
- /** Class logger. */
- @Nonnull private Logger log = LoggerFactory.getLogger(ActivationCondition.class);
-
- /** {@inheritDoc} */
- public boolean test(@Nullable final ProfileRequestContext input) {
-
- if (input != null) {
- final SubjectCanonicalizationContext c14nContext =
- input.getSubcontext(SubjectCanonicalizationContext.class);
- if (c14nContext != null) {
- return apply(input, c14nContext, false);
- }
+ /**
+ * Helper method that returns the first and only {@link NameIdentifierPrincipal} provided it matches a valid Format,
+ * returning null otherwise.
+ *
+ * @param c14nContext input context
+ *
+ * @return the only matching principal or null
+ */
+ @Nullable private NameIdentifierPrincipal getNameIdentifierPrincipal(
+ @Nonnull final SubjectCanonicalizationContext c14nContext) {
+
+ if (c14nContext.getSubject() != null) {
+ final Subject subject = c14nContext.getSubject();
+ assert subject != null;
+ final Set<NameIdentifierPrincipal> nameIDs = subject.getPrincipals(NameIdentifierPrincipal.class);
+ if (nameIDs == null || nameIDs.isEmpty()) {
+ log.debug("{} No NameIdentifierPrincipals were found", getLogPrefix());
+ return null;
+ } else if (nameIDs.size() > 1) {
+ log.debug("{} Multiple NameIdentifierPrincipals were found", getLogPrefix());
+ return null;
}
-
- return false;
- }
-
- /**
- * Check the format against the format list. If we are in the action then we log the error into the C14N context
- * and add the appropriate event to the profile request context.
- *
- * @param format the format to check
- * @param c14nContext the current c14n context
- *
- * @return true if the format matches
- */
- protected boolean formatMatches(@Nonnull @NotEmpty final String format,
- @Nonnull final SubjectCanonicalizationContext c14nContext) {
-
- final SubjectCanonicalizationFlowDescriptor flowDescriptor = c14nContext.getAttemptedFlow();
-
- log.debug("Attempting to match format '{}'", format);
-
- if (null == flowDescriptor) {
- log.error("Supplied Context has no active FlowDescriptor");
- return false;
+ final NameIdentifierPrincipal prin = nameIDs.iterator().next();
+ String format = prin.getNameIdentifier().getFormat();
+ if (format == null) {
+ format = NameIdentifier.UNSPECIFIED;
}
-
- if (!(flowDescriptor instanceof NameIDCanonicalizationFlowDescriptor)) {
- log.error("Flow Descriptor named {} is not appropriate for NameID canonicalization. Use class=\"{}\"",
- flowDescriptor.getId(), NameIDCanonicalizationFlowDescriptor.class.getCanonicalName());
- return false;
+ if (formatMatches(c14nContext, format)) {
+ return prin;
+ } else {
+ log.debug("{} Format not supported", getLogPrefix());
}
+ }
+
+ return null;
+ }
- final NameIDCanonicalizationFlowDescriptor nameIDDescriptor =
- (NameIDCanonicalizationFlowDescriptor) flowDescriptor;
+ /**
+ * Check the format against the relevant flow descriptor's format list.
+ *
+ * @param c14nContext the current c14n context
+ * @param format the format to check
+ *
+ * @return true iff the format matches
+ */
+ private boolean formatMatches(@Nonnull final SubjectCanonicalizationContext c14nContext,
+ @Nonnull final String format) {
- for (final String testFormat : nameIDDescriptor.getFormats()) {
- if (SAML1ObjectSupport.areNameIdentifierFormatsEquivalent(testFormat, format)) {
- log.debug("NameIDCanonicalizationFlowDescriptor {}: format matches {}",
- nameIDDescriptor.getId(), testFormat);
- return true;
- }
- }
+ final SubjectCanonicalizationFlowDescriptor flowDescriptor = c14nContext.getAttemptedFlow();
+
+ log.debug("{} Attempting to match format '{}'", getLogPrefix(), format);
- log.debug("NameIDCanonicalizationFlowDescriptor {}: no format matches", nameIDDescriptor.getId());
+ if (null == flowDescriptor) {
+ log.error("{} Supplied context has no active FlowDescriptor", getLogPrefix());
return false;
}
- /**
- * Helper method that runs either as part of the {@link Predicate} or directly from the
- * {@link NameIdentifierCanonicalization#doPreExecute(ProfileRequestContext, SubjectCanonicalizationContext)}
- * method above.
- *
- * @param profileRequestContext the current profile request context
- * @param c14nContext the current c14n context
- * @param duringAction true iff the method is run from the action above
- *
- * @return true iff the action can operate successfully on the candidate contexts
- */
- public boolean apply(@Nonnull final ProfileRequestContext profileRequestContext,
- @Nonnull final SubjectCanonicalizationContext c14nContext, final boolean duringAction) {
-
- Set<NameIdentifierPrincipal> nameIdentifiers = null;
- final Subject subject = c14nContext.getSubject();
-
- if (subject != null) {
- nameIdentifiers = subject.getPrincipals(NameIdentifierPrincipal.class);
- }
+ if (!(flowDescriptor instanceof NameIDCanonicalizationFlowDescriptor)) {
+ log.error("{} Flow Descriptor named {} is not appropriate for NameID canonicalization. Use class=\"{}\"",
+ getLogPrefix(), flowDescriptor.getId(),
+ NameIDCanonicalizationFlowDescriptor.class.getCanonicalName());
+ return false;
+ }
- if (nameIdentifiers == null || nameIdentifiers.isEmpty()) {
- c14nContext.setException(
- new SubjectCanonicalizationException("No NameIdentifierPrincipals were found"));
- if (duringAction) {
- ActionSupport.buildEvent(profileRequestContext, AuthnEventIds.INVALID_SUBJECT);
- }
- return false;
- } else if (nameIdentifiers.size() > 1) {
- c14nContext.setException(
- new SubjectCanonicalizationException("Multiple NameIdentifierPrincipals were found"));
- if (duringAction) {
- ActionSupport.buildEvent(profileRequestContext, AuthnEventIds.INVALID_SUBJECT);
- }
- return false;
- }
+ final NameIDCanonicalizationFlowDescriptor nameIDDescriptor =
+ (NameIDCanonicalizationFlowDescriptor) flowDescriptor;
- String format = nameIdentifiers.iterator().next().getNameIdentifier().getFormat();
- if (format == null) {
- format = NameIdentifier.UNSPECIFIED;
- }
-
- if (!formatMatches(format, c14nContext)) {
- c14nContext.setException(new SubjectCanonicalizationException("Format not supported"));
- if (duringAction) {
- ActionSupport.buildEvent(profileRequestContext, AuthnEventIds.INVALID_SUBJECT);
- }
- return false;
+ for (final String testFormat : nameIDDescriptor.getFormats()) {
+ if (SAML1ObjectSupport.areNameIdentifierFormatsEquivalent(testFormat, format)) {
+ log.debug("{} Format matches {}", getLogPrefix(), testFormat);
+ return true;
}
-
- return true;
}
+
+ log.debug("{} No format matches", getLogPrefix());
+ return false;
}
}
\ No newline at end of file
diff --git a/idp-saml-impl/src/main/java/net/shibboleth/idp/saml/nameid/impl/StoredPersistentIdDecoder.java b/idp-saml-impl/src/main/java/net/shibboleth/idp/saml/nameid/impl/StoredPersistentIdDecoder.java
index 897ed2e55..09c355708 100644
--- a/idp-saml-impl/src/main/java/net/shibboleth/idp/saml/nameid/impl/StoredPersistentIdDecoder.java
+++ b/idp-saml-impl/src/main/java/net/shibboleth/idp/saml/nameid/impl/StoredPersistentIdDecoder.java
@@ -29,14 +29,13 @@ import net.shibboleth.idp.attribute.impl.JDBCPairwiseIdStore;
import net.shibboleth.idp.authn.context.SubjectCanonicalizationContext;
import net.shibboleth.idp.saml.nameid.NameDecoderException;
import net.shibboleth.idp.saml.nameid.NameIDDecoder;
-import net.shibboleth.shared.annotation.constraint.NonnullAfterInit;
import net.shibboleth.shared.annotation.constraint.NotEmpty;
import net.shibboleth.shared.component.AbstractIdentifiableInitializableComponent;
import net.shibboleth.shared.component.ComponentInitializationException;
import net.shibboleth.shared.primitive.LoggerFactory;
/**
- * An abstract decoder which contains the logic to decode SAML persistent IDs that are managed with a
+ * A decoder which contains the logic to decode SAML persistent IDs that are managed with a
* {@link DurablePairwiseIdStore}.
*/
public class StoredPersistentIdDecoder extends AbstractIdentifiableInitializableComponent implements NameIDDecoder {
@@ -45,7 +44,7 @@ public class StoredPersistentIdDecoder extends AbstractIdentifiableInitializable
@Nonnull private final Logger log = LoggerFactory.getLogger(StoredPersistentIdDecoder.class);
/** Updated version of persistent identifier data store layer. */
- @NonnullAfterInit private DurablePairwiseIdStore pidStore;
+ @Nullable private DurablePairwiseIdStore pidStore;
/** A DataSource to auto-provision a {@link JDBCPairwiseIdStore} instance. */
@Nullable private DataSource dataSource;
@@ -88,7 +87,7 @@ public class StoredPersistentIdDecoder extends AbstractIdentifiableInitializable
}
if (null == pidStore) {
- throw new ComponentInitializationException("PairwiseIdStore cannot be null");
+ log.debug("PairwiseIdStore is null, decoder will be non-functional");
}
}
}
@@ -98,6 +97,10 @@ public class StoredPersistentIdDecoder extends AbstractIdentifiableInitializable
@Nonnull final NameID nameID) throws NameDecoderException {
checkComponentActive();
+ if (pidStore == null) {
+ throw new NameDecoderException("A PairwiseIdStore is not configured");
+ }
+
if (nameID.getValue() == null) {
throw new NameDecoderException("Persistent NameID was empty");
}
@@ -123,6 +126,8 @@ public class StoredPersistentIdDecoder extends AbstractIdentifiableInitializable
pid.setIssuerEntityID(issuerID);
pid.setRecipientEntityID(recipientID);
pid.setPairwiseId(nameID.getValue());
+ // Enforced above.
+ assert pidStore != null;
pid = pidStore.getByIssuedValue(pid);
if (pid == null || pid.getPrincipalName() == null) {
log.info("No entry found for persistent ID {}", nameID.getValue());
diff --git a/idp-saml-impl/src/test/java/net/shibboleth/idp/saml/nameid/impl/CryptoTransientNameIDDecoderTest.java b/idp-saml-impl/src/test/java/net/shibboleth/idp/saml/nameid/impl/CryptoTransientNameIDDecoderTest.java
index 3751b8174..17adf6c49 100644
--- a/idp-saml-impl/src/test/java/net/shibboleth/idp/saml/nameid/impl/CryptoTransientNameIDDecoderTest.java
+++ b/idp-saml-impl/src/test/java/net/shibboleth/idp/saml/nameid/impl/CryptoTransientNameIDDecoderTest.java
@@ -36,8 +36,8 @@ import net.shibboleth.shared.security.impl.BasicKeystoreKeyStrategy;
import net.shibboleth.shared.spring.resource.ResourceHelper;
import org.opensaml.core.testing.OpenSAMLInitBaseTestCase;
+import org.opensaml.profile.action.EventIds;
import org.opensaml.profile.context.ProfileRequestContext;
-import org.opensaml.profile.testing.ActionTestingSupport;
import org.opensaml.saml.saml2.core.NameID;
import org.springframework.core.io.ClassPathResource;
import org.springframework.core.io.Resource;
@@ -116,19 +116,19 @@ public class CryptoTransientNameIDDecoderTest extends OpenSAMLInitBaseTestCase {
Assert.assertEquals(decoder.decode(ct, RECIPIENT), PRINCIPAL);
}
- @Test(expectedExceptions = NameDecoderException.class)
+ @Test
public void timeout()
throws SubjectCanonicalizationException, DataSealerException, NameDecoderException {
final String ct = code(PRINCIPAL, RECIPIENT, Duration.ofMillis(-5));
- decoder.decode(ct, RECIPIENT);
+ Assert.assertNull(decoder.decode(ct, RECIPIENT));
}
- @Test(expectedExceptions = NameDecoderException.class)
+ @Test
public void baddata() throws DataSealerException, NameDecoderException {
final String ct = code(PRINCIPAL, ISSUER, RECIPIENT);
- decoder.decode(ct.toUpperCase(), RECIPIENT);
+ Assert.assertNull(decoder.decode(ct.toUpperCase(), RECIPIENT));
}
@Test public void baddata2() throws DataSealerException, NameDecoderException {
@@ -172,6 +172,7 @@ public class CryptoTransientNameIDDecoderTest extends OpenSAMLInitBaseTestCase {
desc.initialize();
final NameIDCanonicalization canon = new NameIDCanonicalization();
+ canon.setId("test");
canon.setDecoder(decoder);
canon.initialize();
@@ -186,12 +187,8 @@ public class CryptoTransientNameIDDecoderTest extends OpenSAMLInitBaseTestCase {
scc.setRequesterId(TestSources.SP_ENTITY_ID);
scc.setResponderId(TestSources.IDP_ENTITY_ID);
- canon.execute(prc);
-
- ActionTestingSupport.assertProceedEvent(prc);
-
+ Assert.assertEquals(EventIds.PROCEED_EVENT_ID, canon.apply(scc));
Assert.assertEquals(scc.getPrincipalName(), TestSources.PRINCIPAL_ID);
-
}
}
\ No newline at end of file
diff --git a/idp-saml-impl/src/test/java/net/shibboleth/idp/saml/nameid/impl/CryptoTransientNameIdentifierDecoderTest.java b/idp-saml-impl/src/test/java/net/shibboleth/idp/saml/nameid/impl/CryptoTransientNameIdentifierDecoderTest.java
index 428c84be2..adf5323e4 100644
--- a/idp-saml-impl/src/test/java/net/shibboleth/idp/saml/nameid/impl/CryptoTransientNameIdentifierDecoderTest.java
+++ b/idp-saml-impl/src/test/java/net/shibboleth/idp/saml/nameid/impl/CryptoTransientNameIdentifierDecoderTest.java
@@ -30,8 +30,8 @@ import net.shibboleth.shared.security.impl.BasicKeystoreKeyStrategy;
import net.shibboleth.shared.spring.resource.ResourceHelper;
import org.opensaml.core.testing.OpenSAMLInitBaseTestCase;
+import org.opensaml.profile.action.EventIds;
import org.opensaml.profile.context.ProfileRequestContext;
-import org.opensaml.profile.testing.ActionTestingSupport;
import org.opensaml.saml.saml1.core.NameIdentifier;
import org.springframework.core.io.ClassPathResource;
import org.springframework.core.io.Resource;
@@ -108,6 +108,7 @@ public class CryptoTransientNameIdentifierDecoderTest extends OpenSAMLInitBaseTe
desc.initialize();
final NameIdentifierCanonicalization canon = new NameIdentifierCanonicalization();
+ canon.setId("test");
assert decoder!=null;
canon.setDecoder(decoder);
canon.initialize();
@@ -123,10 +124,7 @@ public class CryptoTransientNameIdentifierDecoderTest extends OpenSAMLInitBaseTe
scc.setRequesterId(TestSources.SP_ENTITY_ID);
scc.setResponderId(TestSources.IDP_ENTITY_ID);
- canon.execute(prc);
-
- ActionTestingSupport.assertProceedEvent(prc);
-
+ Assert.assertEquals(canon.apply(scc), EventIds.PROCEED_EVENT_ID);
Assert.assertEquals(scc.getPrincipalName(), TestSources.PRINCIPAL_ID);
}
diff --git a/idp-saml-impl/src/test/java/net/shibboleth/idp/saml/nameid/impl/NameIDCanonicalizationTest.java b/idp-saml-impl/src/test/java/net/shibboleth/idp/saml/nameid/impl/NameIDCanonicalizationTest.java
index 032960aca..6d9097a02 100644
--- a/idp-saml-impl/src/test/java/net/shibboleth/idp/saml/nameid/impl/NameIDCanonicalizationTest.java
+++ b/idp-saml-impl/src/test/java/net/shibboleth/idp/saml/nameid/impl/NameIDCanonicalizationTest.java
@@ -17,6 +17,7 @@ package net.shibboleth.idp.saml.nameid.impl;
import java.util.Arrays;
import java.util.List;
+import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import javax.security.auth.Subject;
@@ -30,8 +31,8 @@ import net.shibboleth.idp.saml.nameid.NameIDDecoder;
import org.opensaml.core.testing.OpenSAMLInitBaseTestCase;
import org.opensaml.core.xml.config.XMLObjectProviderRegistrySupport;
+import org.opensaml.profile.action.EventIds;
import org.opensaml.profile.context.ProfileRequestContext;
-import org.opensaml.profile.testing.ActionTestingSupport;
import org.opensaml.saml.common.SAMLObjectBuilder;
import org.opensaml.saml.saml2.core.NameID;
import org.testng.Assert;
@@ -74,6 +75,7 @@ public class NameIDCanonicalizationTest extends OpenSAMLInitBaseTestCase {
flowDescriptor.initialize();
action = new NameIDCanonicalization();
+ action.setId("test");
action.setDecoder(new NameIDDecoder() {
public String decode(SubjectCanonicalizationContext scc, NameID nameID) throws NameDecoderException {
if (RESPONDER.equals(scc.getResponderId()) && REQUESTER.equals(scc.getRequesterId())) {
@@ -85,7 +87,8 @@ public class NameIDCanonicalizationTest extends OpenSAMLInitBaseTestCase {
action.initialize();
}
- private void setSubContext(@Nullable Subject subject, @Nullable String responder, @Nullable String requester) {
+ @Nonnull private SubjectCanonicalizationContext setSubContext(@Nullable Subject subject, @Nullable String responder,
+ @Nullable String requester) {
final SubjectCanonicalizationContext scc = prc.ensureSubcontext(SubjectCanonicalizationContext.class);
if (subject != null) {
scc.setSubject(subject);
@@ -96,7 +99,7 @@ public class NameIDCanonicalizationTest extends OpenSAMLInitBaseTestCase {
if (responder != null) {
scc.setResponderId(responder);
}
- scc.setAttemptedFlow(flowDescriptor);
+ return scc.setAttemptedFlow(flowDescriptor);
}
private NameID nameId(String value, String format, String nameQualifier, String nameSPQualifier) {
@@ -119,18 +122,18 @@ public class NameIDCanonicalizationTest extends OpenSAMLInitBaseTestCase {
}
@Test public void testNoContext() {
- action.execute(prc);
- ActionTestingSupport.assertEvent(prc, AuthnEventIds.INVALID_SUBJECT_C14N_CTX);
+ final String event = action.apply(null);
+ Assert.assertEquals(event, AuthnEventIds.INVALID_SUBJECT_C14N_CTX);
}
@Test public void testNoPrincipal() {
final Subject subject = new Subject();
- setSubContext(subject, null, null);
+ final var scc = setSubContext(subject, null, null);
- action.execute(prc);
- ActionTestingSupport.assertEvent(prc, AuthnEventIds.INVALID_SUBJECT);
- final SubjectCanonicalizationContext scc = prc.getSubcontext(SubjectCanonicalizationContext.class);
- assert scc!=null && scc.getException()!=null;
+ final String event = action.apply(scc);
+
+ Assert.assertNull(event);
+ Assert.assertNull(scc.getPrincipalName());
}
@Test public void testMultiPrincipals() {
@@ -138,73 +141,71 @@ public class NameIDCanonicalizationTest extends OpenSAMLInitBaseTestCase {
subject.getPrincipals().add(new NameIDPrincipal(nameId("value", NameID.KERBEROS)));
subject.getPrincipals().add(new NameIDPrincipal(nameId("value2", NameID.X509_SUBJECT)));
- setSubContext(subject, null, null);
+ final var scc = setSubContext(subject, null, null);
- action.execute(prc);
- ActionTestingSupport.assertEvent(prc, AuthnEventIds.INVALID_SUBJECT);
- final SubjectCanonicalizationContext scc = prc.getSubcontext(SubjectCanonicalizationContext.class);
- assert scc!=null && scc.getException()!=null;
+ final String event = action.apply(scc);
+
+ Assert.assertNull(event);
+ Assert.assertNull(scc.getPrincipalName());
}
@Test public void testWrongFormat() {
final Subject subject = new Subject();
subject.getPrincipals().add(new NameIDPrincipal(nameId("value", NameID.X509_SUBJECT)));
- setSubContext(subject, RESPONDER, REQUESTER);
+ final var scc = setSubContext(subject, RESPONDER, REQUESTER);
- action.execute(prc);
- ActionTestingSupport.assertEvent(prc, AuthnEventIds.INVALID_SUBJECT);
- final SubjectCanonicalizationContext scc = prc.getSubcontext(SubjectCanonicalizationContext.class);
- assert scc!=null && scc.getException()!=null;
+ final String event = action.apply(scc);
+
+ Assert.assertNull(event);
+ Assert.assertNull(scc.getPrincipalName());
}
@Test public void testWrongRequesterNameID() {
final Subject subject = new Subject();
subject.getPrincipals().add(new NameIDPrincipal(nameId("value", NameID.KERBEROS)));
- setSubContext(subject, RESPONDER, RESPONDER);
+ final var scc = setSubContext(subject, RESPONDER, RESPONDER);
- action.execute(prc);
- ActionTestingSupport.assertEvent(prc, AuthnEventIds.INVALID_SUBJECT);
+ final String event = action.apply(scc);
+ Assert.assertEquals(event, AuthnEventIds.INVALID_SUBJECT);
}
@Test public void testWrongResponderNameID() {
final Subject subject = new Subject();
subject.getPrincipals().add(new NameIDPrincipal(nameId("value", NameID.KERBEROS)));
- setSubContext(subject, REQUESTER, REQUESTER);
+ final var scc = setSubContext(subject, REQUESTER, REQUESTER);
- action.execute(prc);
- ActionTestingSupport.assertEvent(prc, AuthnEventIds.INVALID_SUBJECT);
+ final String event = action.apply(scc);
+ Assert.assertEquals(event, AuthnEventIds.INVALID_SUBJECT);
}
@Test public void testWrongRequester() {
final Subject subject = new Subject();
subject.getPrincipals().add(new NameIDPrincipal(nameId("value", NameID.KERBEROS, REQUESTER, REQUESTER)));
- setSubContext(subject, RESPONDER, RESPONDER);
+ final var scc = setSubContext(subject, RESPONDER, RESPONDER);
- action.execute(prc);
- ActionTestingSupport.assertEvent(prc, AuthnEventIds.INVALID_SUBJECT);
+ final String event = action.apply(scc);
+ Assert.assertEquals(event, AuthnEventIds.INVALID_SUBJECT);
}
@Test public void testWrongResponder() {
final Subject subject = new Subject();
subject.getPrincipals().add(new NameIDPrincipal(nameId("value", NameID.KERBEROS, REQUESTER, REQUESTER)));
- setSubContext(subject, REQUESTER, REQUESTER);
+ final var scc = setSubContext(subject, REQUESTER, REQUESTER);
- action.execute(prc);
- ActionTestingSupport.assertEvent(prc, AuthnEventIds.INVALID_SUBJECT);
+ final String event = action.apply(scc);
+ Assert.assertEquals(event, AuthnEventIds.INVALID_SUBJECT);
}
@Test public void testSuccess() {
final Subject subject = new Subject();
subject.getPrincipals().add(new UsernamePrincipal("foo at osu.edu"));
subject.getPrincipals().add(new NameIDPrincipal(nameId("works", NameID.KERBEROS)));
- setSubContext(subject, RESPONDER, REQUESTER);
+ final var scc = setSubContext(subject, RESPONDER, REQUESTER);
- action.execute(prc);
- ActionTestingSupport.assertProceedEvent(prc);
- SubjectCanonicalizationContext sc = prc.getSubcontext(SubjectCanonicalizationContext.class);
- assert sc!=null;
- Assert.assertEquals(sc.getPrincipalName(), VALUE_PREFIX + "works");
+ final String event = action.apply(scc);
+ Assert.assertEquals(event, EventIds.PROCEED_EVENT_ID);
+ Assert.assertEquals(scc.getPrincipalName(), VALUE_PREFIX + "works");
}
}
\ No newline at end of file
diff --git a/idp-saml-impl/src/test/java/net/shibboleth/idp/saml/nameid/impl/NameIdentifierCanonicalizationTest.java b/idp-saml-impl/src/test/java/net/shibboleth/idp/saml/nameid/impl/NameIdentifierCanonicalizationTest.java
index ccba9efdf..25e432804 100644
--- a/idp-saml-impl/src/test/java/net/shibboleth/idp/saml/nameid/impl/NameIdentifierCanonicalizationTest.java
+++ b/idp-saml-impl/src/test/java/net/shibboleth/idp/saml/nameid/impl/NameIdentifierCanonicalizationTest.java
@@ -22,8 +22,8 @@ import javax.security.auth.Subject;
import org.opensaml.core.testing.OpenSAMLInitBaseTestCase;
import org.opensaml.core.xml.config.XMLObjectProviderRegistrySupport;
+import org.opensaml.profile.action.EventIds;
import org.opensaml.profile.context.ProfileRequestContext;
-import org.opensaml.profile.testing.ActionTestingSupport;
import org.opensaml.saml.common.SAMLObjectBuilder;
import org.opensaml.saml.saml1.core.NameIdentifier;
import org.testng.Assert;
@@ -76,6 +76,7 @@ public class NameIdentifierCanonicalizationTest extends OpenSAMLInitBaseTestCase
flowDescriptor.initialize();
action = new NameIdentifierCanonicalization();
+ action.setId("test");
action.setDecoder(new NameIdentifierDecoder() {
public String decode(@Nonnull SubjectCanonicalizationContext scc, @Nonnull NameIdentifier nameIdentifier) {
if (RESPONDER.equals(scc.getResponderId()) && REQUESTER.equals(scc.getRequesterId())) {
@@ -87,7 +88,8 @@ public class NameIdentifierCanonicalizationTest extends OpenSAMLInitBaseTestCase
action.initialize();
}
- private void setSubContext(@Nullable Subject subject, @Nullable String responder, @Nullable String requester) {
+ @Nonnull private SubjectCanonicalizationContext setSubContext(@Nullable Subject subject, @Nullable String responder,
+ @Nullable String requester) {
final SubjectCanonicalizationContext scc = prc.ensureSubcontext(SubjectCanonicalizationContext.class);
if (subject != null) {
scc.setSubject(subject);
@@ -98,13 +100,11 @@ public class NameIdentifierCanonicalizationTest extends OpenSAMLInitBaseTestCase
if (responder != null) {
scc.setResponderId(responder);
}
- scc.setAttemptedFlow(flowDescriptor);
+ return scc.setAttemptedFlow(flowDescriptor);
}
@Nonnull private NameIdentifier nameId(String value, String format, String nameQualifier) {
-
final NameIdentifier id = builder.buildObject();
-
id.setValue(value);
id.setFormat(format);
id.setNameQualifier(nameQualifier);
@@ -112,29 +112,22 @@ public class NameIdentifierCanonicalizationTest extends OpenSAMLInitBaseTestCase
}
@Nonnull private NameIdentifier nameId(String value, String format) {
-
return nameId(value, format, RESPONDER);
}
@Test public void testNoContext() {
- assert prc!=null;
- action.execute(prc);
-
- assert prc!=null;
- ActionTestingSupport.assertEvent(prc, AuthnEventIds.INVALID_SUBJECT_C14N_CTX);
+ final String event = action.apply(null);
+ Assert.assertEquals(event, AuthnEventIds.INVALID_SUBJECT_C14N_CTX);
}
@Test public void testNoPrincipal() {
final Subject subject = new Subject();
- setSubContext(subject, null, null);
+ final var scc = setSubContext(subject, null, null);
- assert prc!=null;
- action.execute(prc);
+ final String event = action.apply(scc);
- assert prc!=null;
- ActionTestingSupport.assertEvent(prc, AuthnEventIds.INVALID_SUBJECT);
- final SubjectCanonicalizationContext scc = prc.getSubcontext(SubjectCanonicalizationContext.class);
- assert scc!=null && scc.getException()!=null;
+ Assert.assertNull(event);
+ Assert.assertNull(scc.getPrincipalName());
}
@Test public void testMultiPrincipals() {
@@ -142,66 +135,51 @@ public class NameIdentifierCanonicalizationTest extends OpenSAMLInitBaseTestCase
subject.getPrincipals().add(new NameIdentifierPrincipal(nameId("value", NameIdentifier.WIN_DOMAIN_QUALIFIED)));
subject.getPrincipals().add(new NameIdentifierPrincipal(nameId("value2", NameIdentifier.X509_SUBJECT)));
- setSubContext(subject, null, null);
+ final var scc = setSubContext(subject, null, null);
- assert prc!=null;
- action.execute(prc);
+ final String event = action.apply(scc);
- assert prc!=null;
- ActionTestingSupport.assertEvent(prc, AuthnEventIds.INVALID_SUBJECT);
- final SubjectCanonicalizationContext scc = prc.getSubcontext(SubjectCanonicalizationContext.class);
- assert scc!=null && scc.getException()!=null;
+ Assert.assertNull(event);
+ Assert.assertNull(scc.getPrincipalName());
}
@Test public void testWrongFormat() {
final Subject subject = new Subject();
subject.getPrincipals().add(new NameIdentifierPrincipal(nameId("value", NameIdentifier.WIN_DOMAIN_QUALIFIED)));
- setSubContext(subject, RESPONDER, REQUESTER);
+ final var scc = setSubContext(subject, RESPONDER, REQUESTER);
- assert prc!=null;
- action.execute(prc);
+ final String event = action.apply(scc);
- assert prc!=null;
- ActionTestingSupport.assertEvent(prc, AuthnEventIds.INVALID_SUBJECT);
- final SubjectCanonicalizationContext scc = prc.getSubcontext(SubjectCanonicalizationContext.class);
- assert scc!=null && scc.getException()!=null;
+ Assert.assertNull(event);
+ Assert.assertNull(scc.getPrincipalName());
}
@Test public void testWrongRequester() {
final Subject subject = new Subject();
subject.getPrincipals().add(new NameIdentifierPrincipal(nameId("value", NameIdentifier.EMAIL)));
- setSubContext(subject, RESPONDER, RESPONDER);
+ final var scc = setSubContext(subject, RESPONDER, RESPONDER);
- assert prc!=null;
- action.execute(prc);
-
- assert prc!=null;
- ActionTestingSupport.assertEvent(prc, AuthnEventIds.INVALID_SUBJECT);
+ final String event = action.apply(scc);
+ Assert.assertEquals(event, AuthnEventIds.INVALID_SUBJECT);
}
@Test public void testWrongResponderNameId() {
final Subject subject = new Subject();
subject.getPrincipals().add(new NameIdentifierPrincipal(nameId("value", NameIdentifier.EMAIL)));
- setSubContext(subject, REQUESTER, REQUESTER);
-
- assert prc!=null;
- action.execute(prc);
+ final var scc = setSubContext(subject, REQUESTER, REQUESTER);
- assert prc!=null;
- ActionTestingSupport.assertEvent(prc, AuthnEventIds.INVALID_SUBJECT);
+ final String event = action.apply(scc);
+ Assert.assertEquals(event, AuthnEventIds.INVALID_SUBJECT);
}
@Test public void testWrongResponder() {
final Subject subject = new Subject();
subject.getPrincipals().add(new NameIdentifierPrincipal(nameId("value", NameIdentifier.EMAIL, REQUESTER)));
- setSubContext(subject, REQUESTER, REQUESTER);
+ final var scc = setSubContext(subject, REQUESTER, REQUESTER);
- assert prc!=null;
- action.execute(prc);
-
- assert prc!=null;
- ActionTestingSupport.assertEvent(prc, AuthnEventIds.INVALID_SUBJECT);
+ final String event = action.apply(scc);
+ Assert.assertEquals(event, AuthnEventIds.INVALID_SUBJECT);
}
@@ -209,16 +187,11 @@ public class NameIdentifierCanonicalizationTest extends OpenSAMLInitBaseTestCase
final Subject subject = new Subject();
subject.getPrincipals().add(new UsernamePrincipal("foo at osu.edu"));
subject.getPrincipals().add(new NameIdentifierPrincipal(nameId("works", NameIdentifier.EMAIL)));
- setSubContext(subject, RESPONDER, REQUESTER);
-
- assert prc!=null;
- action.execute(prc);
+ final var scc = setSubContext(subject, RESPONDER, REQUESTER);
- assert prc!=null;
- ActionTestingSupport.assertProceedEvent(prc);
- SubjectCanonicalizationContext sc = prc.getSubcontext(SubjectCanonicalizationContext.class);
- assert sc!=null;
- Assert.assertEquals(sc.getPrincipalName(), VALUE_PREFIX+"works");
+ final String event = action.apply(scc);
+ Assert.assertEquals(event, EventIds.PROCEED_EVENT_ID);
+ Assert.assertEquals(scc.getPrincipalName(), VALUE_PREFIX+"works");
}
}
\ No newline at end of file
diff --git a/idp-saml-impl/src/test/java/net/shibboleth/idp/saml/nameid/impl/TransientDecoderTest.java b/idp-saml-impl/src/test/java/net/shibboleth/idp/saml/nameid/impl/TransientDecoderTest.java
index 44892c76d..8be3fe313 100644
--- a/idp-saml-impl/src/test/java/net/shibboleth/idp/saml/nameid/impl/TransientDecoderTest.java
+++ b/idp-saml-impl/src/test/java/net/shibboleth/idp/saml/nameid/impl/TransientDecoderTest.java
@@ -27,8 +27,8 @@ import net.shibboleth.shared.collection.CollectionSupport;
import net.shibboleth.shared.component.ComponentInitializationException;
import org.opensaml.core.testing.OpenSAMLInitBaseTestCase;
+import org.opensaml.profile.action.EventIds;
import org.opensaml.profile.context.ProfileRequestContext;
-import org.opensaml.profile.testing.ActionTestingSupport;
import org.opensaml.saml.saml2.core.NameID;
import org.opensaml.storage.impl.MemoryStorageService;
import org.testng.Assert;
@@ -151,6 +151,7 @@ public class TransientDecoderTest extends OpenSAMLInitBaseTestCase {
decoder.setId("decoder");
decoder.setIdStore(store);
decoder.initialize();
+ canon.setId("c14n/test");
canon.setDecoder(decoder);
canon.initialize();
@@ -164,10 +165,7 @@ public class TransientDecoderTest extends OpenSAMLInitBaseTestCase {
scc.setRequesterId(TestSources.SP_ENTITY_ID);
scc.setResponderId(TestSources.IDP_ENTITY_ID);
- canon.execute(prc);
-
- ActionTestingSupport.assertProceedEvent(prc);
-
+ Assert.assertEquals(canon.apply(scc), EventIds.PROCEED_EVENT_ID);
Assert.assertEquals(scc.getPrincipalName(), TestSources.PRINCIPAL_ID);
}
--
To stop receiving notification emails like this one, please contact
the administrator of this repository.
More information about the commits
mailing list