[java-identity-provider] branch main updated: Implement deferred class for Subject DataConnector and add unit tests.
Scott Cantor
cantor.2 at osu.edu
Mon Jul 11 20:19:51 UTC 2022
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=fa68b126bde727a63b37f6365dcd53ce1d3ca097
The following commit(s) were added to refs/heads/main by this push:
new fa68b126b Implement deferred class for Subject DataConnector and add unit tests.
fa68b126b is described below
commit fa68b126bde727a63b37f6365dcd53ce1d3ca097
Author: Scott Cantor <cantor.2 at osu.edu>
AuthorDate: Mon Jul 11 16:19:48 2022 -0400
Implement deferred class for Subject DataConnector and add unit tests.
---
.../impl/SubjectDerivedAttributesFunction.java | 178 ++++++++++++++++++++
.../impl/SubjectDataConnectorParserTest.java | 53 ++++++
.../context/impl/SubjectDataConnectorTest.java | 183 +++++++++++++++++++++
.../resolver/spring/dc/subjectAttributes.xml | 7 +
.../resolver/spring/dc/subjectAttributesNull.xml | 6 +
.../.settings/org.eclipse.wst.validation.prefs | 2 +
6 files changed, 429 insertions(+)
diff --git a/idp-authn-impl/src/main/java/net/shibboleth/idp/authn/context/impl/SubjectDerivedAttributesFunction.java b/idp-authn-impl/src/main/java/net/shibboleth/idp/authn/context/impl/SubjectDerivedAttributesFunction.java
new file mode 100644
index 000000000..5254b9495
--- /dev/null
+++ b/idp-authn-impl/src/main/java/net/shibboleth/idp/authn/context/impl/SubjectDerivedAttributesFunction.java
@@ -0,0 +1,178 @@
+/*
+ * 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.authn.context.impl;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.List;
+import java.util.function.Function;
+import java.util.stream.Collectors;
+
+import javax.annotation.Nonnull;
+import javax.annotation.Nullable;
+import javax.security.auth.Subject;
+
+import net.shibboleth.idp.attribute.IdPAttribute;
+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.AbstractIdentifiableInitializableComponent;
+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.messaging.context.navigate.ChildContextLookup;
+import org.opensaml.profile.context.ProfileRequestContext;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * A Function which returns {@link IdPAttribute}s derived from the {@link java.security.Principal}s
+ * associated with the request.
+ */
+public class SubjectDerivedAttributesFunction extends AbstractIdentifiableInitializableComponent implements
+ Function<ProfileRequestContext,List<IdPAttribute>> {
+
+ /** Logger. */
+ @Nonnull private final Logger log = LoggerFactory.getLogger(SubjectDerivedAttributesFunction.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;
+
+ /** Constructor. */
+ public SubjectDerivedAttributesFunction() {
+ scLookupStrategy = new ChildContextLookup<>(SubjectContext.class);
+ }
+
+ /**
+ * Gets whether the definition is being used during Subject Canonicalization, causing
+ * auto-installation of an alternate Subject lookup strategy.
+ *
+ * @return whether the definition is being used during Subject Canonicalization
+ */
+ public boolean isForCanonicalization() {
+ return forCanonicalization;
+ }
+
+ /**
+ * Sets whether the definition is being used during Subject Canonicalization, causing
+ * auto-installation of an alternate Subject lookup strategy.
+ *
+ * @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 net.shibboleth.idp.attribute.resolver.context.AttributeResolutionContext}.
+ *
+ * @param strategy strategy used to locate the {@link SubjectContext} associated with a given
+ * {@link net.shibboleth.idp.attribute.resolver.context.AttributeResolutionContext}
+ */
+ public void setSubjectContextLookupStrategy(
+ @Nonnull final Function<ProfileRequestContext,SubjectContext> strategy) {
+ ComponentSupport.ifInitializedThrowUnmodifiabledComponentException(this);
+
+ scLookupStrategy = Constraint.isNotNull(strategy, "SubjectContext lookup strategy cannot be null");
+ }
+
+ /**
+ * Sets the strategy used to locate a {@link Subject} associated with a given
+ * {@link net.shibboleth.idp.attribute.resolver.context.AttributeResolutionContext}.
+ *
+ * @param strategy strategy used to locate a {@link Subject} associated with a given
+ * {@link net.shibboleth.idp.attribute.resolver.context.AttributeResolutionContext}
+ */
+ public void setSubjectLookupStrategy(@Nullable final Function<ProfileRequestContext,Subject> strategy) {
+ ComponentSupport.ifInitializedThrowUnmodifiabledComponentException(this);
+
+ subjectLookupStrategy = strategy;
+ }
+
+ /** {@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} */
+ @Nullable public List<IdPAttribute> apply(@Nullable final ProfileRequestContext prc) {
+
+ Collection<Subject> subjects = Collections.emptyList();
+
+ if (subjectLookupStrategy != null) {
+ final Subject subject = subjectLookupStrategy.apply(prc);
+ if (subject == null) {
+ log.debug("{} No Subject returned from lookup, no attribute resolved", getLogPrefix());
+ return null;
+ }
+ subjects = Collections.singletonList(subject);
+ } else {
+ final SubjectContext cs = scLookupStrategy.apply(prc);
+ if (cs == null || cs.getSubjects().isEmpty()) {
+ log.debug("{} No Subjects returned from SubjectContext lookup, no attribute resolved", getLogPrefix());
+ return null;
+ }
+ subjects = cs.getSubjects();
+ }
+
+ final List<IdPAttribute> results = new ArrayList<>();
+
+ for (final Subject subject : subjects) {
+ results.addAll(subject.getPrincipals(IdPAttributePrincipal.class).stream()
+ .map(IdPAttributePrincipal::getAttribute)
+ .collect(Collectors.toUnmodifiableList()));
+ }
+
+ if (results.isEmpty()) {
+ log.info("{} No attributes resolved", getLogPrefix());
+ return null;
+ }
+ log.debug("{} Generated {} attributes", getLogPrefix(), results.size());
+
+ return results;
+ }
+
+ /**
+ * Produce a consistent log prefix.
+ *
+ * @return a consistent log prefix
+ */
+ private String getLogPrefix() {
+ return "SubjectDerivedDataConnector " + getId();
+ }
+
+}
\ No newline at end of file
diff --git a/idp-authn-impl/src/test/java/net/shibboleth/idp/authn/context/impl/SubjectDataConnectorParserTest.java b/idp-authn-impl/src/test/java/net/shibboleth/idp/authn/context/impl/SubjectDataConnectorParserTest.java
new file mode 100644
index 000000000..6bd4cf379
--- /dev/null
+++ b/idp-authn-impl/src/test/java/net/shibboleth/idp/authn/context/impl/SubjectDataConnectorParserTest.java
@@ -0,0 +1,53 @@
+/*
+ * 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.authn.context.impl;
+
+import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.assertTrue;
+
+import org.springframework.beans.factory.BeanCreationException;
+import org.testng.annotations.Test;
+
+import net.shibboleth.idp.attribute.resolver.dc.impl.ContextDerivedDataConnector;
+import net.shibboleth.idp.attribute.resolver.spring.dc.impl.SubjectDataConnectorParser;
+import net.shibboleth.idp.attribute.resolver.spring.testing.BaseAttributeDefinitionParserTest;
+
+/**
+ * test for {@link SubjectDataConnectorParser}
+ */
+ at SuppressWarnings("javadoc")
+public class SubjectDataConnectorParserTest extends BaseAttributeDefinitionParserTest {
+
+ @Test public void simple() {
+ final ContextDerivedDataConnector connector = getDataConnector("resolver/subjectAttributes.xml", ContextDerivedDataConnector.class);
+
+ assertEquals(connector.getExportAttributes().size(), 2);
+ assertTrue(connector.getExportAttributes().contains("foo"));
+ assertTrue(connector.getExportAttributes().contains("bar"));
+ assertTrue(connector.isNoResultIsError());
+
+ final SubjectDerivedAttributesFunction fn = (SubjectDerivedAttributesFunction) connector.getAttributesFunction();
+
+ assertTrue(fn.isForCanonicalization());
+ }
+
+ @Test(expectedExceptions = {BeanCreationException.class}) public void emptyNoResultIsError() {
+ getDataConnector("resolver/subjectAttributesNull.xml", ContextDerivedDataConnector.class);
+ }
+
+}
\ No newline at end of file
diff --git a/idp-authn-impl/src/test/java/net/shibboleth/idp/authn/context/impl/SubjectDataConnectorTest.java b/idp-authn-impl/src/test/java/net/shibboleth/idp/authn/context/impl/SubjectDataConnectorTest.java
new file mode 100644
index 000000000..42e07866a
--- /dev/null
+++ b/idp-authn-impl/src/test/java/net/shibboleth/idp/authn/context/impl/SubjectDataConnectorTest.java
@@ -0,0 +1,183 @@
+/*
+ * 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.authn.context.impl;
+
+import static org.testng.Assert.*;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+
+import javax.security.auth.Subject;
+
+import org.testng.annotations.Test;
+
+import net.shibboleth.idp.attribute.IdPAttribute;
+import net.shibboleth.idp.attribute.IdPAttributeValue;
+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.attribute.resolver.dc.impl.ContextDerivedDataConnector;
+import net.shibboleth.idp.attribute.resolver.testing.TestSources;
+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;
+import net.shibboleth.utilities.java.support.component.ComponentInitializationException;
+
+/** Test for {@link SubjectDataConnector}. */
+ at SuppressWarnings("javadoc")
+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));
+ list.add(new StringAttributeValue(SIMPLE_VALUE + "2"));
+
+ final IdPAttribute attr = new IdPAttribute("wibble");
+ attr.setValues(list);
+
+ final SubjectDerivedAttributesFunction fn = new SubjectDerivedAttributesFunction();
+ fn.setId("test");
+ fn.initialize();
+
+ final ContextDerivedDataConnector defn = new ContextDerivedDataConnector();
+ defn.setAttributesFunction(fn);
+ defn.setId("pDAD");
+ defn.initialize();
+
+ final AttributeResolutionContext ctx =
+ TestSources.createResolutionContext(TestSources.PRINCIPAL_ID, TestSources.IDP_ENTITY_ID,
+ TestSources.SP_ENTITY_ID);
+ final SubjectContext sc = ctx.getParent().getSubcontext(SubjectContext.class, true);
+ final Map<String, AuthenticationResult> authnResults = sc.getAuthenticationResults();
+ final Subject subject = new Subject();
+ subject.getPrincipals().add(new IdPAttributePrincipal(attr));
+ subject.getPrincipals().add(new AuthenticationMethodPrincipal(SIMPLE_VALUE + "2"));
+ authnResults.put("one", new AuthenticationResult("1", 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 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 SubjectDerivedAttributesFunction fn = new SubjectDerivedAttributesFunction();
+ fn.setId("test");
+ fn.setForCanonicalization(true);
+ fn.initialize();
+
+ final ContextDerivedDataConnector defn = new ContextDerivedDataConnector();
+ defn.setId("pDAD");
+ defn.setAttributesFunction(fn);
+ 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")));
+ }
+
+ @SuppressWarnings("removal")
+ @Test public void emptyOk() throws ComponentInitializationException, ResolutionException {
+
+ final SubjectDerivedAttributesFunction fn = new SubjectDerivedAttributesFunction();
+ fn.setId("test");
+ fn.setForCanonicalization(true);
+ fn.initialize();
+
+ final ContextDerivedDataConnector defn = new ContextDerivedDataConnector();
+ defn.setExportAllAttributes(true);
+ defn.setId("pDAD");
+ defn.setAttributesFunction(fn);
+ defn.initialize();
+
+ final AttributeResolutionContext ctx =
+ TestSources.createResolutionContext(TestSources.PRINCIPAL_ID, TestSources.IDP_ENTITY_ID,
+ TestSources.SP_ENTITY_ID);
+ final SubjectContext sc = ctx.getParent().getSubcontext(SubjectContext.class, true);
+ final Map<String, AuthenticationResult> authnResults = sc.getAuthenticationResults();
+ final Subject subject = new Subject();
+ subject.getPrincipals().add(new AuthenticationMethodPrincipal(SIMPLE_VALUE + "2"));
+ authnResults.put("one", new AuthenticationResult("1", subject));
+
+ final Map<String,IdPAttribute> results = defn.resolve(ctx);
+ assertNull(results);
+ }
+
+ @SuppressWarnings("removal")
+ @Test(expectedExceptions=ResolutionException.class)
+ public void emptyError() throws ComponentInitializationException, ResolutionException {
+
+ final SubjectDerivedAttributesFunction fn = new SubjectDerivedAttributesFunction();
+ fn.setId("test");
+ fn.initialize();
+
+ final ContextDerivedDataConnector defn = new ContextDerivedDataConnector();
+ defn.setId("pDAD");
+ defn.setExportAllAttributes(true);
+ defn.setNoResultIsError(true);
+ defn.setAttributesFunction(fn);
+ defn.initialize();
+
+ final AttributeResolutionContext ctx =
+ TestSources.createResolutionContext(TestSources.PRINCIPAL_ID, TestSources.IDP_ENTITY_ID,
+ TestSources.SP_ENTITY_ID);
+ final SubjectContext sc = ctx.getParent().getSubcontext(SubjectContext.class, true);
+ final Map<String, AuthenticationResult> authnResults = sc.getAuthenticationResults();
+ final Subject subject = new Subject();
+ subject.getPrincipals().add(new AuthenticationMethodPrincipal(SIMPLE_VALUE + "2"));
+ authnResults.put("one", new AuthenticationResult("1", subject));
+
+ defn.resolve(ctx);
+ }
+
+}
\ No newline at end of file
diff --git a/idp-authn-impl/src/test/resources/net/shibboleth/idp/attribute/resolver/spring/dc/subjectAttributes.xml b/idp-authn-impl/src/test/resources/net/shibboleth/idp/attribute/resolver/spring/dc/subjectAttributes.xml
new file mode 100644
index 000000000..73f757ef9
--- /dev/null
+++ b/idp-authn-impl/src/test/resources/net/shibboleth/idp/attribute/resolver/spring/dc/subjectAttributes.xml
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<DataConnector id="subjectAttributes" xsi:type="Subject"
+ 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-authn-impl/src/test/resources/net/shibboleth/idp/attribute/resolver/spring/dc/subjectAttributesNull.xml b/idp-authn-impl/src/test/resources/net/shibboleth/idp/attribute/resolver/spring/dc/subjectAttributesNull.xml
new file mode 100644
index 000000000..e2f5e1203
--- /dev/null
+++ b/idp-authn-impl/src/test/resources/net/shibboleth/idp/attribute/resolver/spring/dc/subjectAttributesNull.xml
@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<DataConnector id="subjectAttributes" xsi:type="Subject"
+ xmlns="urn:mace:shibboleth:2.0:resolver" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ exportAttributes="foo bar"
+ noResultIsError=" "
+ xsi:schemaLocation="urn:mace:shibboleth:2.0:resolver http://shibboleth.net/schema/idp/shibboleth-attribute-resolver.xsd" />
diff --git a/idp-spring/.settings/org.eclipse.wst.validation.prefs b/idp-spring/.settings/org.eclipse.wst.validation.prefs
new file mode 100644
index 000000000..04cad8cb7
--- /dev/null
+++ b/idp-spring/.settings/org.eclipse.wst.validation.prefs
@@ -0,0 +1,2 @@
+disabled=06target
+eclipse.preferences.version=1
--
To stop receiving notification emails like this one, please contact
the administrator of this repository.
More information about the commits
mailing list