[java-identity-provider] branch master updated: Extend c14n variant to Subject DataConnector.

Scott Cantor cantor.2 at osu.edu
Mon Nov 4 16:01:14 EST 2019


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

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

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

The following commit(s) were added to refs/heads/master by this push:
       new  09d2671   Extend c14n variant to Subject DataConnector.
09d2671 is described below

commit 09d2671db67a48dca8810013a4de9606916c4e43
Author: Scott Cantor <cantor.2 at osu.edu>
AuthorDate: Mon Nov 4 16:01:11 2019 -0500

    Extend c14n variant to Subject DataConnector.
---
 .../resolver/dc/impl/SubjectDataConnector.java     | 86 ++++++++++++++++++++--
 .../resolver/dc/impl/SubjectDataConnectorTest.java | 38 +++++++++-
 .../SubjectDerivedAttributeDefinitionParser.java   |  9 ++-
 .../spring/dc/impl/SubjectDataConnectorParser.java |  9 ++-
 .../spring/dc/SubjectDataConnectorParserTest.java  |  1 +
 .../spring/dc/resolver/subjectAttributes.xml       |  1 +
 .../schema/shibboleth-attribute-resolver.xsd       |  8 ++
 7 files changed, 136 insertions(+), 16 deletions(-)

diff --git a/idp-attribute-resolver-impl/src/main/java/net/shibboleth/idp/attribute/resolver/dc/impl/SubjectDataConnector.java b/idp-attribute-resolver-impl/src/main/java/net/shibboleth/idp/attribute/resolver/dc/impl/SubjectDataConnector.java
index 52203c4..4b6913d 100644
--- a/idp-attribute-resolver-impl/src/main/java/net/shibboleth/idp/attribute/resolver/dc/impl/SubjectDataConnector.java
+++ b/idp-attribute-resolver-impl/src/main/java/net/shibboleth/idp/attribute/resolver/dc/impl/SubjectDataConnector.java
@@ -17,12 +17,14 @@
 
 package net.shibboleth.idp.attribute.resolver.dc.impl;
 
+import java.util.Collection;
 import java.util.Collections;
 import java.util.HashMap;
 import java.util.Map;
 import java.util.function.Function;
 
 import javax.annotation.Nonnull;
+import javax.annotation.Nullable;
 import javax.annotation.concurrent.ThreadSafe;
 import javax.security.auth.Subject;
 
@@ -36,8 +38,11 @@ import net.shibboleth.idp.attribute.resolver.AbstractDataConnector;
 import net.shibboleth.idp.attribute.resolver.ResolutionException;
 import net.shibboleth.idp.attribute.resolver.context.AttributeResolutionContext;
 import net.shibboleth.idp.attribute.resolver.context.AttributeResolverWorkContext;
+import net.shibboleth.idp.authn.context.SubjectCanonicalizationContext;
 import net.shibboleth.idp.authn.context.SubjectContext;
+import net.shibboleth.idp.authn.context.navigate.SubjectCanonicalizationContextSubjectLookupFunction;
 import net.shibboleth.idp.authn.principal.IdPAttributePrincipal;
+import net.shibboleth.utilities.java.support.component.ComponentInitializationException;
 import net.shibboleth.utilities.java.support.component.ComponentSupport;
 import net.shibboleth.utilities.java.support.logic.Constraint;
 
@@ -45,6 +50,8 @@ import net.shibboleth.utilities.java.support.logic.Constraint;
  * A {@link net.shibboleth.idp.attribute.resolver.DataConnector} that extracts all
  * {@link IdPAttributePrincipal} objects from the {@link Subject} objects associated
  * with the request.
