[java-shib-attribute] branch main updated: Re-implement Subject data connector on top of new generic connector.

Scott Cantor cantor.2 at osu.edu
Mon Jul 11 20:16:39 UTC 2022


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

scantor pushed a commit to branch main
in repository java-shib-attribute.

View the commit online:
http://git.shibboleth.net/view/?p=java-shib-attribute.git;a=commit;h=e249c48b3dc95387909b36ea9cfec0586555a5d8

The following commit(s) were added to refs/heads/main by this push:
     new e249c48b3 Re-implement Subject data connector on top of new generic connector.
e249c48b3 is described below

commit e249c48b3dc95387909b36ea9cfec0586555a5d8
Author: Scott Cantor <cantor.2 at osu.edu>
AuthorDate: Mon Jul 11 16:16:36 2022 -0400

    Re-implement Subject data connector on top of new generic connector.
---
 .../dc/impl/ContextDerivedDataConnector.java       | 134 +++++++++++++++++++++
 .../dc/impl/ContextDerivedDataConnectorParser.java |  72 +++++++++++
 .../spring/dc/impl/SubjectDataConnectorParser.java |  96 +++++++++++++++
 .../impl/AttributeResolverNamespaceHandler.java    |   7 +-
 .../schema/shibboleth-attribute-resolver.xsd       |  29 ++++-
 5 files changed, 335 insertions(+), 3 deletions(-)

diff --git a/shib-attribute-resolver-impl/src/main/java/net/shibboleth/idp/attribute/resolver/dc/impl/ContextDerivedDataConnector.java b/shib-attribute-resolver-impl/src/main/java/net/shibboleth/idp/attribute/resolver/dc/impl/ContextDerivedDataConnector.java
new file mode 100644
index 000000000..4cd189b76
--- /dev/null
+++ b/shib-attribute-resolver-impl/src/main/java/net/shibboleth/idp/attribute/resolver/dc/impl/ContextDerivedDataConnector.java
@@ -0,0 +1,134 @@
+/*
+ * Licensed to the University Corporation for Advanced Internet Development,
+ * Inc. (UCAID) under one or more contributor license agreements.  See the
+ * NOTICE file distributed with this work for additional information regarding
+ * copyright ownership. The UCAID licenses this file to You under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file except in
+ * compliance with the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package net.shibboleth.idp.attribute.resolver.dc.impl;
+
+import java.util.List;
+import java.util.Map;
+import java.util.function.Function;
+import java.util.stream.Collectors;
+
+import javax.annotation.Nonnull;
+
+import net.shibboleth.idp.attribute.IdPAttribute;
+import net.shibboleth.idp.attribute.resolver.AbstractDataConnector;
+import net.shibboleth.idp.attribute.resolver.NoResultAnErrorResolutionException;
+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.utilities.java.support.annotation.constraint.NonnullAfterInit;
+import net.shibboleth.utilities.java.support.component.ComponentInitializationException;
+import net.shibboleth.utilities.java.support.component.ComponentSupport;
+import net.shibboleth.utilities.java.support.logic.Constraint;
+
+import org.opensaml.profile.context.ProfileRequestContext;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * A data connector which returns attributes whose values are derived from the
+ * {@link ProfileRequestContext} associated with the request via a plugged in {@link Function}.
+ */
+public class ContextDerivedDataConnector extends AbstractDataConnector {
+
+    /** Logger. */
+    @Nonnull private final Logger log = LoggerFactory.getLogger(ContextDerivedDataConnector.class);
+
+    /**
+     * Function used to generate the attributes derived from the {@link ProfileRequestContext}.
+     */
+    @NonnullAfterInit private Function<ProfileRequestContext,List<IdPAttribute>> attributesFunction;
+
+    /** Whether no record is an error. */
+    private boolean noResultIsError;
+
+    /**
+     * Gets the attribute derivation function.
+     * 
+     * @return derivation function
+     */
+    @NonnullAfterInit public Function<ProfileRequestContext,List<IdPAttribute>> getAttributesFunction() {
+        return attributesFunction;
+    }
+    
+    /**
+     * Sets the attribute derivation function.
+     * 
+     * @param function what to set.
+     */
+    public void setAttributesFunction(@Nonnull final Function<ProfileRequestContext,List<IdPAttribute>> function) {
+        ComponentSupport.ifInitializedThrowUnmodifiabledComponentException(this);
+        ComponentSupport.ifDestroyedThrowDestroyedComponentException(this);
+        
+        attributesFunction = Constraint.isNotNull(function, "Attribute Function cannot be null");
+    }
+
+    /**
+     * Gets whether the lack of returned attributes constitutes an error.
+     * 
+     * @return whether the lack of returned attributes constitutes an error
+     */
+    public boolean isNoResultIsError() {
+        return noResultIsError;
+    }
+    
+    /**
+     * Sets whether the lack of a returned record constitutes an error.
+     * 
+     * @param flag flag to set
+     */
+    public void setNoResultIsError(final boolean flag) {
+        ComponentSupport.ifInitializedThrowUnmodifiabledComponentException(this);
+        ComponentSupport.ifDestroyedThrowDestroyedComponentException(this);
+
+        noResultIsError = flag;
+    }
+
+    /** {@inheritDoc} */
+    @Override protected void doInitialize() throws ComponentInitializationException {
+        super.doInitialize();
+    
+        if (attributesFunction == null) {
+            throw new ComponentInitializationException("Attribute lookup strategy cannot be null");
+        }
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    @Nonnull protected Map<String,IdPAttribute> doDataConnectorResolve(
+            @Nonnull final AttributeResolutionContext resolutionContext,
+            @Nonnull final AttributeResolverWorkContext workContext) throws ResolutionException {
+
+        final List<IdPAttribute> results =
+                attributesFunction.apply(
+                        resolutionContext.getProfileRequestContextLookupStrategy().apply(resolutionContext));
+
+        if (null == results || results.isEmpty()) {
+            if (noResultIsError) {
+                throw new NoResultAnErrorResolutionException(getLogPrefix() + " No attributes returned");
+            }
+            log.debug("{} Generated no attributes", getLogPrefix());
+            return null;
+        }
+        
+        log.debug("{} Generated {} attributes", getLogPrefix(), results.size());
+        log.trace("{} Attributes: {}", getLogPrefix(), results);
+        
+        return results.stream().collect(Collectors.toUnmodifiableMap(IdPAttribute::getId, Function.identity()));
+    }
+
+}
\ No newline at end of file
diff --git a/shib-attribute-resolver-spring/src/main/java/net/shibboleth/idp/attribute/resolver/spring/dc/impl/ContextDerivedDataConnectorParser.java b/shib-attribute-resolver-spring/src/main/java/net/shibboleth/idp/attribute/resolver/spring/dc/impl/ContextDerivedDataConnectorParser.java
new file mode 100644
index 000000000..2655ec494
--- /dev/null
+++ b/shib-attribute-resolver-spring/src/main/java/net/shibboleth/idp/attribute/resolver/spring/dc/impl/ContextDerivedDataConnectorParser.java
@@ -0,0 +1,72 @@
+/*
+ * Licensed to the University Corporation for Advanced Internet Development,
+ * Inc. (UCAID) under one or more contributor license agreements.  See the
+ * NOTICE file distributed with this work for additional information regarding
+ * copyright ownership. The UCAID licenses this file to You under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file except in
+ * compliance with the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package net.shibboleth.idp.attribute.resolver.spring.dc.impl;
+
+import javax.annotation.Nonnull;
+import javax.xml.namespace.QName;
+
+import org.springframework.beans.factory.BeanCreationException;
+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.AbstractDataConnector;
+import net.shibboleth.idp.attribute.resolver.dc.impl.ContextDerivedDataConnector;
+import net.shibboleth.idp.attribute.resolver.spring.dc.AbstractDataConnectorParser;
+import net.shibboleth.idp.attribute.resolver.spring.impl.AttributeResolverNamespaceHandler;
+import net.shibboleth.utilities.java.support.primitive.StringSupport;
+import net.shibboleth.utilities.java.support.xml.AttributeSupport;
+
+/** Spring Bean Definition Parser for {@link ContextDerivedDataConnector}. */
+public class ContextDerivedDataConnectorParser extends AbstractDataConnectorParser {
+
+    /** Schema type name. */
+    @Nonnull public static final QName TYPE_NAME_RESOLVER =
+            new QName(AttributeResolverNamespaceHandler.NAMESPACE, "ContextDerived");
+
+    /** {@inheritDoc} */
+    @Override
+    @Nonnull protected Class<? extends AbstractDataConnector> getNativeBeanClass() {
+        return ContextDerivedDataConnector.class;
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    protected void doV2Parse(@Nonnull final Element element, @Nonnull final ParserContext parserContext,
+            @Nonnull final BeanDefinitionBuilder builder) {
+        final String functionRef = StringSupport.trimOrNull(element.getAttributeNS(null, "attributesFunctionRef"));
+
+        if (null == functionRef) {
+            throw new BeanCreationException(getLogPrefix() + "requires 'attributesFunctionRef'");
+        }
+        builder.addPropertyReference("attributesFunction", functionRef);
+
+        final String noResultIsError =
+                AttributeSupport.getAttributeValue(element, new QName("noResultIsError"));
+        if (noResultIsError != null) {
+            builder.addPropertyValue("noResultIsError", SpringSupport.getStringValueAsBoolean(noResultIsError));
+        }
+    }
+    
+    /** {@inheritDoc} */
+    @Override protected boolean failOnDependencies() {
+        return true;
+    }
+
+}
\ No newline at end of file
diff --git a/shib-attribute-resolver-spring/src/main/java/net/shibboleth/idp/attribute/resolver/spring/dc/impl/SubjectDataConnectorParser.java b/shib-attribute-resolver-spring/src/main/java/net/shibboleth/idp/attribute/resolver/spring/dc/impl/SubjectDataConnectorParser.java
new file mode 100644
index 000000000..6f69f0120
--- /dev/null
+++ b/shib-attribute-resolver-spring/src/main/java/net/shibboleth/idp/attribute/resolver/spring/dc/impl/SubjectDataConnectorParser.java
@@ -0,0 +1,96 @@
+/*
+ * Licensed to the University Corporation for Advanced Internet Development,
+ * Inc. (UCAID) under one or more contributor license agreements.  See the
+ * NOTICE file distributed with this work for additional information regarding
+ * copyright ownership. The UCAID licenses this file to You under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file except in
+ * compliance with the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package net.shibboleth.idp.attribute.resolver.spring.dc.impl;
+
+import java.util.function.Function;
+
+import javax.annotation.Nonnull;
+import javax.xml.namespace.QName;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.BeanCreationException;
+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.dc.impl.ContextDerivedDataConnector;
+import net.shibboleth.idp.attribute.resolver.spring.impl.AttributeResolverNamespaceHandler;
+import net.shibboleth.utilities.java.support.annotation.constraint.NotEmpty;
+import net.shibboleth.utilities.java.support.xml.AttributeSupport;
+
+/** Spring Bean Definition Parser for {@link ContextDerivedDataConnector} with a predefined mapping function. */
+public class SubjectDataConnectorParser extends ContextDerivedDataConnectorParser {
+
+    /** Schema type name. */
+    @Nonnull public static final QName TYPE_NAME_RESOLVER =
+            new QName(AttributeResolverNamespaceHandler.NAMESPACE, "Subject");
+
+    /** Class name for sourcing attributes from Subject(s). */
+    @Nonnull @NotEmpty private static final String SUBJECT_DERIVED_CLASS_NAME =
+            "net.shibboleth.idp.authn.context.impl.SubjectDerivedAttributesFunction"; 
+
+    /** Class logger. */
+    @Nonnull private final Logger log = LoggerFactory.getLogger(SubjectDataConnectorParser.class);
+
+    /** Class for sourcing values from Subject(s). */
+    @Nonnull private Class<? extends Function<?,?>> subjectDerivedClass;
+
+    /** Constructor. */
+    @SuppressWarnings("unchecked")
+    public SubjectDataConnectorParser() {
+        try {
+            subjectDerivedClass = (Class<? extends Function<?, ?>>) Class.forName(SUBJECT_DERIVED_CLASS_NAME);
+        } catch (final ClassNotFoundException e) {
+            log.error("Unable to load class to support instantiation of this plugin type.");
+        }
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    protected void doV2Parse(@Nonnull final Element element, @Nonnull final ParserContext parserContext,
+            @Nonnull final BeanDefinitionBuilder builder) {
+        
+        if (subjectDerivedClass == null) {
+            throw new BeanCreationException("Unable to load class for subject-derived attribute function.");
+        }
+
+        // Auto-inject an instance of the deferred class type as the lookup function.
+        
+        final BeanDefinitionBuilder contextFunctionBuilder =
+                BeanDefinitionBuilder.genericBeanDefinition(subjectDerivedClass);
+        contextFunctionBuilder.setInitMethodName("initialize");
+        contextFunctionBuilder.setDestroyMethodName("destroy");
+        contextFunctionBuilder.addPropertyValue("id", getDefinitionId());
+
+        if (element.hasAttributeNS(null, "forCanonicalization")) {
+            contextFunctionBuilder.addPropertyValue("forCanonicalization",
+                    SpringSupport.getStringValueAsBoolean(element.getAttributeNS(null, "forCanonicalization")));
+        }
+        
+        builder.addPropertyValue("attributesFunction", contextFunctionBuilder.getBeanDefinition());
+        
+        final String noResultIsError =
+                AttributeSupport.getAttributeValue(element, new QName("noResultIsError"));
+        if (noResultIsError != null) {
+            builder.addPropertyValue("noResultIsError", SpringSupport.getStringValueAsBoolean(noResultIsError));
+        }
+    }
+
+}
\ No newline at end of file
diff --git a/shib-attribute-resolver-spring/src/main/java/net/shibboleth/idp/attribute/resolver/spring/impl/AttributeResolverNamespaceHandler.java b/shib-attribute-resolver-spring/src/main/java/net/shibboleth/idp/attribute/resolver/spring/impl/AttributeResolverNamespaceHandler.java
index 596432c28..46352c942 100644
--- a/shib-attribute-resolver-spring/src/main/java/net/shibboleth/idp/attribute/resolver/spring/impl/AttributeResolverNamespaceHandler.java
+++ b/shib-attribute-resolver-spring/src/main/java/net/shibboleth/idp/attribute/resolver/spring/impl/AttributeResolverNamespaceHandler.java
@@ -39,10 +39,12 @@ import net.shibboleth.idp.attribute.resolver.spring.ad.mapped.impl.SourceValuePa
 import net.shibboleth.idp.attribute.resolver.spring.ad.mapped.impl.ValueMapParser;
 import net.shibboleth.idp.attribute.resolver.spring.dc.http.impl.HTTPDataConnectorParser;
 import net.shibboleth.idp.attribute.resolver.spring.dc.impl.ComputedIdDataConnectorParser;
+import net.shibboleth.idp.attribute.resolver.spring.dc.impl.ContextDerivedDataConnectorParser;
 import net.shibboleth.idp.attribute.resolver.spring.dc.impl.PairwiseIdDataConnectorParser;
 import net.shibboleth.idp.attribute.resolver.spring.dc.impl.ScriptedDataConnectorParser;
 import net.shibboleth.idp.attribute.resolver.spring.dc.impl.StaticDataConnectorParser;
 import net.shibboleth.idp.attribute.resolver.spring.dc.impl.StoredIdDataConnectorParser;
+import net.shibboleth.idp.attribute.resolver.spring.dc.impl.SubjectDataConnectorParser;
 import net.shibboleth.idp.attribute.resolver.spring.dc.ldap.impl.LDAPDataConnectorParser;
 import net.shibboleth.idp.attribute.resolver.spring.dc.rdbms.impl.RDBMSDataConnectorParser;
 import net.shibboleth.idp.attribute.resolver.spring.dc.storage.impl.StorageServiceDataConnectorParser;
@@ -118,8 +120,9 @@ public class AttributeResolverNamespaceHandler extends BaseSpringNamespaceHandle
         registerBeanDefinitionParser(ScriptedDataConnectorParser.TYPE_NAME_RESOLVER, new ScriptedDataConnectorParser());
         registerBeanDefinitionParser(StaticDataConnectorParser.TYPE_NAME_RESOLVER, new StaticDataConnectorParser());
         registerBeanDefinitionParser(StoredIdDataConnectorParser.TYPE_NAME_RESOLVER, new StoredIdDataConnectorParser());
-        // Implement in IdP layer.
-        // registerBeanDefinitionParser(SubjectDataConnectorParser.TYPE_NAME_RESOLVER, new SubjectDataConnectorParser());
+        registerBeanDefinitionParser(ContextDerivedDataConnectorParser.TYPE_NAME_RESOLVER,
+                new ContextDerivedDataConnectorParser());
+        registerBeanDefinitionParser(SubjectDataConnectorParser.TYPE_NAME_RESOLVER, new SubjectDataConnectorParser());
         registerBeanDefinitionParser(StorageServiceDataConnectorParser.TYPE_NAME,
                 new StorageServiceDataConnectorParser());
 
diff --git a/shib-attribute-resolver-spring/src/main/resources/schema/shibboleth-attribute-resolver.xsd b/shib-attribute-resolver-spring/src/main/resources/schema/shibboleth-attribute-resolver.xsd
index 8126677ef..9e9ff8757 100644
--- a/shib-attribute-resolver-spring/src/main/resources/schema/shibboleth-attribute-resolver.xsd
+++ b/shib-attribute-resolver-spring/src/main/resources/schema/shibboleth-attribute-resolver.xsd
@@ -3,7 +3,7 @@
     xmlns:resolver="urn:mace:shibboleth:2.0:resolver"
     xmlns:sec="urn:mace:shibboleth:2.0:security"
     targetNamespace="urn:mace:shibboleth:2.0:resolver"
-    elementFormDefault="qualified" version="4.1">
+    elementFormDefault="qualified" version="5.0">
 
     <import namespace="http://www.w3.org/XML/1998/namespace" schemaLocation="http://www.w3.org/2001/xml.xsd"/>
     <import namespace="urn:mace:shibboleth:2.0:security" schemaLocation="http://shibboleth.net/schema/idp/shibboleth-security.xsd"/>
@@ -1712,6 +1712,33 @@
         </complexContent>
     </complexType>
     
+    <complexType name="ContextDerived">
+        <annotation>
+            <documentation>A data connector to pull attributes from anywhere in the PRC tree</documentation>
+        </annotation>
+        <complexContent>
+            <extension base="resolver:BaseDataConnectorType">
+                <sequence>
+                    <element ref="resolver:FailoverDataConnector" minOccurs="0" maxOccurs="1"/>
+                </sequence>
+                <attribute name="noResultIsError" type="resolver:string">
+                    <annotation>
+                        <documentation>
+                            A boolean flag indicating whether an absence of any results will cause an error. If an error
+                            is raised and a failover dependency is defined for this connector the failover will be invoked.
+                            Default value is false.
+                        </documentation>
+                    </annotation>
+                </attribute>
+                <attribute name="attributesFunctionRef" type="resolver:string" use="required">
+                    <annotation>
+                        <documentation>The Function to generate the Attributes given a PRC</documentation>
+                    </annotation>
+                </attribute>
+            </extension>
+        </complexContent>
+    </complexType>
+    
     <complexType name="Subject">
         <annotation>
             <documentation>

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


More information about the commits mailing list