+ * 
+ * @since 4.0.0
  */
 @ThreadSafe
 public class SubjectDataConnector extends AbstractDataConnector {
@@ -52,9 +59,15 @@ public class SubjectDataConnector extends AbstractDataConnector {
     /** Class logger. */
     @Nonnull private final Logger log = LoggerFactory.getLogger(SubjectDataConnector.class);
     
+    /** Flag denoting whether plugin is being used for subject c14n or standard usage. */
+    private boolean forCanonicalization;
+
     /** Strategy used to locate the {@link SubjectContext} to use. */
     @Nonnull private Function<ProfileRequestContext,SubjectContext> scLookupStrategy;
     
+    /** Strategy used to locate the {@link Subject} to use. */
+    @Nullable private Function<ProfileRequestContext,Subject> subjectLookupStrategy;
+    
     /** Controls handling of empty results. */
     private boolean noResultIsError;
     
@@ -64,6 +77,30 @@ public class SubjectDataConnector extends AbstractDataConnector {
     }
     
     /**
+     * Gets whether the connector is being used during Subject Canonicalization, causing
+     * auto-installation of an alternate Subject lookup strategy.
+     * 
+     * @return whether connector is being used during c14n
+     */
+    public boolean isForCanonicalization() {
+        return forCanonicalization;
+    }
+    
+    /**
+     * Sets whether the connector is being used during Subject Canonicalization, causing
+     * auto-installation of an alternate Subject lookup strategy.
+     * 
+     * <p>Defaults to false.</p>
+     * 
+     * @param flag flag to set
+     */
+    public void setForCanonicalization(final boolean flag) {
+        ComponentSupport.ifInitializedThrowUnmodifiabledComponentException(this);
+        
+        forCanonicalization = flag;
+    }
+    
+    /**
      * Sets the strategy used to locate the {@link SubjectContext} associated with a given
      * {@link AttributeResolutionContext}.
      * 
@@ -77,6 +114,19 @@ public class SubjectDataConnector extends AbstractDataConnector {
     }
     
     /**
+     * Sets the strategy used to locate a {@link Subject} associated with a given
+     * {@link AttributeResolutionContext}.
+     * 
+     * @param strategy strategy used to locate a {@link Subject} associated with a given
+     *            {@link AttributeResolutionContext}
+     */
+    public void setSubjectLookupStrategy(@Nullable final Function<ProfileRequestContext,Subject> strategy) {
+        ComponentSupport.ifInitializedThrowUnmodifiabledComponentException(this);
+
+        subjectLookupStrategy = strategy;
+    }
+    
+    /**
      * Gets whether obtaining no results should be treated as an error.
      * 
      * @return whether obtaining no results should be treated as an error
@@ -97,6 +147,18 @@ public class SubjectDataConnector extends AbstractDataConnector {
         
         noResultIsError = flag;
     }
+    
+    /** {@inheritDoc} */
+    @Override protected void doInitialize() throws ComponentInitializationException {
+        super.doInitialize();
+        
+        if (forCanonicalization && subjectLookupStrategy == null) {
+            log.debug("{} Marked for use during canonicalication, auto-installing Subject lookup strategy",
+                    getLogPrefix());
+            subjectLookupStrategy = new SubjectCanonicalizationContextSubjectLookupFunction().compose(
+                    new ChildContextLookup<>(SubjectCanonicalizationContext.class));
+        }
+    }
 
     /** {@inheritDoc} */
     @Override
@@ -106,19 +168,27 @@ public class SubjectDataConnector extends AbstractDataConnector {
         ComponentSupport.ifNotInitializedThrowUninitializedComponentException(this);
         ComponentSupport.ifDestroyedThrowDestroyedComponentException(this);
         
-        final SubjectContext sc = scLookupStrategy.compose(getProfileContextStrategy()).apply(resolutionContext);
-        if (sc == null || sc.getSubjects().isEmpty()) {
-            if (noResultIsError) {
-                throw new ResolutionException("No Subjects available to obtain attributes");
+        Collection<Subject> subjects = Collections.emptyList();
+        
+        if (subjectLookupStrategy != null) {
+            final Subject subject = subjectLookupStrategy.apply(getProfileContextStrategy().apply(resolutionContext));
+            if (subject == null) {
+                log.debug("{} No Subject returned from lookup, no attributes resolved", getLogPrefix());
+                return Collections.emptyMap();
             }
-            log.debug("{} Obtained no attributes from Subjects for principal '{}'", getLogPrefix(),
-                    resolutionContext.getPrincipal());
-            return Collections.emptyMap();
+            subjects = Collections.singletonList(subject);
+        } else {
+            final SubjectContext cs = scLookupStrategy.apply(getProfileContextStrategy().apply(resolutionContext));
+            if (cs == null || cs.getSubjects().isEmpty()) {
+                log.debug("{} No Subjects returned from SubjectContext lookup, no attributes resolved", getLogPrefix());
+                return Collections.emptyMap();
+            }
+            subjects = cs.getSubjects();
         }
         
         final Map<String,IdPAttribute> results = new HashMap<>();
         
-        for (final Subject subject : sc.getSubjects()) {
+        for (final Subject subject : subjects) {
             for (final IdPAttributePrincipal principal : subject.getPrincipals(IdPAttributePrincipal.class)) {
                 results.put(principal.getName(), principal.getAttribute());
             }
diff --git a/idp-attribute-resolver-impl/src/test/java/net/shibboleth/idp/attribute/resolver/dc/impl/SubjectDataConnectorTest.java b/idp-attribute-resolver-impl/src/test/java/net/shibboleth/idp/attribute/resolver/dc/impl/SubjectDataConnectorTest.java
index b2c18d9..3e0fb62 100644
--- a/idp-attribute-resolver-impl/src/test/java/net/shibboleth/idp/attribute/resolver/dc/impl/SubjectDataConnectorTest.java
+++ b/idp-attribute-resolver-impl/src/test/java/net/shibboleth/idp/attribute/resolver/dc/impl/SubjectDataConnectorTest.java
@@ -33,6 +33,7 @@ import net.shibboleth.idp.attribute.StringAttributeValue;
 import net.shibboleth.idp.attribute.resolver.ResolutionException;
 import net.shibboleth.idp.attribute.resolver.context.AttributeResolutionContext;
 import net.shibboleth.idp.authn.AuthenticationResult;
+import net.shibboleth.idp.authn.context.SubjectCanonicalizationContext;
 import net.shibboleth.idp.authn.context.SubjectContext;
 import net.shibboleth.idp.authn.principal.IdPAttributePrincipal;
 import net.shibboleth.idp.saml.authn.principal.AuthenticationMethodPrincipal;
@@ -45,7 +46,6 @@ public class SubjectDataConnectorTest {
     /** Simple result. */
     private static final String SIMPLE_VALUE = "simple";
     
-
     @Test public void simpleValue() throws ComponentInitializationException, ResolutionException {
         final List<IdPAttributeValue> list = new ArrayList<>(2);
         list.add(new StringAttributeValue(SIMPLE_VALUE));
@@ -79,7 +79,41 @@ public class SubjectDataConnectorTest {
         assertTrue(copy.getValues().contains(new StringAttributeValue(SIMPLE_VALUE)));
         assertTrue(copy.getValues().contains(new StringAttributeValue(SIMPLE_VALUE + "2")));
     }
-    
+
+    @Test public void simpleValueViaC14N() throws ComponentInitializationException, ResolutionException {
+        final List<IdPAttributeValue> list = new ArrayList<>(2);
+        list.add(new StringAttributeValue(SIMPLE_VALUE));
+        list.add(new StringAttributeValue(SIMPLE_VALUE + "2"));
+        
+        final IdPAttribute attr = new IdPAttribute("wibble");
+        attr.setValues(list);
+
+        final SubjectDataConnector defn = new SubjectDataConnector();
+        defn.setId("pDAD");
+        defn.setForCanonicalization(true);
+        defn.initialize();
+
+        final AttributeResolutionContext ctx =
+                TestSources.createResolutionContext(TestSources.PRINCIPAL_ID, TestSources.IDP_ENTITY_ID,
+                        TestSources.SP_ENTITY_ID);
+        final SubjectCanonicalizationContext sc = ctx.getParent().getSubcontext(SubjectCanonicalizationContext.class, true);
+        final Subject subject = new Subject();
+        subject.getPrincipals().add(new IdPAttributePrincipal(attr));
+        subject.getPrincipals().add(new AuthenticationMethodPrincipal(SIMPLE_VALUE + "2"));
+        sc.setSubject(subject);
+        
+        
+        final Map<String,IdPAttribute> results = defn.resolve(ctx);
+        
+        assertEquals(1, results.size());
+        
+        final IdPAttribute copy = results.get("wibble");
+        
+        assertEquals(copy.getValues().size(), 2);
+        assertTrue(copy.getValues().contains(new StringAttributeValue(SIMPLE_VALUE)));
+        assertTrue(copy.getValues().contains(new StringAttributeValue(SIMPLE_VALUE + "2")));
+    }
+
     @Test public void emptyOk() throws ComponentInitializationException, ResolutionException {
 
         final SubjectDataConnector defn = new SubjectDataConnector();
diff --git a/idp-attribute-resolver-spring/src/main/java/net/shibboleth/idp/attribute/resolver/spring/ad/impl/SubjectDerivedAttributeDefinitionParser.java b/idp-attribute-resolver-spring/src/main/java/net/shibboleth/idp/attribute/resolver/spring/ad/impl/SubjectDerivedAttributeDefinitionParser.java
index 033908b..72ec4d4 100644
--- a/idp-attribute-resolver-spring/src/main/java/net/shibboleth/idp/attribute/resolver/spring/ad/impl/SubjectDerivedAttributeDefinitionParser.java
+++ b/idp-attribute-resolver-spring/src/main/java/net/shibboleth/idp/attribute/resolver/spring/ad/impl/SubjectDerivedAttributeDefinitionParser.java
@@ -27,6 +27,7 @@ import org.springframework.beans.factory.support.BeanDefinitionBuilder;
 import org.springframework.beans.factory.xml.ParserContext;
 import org.w3c.dom.Element;
 
+import net.shibboleth.ext.spring.util.SpringSupport;
 import net.shibboleth.idp.attribute.resolver.ad.impl.ContextDerivedAttributeDefinition;
 import net.shibboleth.idp.attribute.resolver.ad.impl.IdPAttributePrincipalValuesFunction;
 import net.shibboleth.idp.attribute.resolver.ad.impl.SubjectDerivedAttributeValuesFunction;
@@ -62,16 +63,16 @@ public class SubjectDerivedAttributeDefinitionParser extends BaseAttributeDefini
         super.doParse(config, parserContext, builder);
         final String attributeName = StringSupport.trimOrNull(config.getAttributeNS(null, "principalAttributeName"));
         final String functionRef = StringSupport.trimOrNull(config.getAttributeNS(null, "attributeValuesFunctionRef"));
-        final String c14n = StringSupport.trimOrNull(config.getAttributeNS(null, "forCanonicalization"));
         
         final BeanDefinitionBuilder contextFunctionBuilder =
                 BeanDefinitionBuilder.genericBeanDefinition(SubjectDerivedAttributeValuesFunction.class);
         contextFunctionBuilder.addPropertyValue("id", getDefinitionId());
 
-        if (c14n != null) {
-            contextFunctionBuilder.addPropertyValue("forCanonicalization", c14n);
+        if (config.hasAttributeNS(null, "forCanonicalization")) {
+            contextFunctionBuilder.addPropertyValue("forCanonicalization",
+                    SpringSupport.getStringValueAsBoolean(config.getAttributeNS(null, "forCanonicalization")));
         }
-        
+
         if (null != attributeName) {
             if (null != functionRef) {
                 log.warn("{} only one of \"principalAttributeName\" or \"attributeValuesFunctionRef\""
diff --git a/idp-attribute-resolver-spring/src/main/java/net/shibboleth/idp/attribute/resolver/spring/dc/impl/SubjectDataConnectorParser.java b/idp-attribute-resolver-spring/src/main/java/net/shibboleth/idp/attribute/resolver/spring/dc/impl/SubjectDataConnectorParser.java
index f2be591..9758fde 100644
--- a/idp-attribute-resolver-spring/src/main/java/net/shibboleth/idp/attribute/resolver/spring/dc/impl/SubjectDataConnectorParser.java
+++ b/idp-attribute-resolver-spring/src/main/java/net/shibboleth/idp/attribute/resolver/spring/dc/impl/SubjectDataConnectorParser.java
@@ -46,8 +46,13 @@ public class SubjectDataConnectorParser extends AbstractDataConnectorParser {
             @Nonnull final BeanDefinitionBuilder builder) {
         
         if (config.hasAttributeNS(null, "noResultIsError")) {
-            builder.addPropertyValue("noResultIsError", SpringSupport.getStringValueAsBoolean(
-                    config.getAttributeNS(null, "noResultIsError")));
+            builder.addPropertyValue("noResultIsError",
+                    SpringSupport.getStringValueAsBoolean(config.getAttributeNS(null, "noResultIsError")));
+        }
+        
+        if (config.hasAttributeNS(null, "forCanonicalization")) {
+            builder.addPropertyValue("forCanonicalization",
+                    SpringSupport.getStringValueAsBoolean(config.getAttributeNS(null, "forCanonicalization")));
         }
     }
 
diff --git a/idp-attribute-resolver-spring/src/test/java/net/shibboleth/idp/attribute/resolver/spring/dc/SubjectDataConnectorParserTest.java b/idp-attribute-resolver-spring/src/test/java/net/shibboleth/idp/attribute/resolver/spring/dc/SubjectDataConnectorParserTest.java
index a4ebdf2..62d406e 100644
--- a/idp-attribute-resolver-spring/src/test/java/net/shibboleth/idp/attribute/resolver/spring/dc/SubjectDataConnectorParserTest.java
+++ b/idp-attribute-resolver-spring/src/test/java/net/shibboleth/idp/attribute/resolver/spring/dc/SubjectDataConnectorParserTest.java
@@ -40,6 +40,7 @@ public class SubjectDataConnectorParserTest extends BaseAttributeDefinitionParse
         assertTrue(connector.getExportAttributes().contains("foo"));
         assertTrue(connector.getExportAttributes().contains("bar"));
         assertTrue(connector.isNoResultIsError());
+        assertTrue(connector.isForCanonicalization());
     }
     
     @Test(expectedExceptions = {BeanCreationException.class}) public void emptyNoResultIsError() {
diff --git a/idp-attribute-resolver-spring/src/test/resources/net/shibboleth/idp/attribute/resolver/spring/dc/resolver/subjectAttributes.xml b/idp-attribute-resolver-spring/src/test/resources/net/shibboleth/idp/attribute/resolver/spring/dc/resolver/subjectAttributes.xml
index 0877943..73f757e 100644
--- a/idp-attribute-resolver-spring/src/test/resources/net/shibboleth/idp/attribute/resolver/spring/dc/resolver/subjectAttributes.xml
+++ b/idp-attribute-resolver-spring/src/test/resources/net/shibboleth/idp/attribute/resolver/spring/dc/resolver/subjectAttributes.xml
@@ -3,4 +3,5 @@
     xmlns="urn:mace:shibboleth:2.0:resolver"  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
     exportAttributes="foo bar"
     noResultIsError="true"
+    forCanonicalization="1"
 	xsi:schemaLocation="urn:mace:shibboleth:2.0:resolver http://shibboleth.net/schema/idp/shibboleth-attribute-resolver.xsd" />
diff --git a/idp-schema/src/main/resources/schema/shibboleth-attribute-resolver.xsd b/idp-schema/src/main/resources/schema/shibboleth-attribute-resolver.xsd
index 33c79a8..0512951 100644
--- a/idp-schema/src/main/resources/schema/shibboleth-attribute-resolver.xsd
+++ b/idp-schema/src/main/resources/schema/shibboleth-attribute-resolver.xsd
@@ -1548,6 +1548,14 @@
                         </documentation>
                     </annotation>
                 </attribute>
+                <attribute name="forCanonicalization" type="resolver:string">
+                    <annotation>
+                        <documentation>
+                            If true, the source Subject is assumed to be undergoing C14N rather than the
+                            usual post-authentication source. Defaults to false.
+                        </documentation>
+                    </annotation>
+                </attribute>
             </extension>
         </complexContent>
     </complexType>

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


More information about the commits mailing list