[java-identity-provider] branch master updated: IDP-1235 Add support to pe-resolve attributes
Rod Widdowson
rdw at steadingsoftware.com
Fri Sep 20 10:35:55 EDT 2019
This is an automated email from the git hooks/post-receive script.
rdw 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=fe0f207baf6e5cdf513ead9aa745e0bd506b53ef
The following commit(s) were added to refs/heads/master by this push:
new fe0f207 IDP-1235 Add support to pe-resolve attributes
fe0f207 is described below
commit fe0f207baf6e5cdf513ead9aa745e0bd506b53ef
Author: Rod Widdowson <rdw at steadingsoftware.com>
AuthorDate: Fri Sep 20 11:11:52 2019 +0100
IDP-1235 Add support to pe-resolve attributes
https://issues.shibboleth.net/jira/browse/IDP-1235
These are placed, for the duration of the resolve, into an AtttributeContext which is the
child of the AttributeResolutionContext. Configuration to follow.
---
.../resolver/impl/AttributeResolverImpl.java | 75 ++++++++++++++++++++--
.../resolver/impl/AttributeResolverImplTest.java | 53 +++++++++++++++
2 files changed, 123 insertions(+), 5 deletions(-)
diff --git a/idp-attribute-resolver-impl/src/main/java/net/shibboleth/idp/attribute/resolver/impl/AttributeResolverImpl.java b/idp-attribute-resolver-impl/src/main/java/net/shibboleth/idp/attribute/resolver/impl/AttributeResolverImpl.java
index 99d7911..b1a0b10 100644
--- a/idp-attribute-resolver-impl/src/main/java/net/shibboleth/idp/attribute/resolver/impl/AttributeResolverImpl.java
+++ b/idp-attribute-resolver-impl/src/main/java/net/shibboleth/idp/attribute/resolver/impl/AttributeResolverImpl.java
@@ -47,6 +47,7 @@ import net.shibboleth.ext.spring.service.AbstractServiceableComponent;
import net.shibboleth.idp.attribute.EmptyAttributeValue;
import net.shibboleth.idp.attribute.IdPAttribute;
import net.shibboleth.idp.attribute.IdPAttributeValue;
+import net.shibboleth.idp.attribute.context.AttributeContext;
import net.shibboleth.idp.attribute.resolver.AttributeDefinition;
import net.shibboleth.idp.attribute.resolver.AttributeResolver;
import net.shibboleth.idp.attribute.resolver.DataConnector;
@@ -90,8 +91,11 @@ public class AttributeResolverImpl extends AbstractServiceableComponent<Attribut
/** Data connectors defined for this resolver. */
@NonnullAfterInit private Map<String, DataConnector> dataConnectors;
- /** cache for the log prefix - to save multiple recalculations. */
+ /** Cache for the log prefix - to save multiple recalculations. */
@NonnullAfterInit private String logPrefix;
+
+ /** PreRequestedAttributes, resolved first and made available for late-comers. */
+ @NonnullAfterInit private List<String> preRequestedAttributes;
/** Whether to strip null attribute values. */
private boolean stripNulls;
@@ -128,6 +132,13 @@ public class AttributeResolverImpl extends AbstractServiceableComponent<Attribut
attributeDefinitions = ImmutableMap.copyOf(checkedDefinitions);
}
+ /** Sets the Attributes to be resolved "first" for this resolver.
+ * @param attrs what to set.
+ */
+ public void setPreRequestedAttributes(final List<String> attrs) {
+ preRequestedAttributes = Collections.unmodifiableList(attrs);
+ }
+
/**
* Gets the collection of attribute definitions for this resolver.
*
@@ -212,6 +223,7 @@ public class AttributeResolverImpl extends AbstractServiceableComponent<Attribut
*
* @throws ResolutionException thrown if there is a problem resolving the attributes for the subject
*/
+ // CheckStyle: CyclomaticComplexity OFF
@Override public void resolveAttributes(@Nonnull final AttributeResolutionContext resolutionContext)
throws ResolutionException {
ComponentSupport.ifNotInitializedThrowUninitializedComponentException(this);
@@ -221,11 +233,20 @@ public class AttributeResolverImpl extends AbstractServiceableComponent<Attribut
final AttributeResolverWorkContext workContext =
resolutionContext.getSubcontext(AttributeResolverWorkContext.class, true);
+ AttributeContext attributeContext = null;
final boolean timerStarted = startTimer(resolutionContext);
try {
log.debug("{} Initiating attribute resolution", logPrefix);
+ if (!preRequestedAttributes.isEmpty()) {
+ log.debug("Resolving pre-requested Attributes");
+ for (final String attributeId : preRequestedAttributes) {
+ resolveAttributeDefinition(attributeId, resolutionContext);
+ }
+ attributeContext = finalizePreResolvedAttributes(resolutionContext);
+ }
+
boolean hasExportingDataConnector = false;
for (final Entry<String, DataConnector> dataConnectorEntry : dataConnectors.entrySet()) {
@@ -256,12 +277,15 @@ public class AttributeResolverImpl extends AbstractServiceableComponent<Attribut
resolutionContext.getResolvedIdPAttributes().keySet());
} finally {
resolutionContext.removeSubcontext(workContext);
-
+ if (attributeContext != null) {
+ resolutionContext.removeSubcontext(attributeContext);
+ }
if (timerStarted) {
stopTimer(resolutionContext);
}
}
}
+ // CheckStyle: CyclomaticComplexity ON
/**
* Gets the list of attributes, identified by IDs, that should be resolved. If the
@@ -477,9 +501,10 @@ public class AttributeResolverImpl extends AbstractServiceableComponent<Attribut
* Helper function to collect suitably resolved attributes.
* @param resolvedAttributes bucket to collect attributes into
* @param workContext context to extract attributes from
+ * @param includeDependencyOnly whether we include dependencyOnly attributes
*/
private void collectResolvedAttributes(final Map<String, IdPAttribute> resolvedAttributes,
- final AttributeResolverWorkContext workContext) {
+ final AttributeResolverWorkContext workContext, final boolean includeDependencyOnly) {
for (final ResolvedAttributeDefinition definition : workContext.getResolvedIdPAttributeDefinitions().values()) {
final IdPAttribute resolvedAttribute = definition.getResolvedAttribute();
@@ -491,7 +516,7 @@ public class AttributeResolverImpl extends AbstractServiceableComponent<Attribut
}
// Remove dependency-only attributes.
- if (definition.isDependencyOnly()) {
+ if (definition.isDependencyOnly() && !includeDependencyOnly) {
log.debug("{} Removing result of attribute definition '{}', is marked as dependency only", logPrefix,
definition.getId());
continue;
@@ -584,13 +609,43 @@ public class AttributeResolverImpl extends AbstractServiceableComponent<Attribut
final Map<String, IdPAttribute> resolvedAttributes = new LazyMap<>();
- collectResolvedAttributes(resolvedAttributes, workContext);
+ collectResolvedAttributes(resolvedAttributes, workContext, false) ;
collectExportingDataConnectors(resolvedAttributes, workContext);
resolutionContext.setResolvedIdPAttributes(resolvedAttributes.values());
}
+ /**
+ * Collects the set of pre resolved attributes and places them in an {@link AttributeContext} which inserted
+ * as a child of the {@link AttributeResolutionContext} and also returned.
+ * <p>
+ * Values are also de-duplicated here.
+ * </p>
+ *
+ * @param resolutionContext current resolution context
+ * @return a populated Attribute Context, or nothing
+ */
+ @Nullable protected AttributeContext finalizePreResolvedAttributes(@Nonnull
+ final AttributeResolutionContext resolutionContext) {
+ Constraint.isNotNull(resolutionContext, "Attribute resolution context cannot be null");
+ final AttributeResolverWorkContext workContext =
+ resolutionContext.getSubcontext(AttributeResolverWorkContext.class, false);
+
+ final Map<String, IdPAttribute> resolvedAttributes = new LazyMap<>();
+
+ collectResolvedAttributes(resolvedAttributes, workContext, true);
+
+ if (resolvedAttributes.isEmpty()) {
+ return null;
+ }
+
+ final AttributeContext context = resolutionContext.getSubcontext(AttributeContext.class, true);
+ log.debug("Pre-resolved Attributes: {}", resolvedAttributes.keySet());
+ context.setIdPAttributes(resolvedAttributes.values());
+ return context;
+ }
+
/** {@inheritDoc} */
@Override protected void doInitialize() throws ComponentInitializationException {
super.doInitialize();
@@ -605,6 +660,16 @@ public class AttributeResolverImpl extends AbstractServiceableComponent<Attribut
throw new ComponentInitializationException("No Data Connectors provided");
}
+ if (null == preRequestedAttributes) {
+ preRequestedAttributes = Collections.emptyList();
+ } else {
+ for (final String requested : preRequestedAttributes) {
+ if (!attributeDefinitions.containsKey(requested)) {
+ throw new ComponentInitializationException("Definition for prerequested attribute '"
+ + requested + "' not present");
+ }
+ }
+ }
final HashSet<String> dependencyVerifiedPlugins = new HashSet<>();
for (final DataConnector plugin : dataConnectors.values()) {
diff --git a/idp-attribute-resolver-impl/src/test/java/net/shibboleth/idp/attribute/resolver/impl/AttributeResolverImplTest.java b/idp-attribute-resolver-impl/src/test/java/net/shibboleth/idp/attribute/resolver/impl/AttributeResolverImplTest.java
index 5c5b501..ce30405 100644
--- a/idp-attribute-resolver-impl/src/test/java/net/shibboleth/idp/attribute/resolver/impl/AttributeResolverImplTest.java
+++ b/idp-attribute-resolver-impl/src/test/java/net/shibboleth/idp/attribute/resolver/impl/AttributeResolverImplTest.java
@@ -20,6 +20,7 @@ package net.shibboleth.idp.attribute.resolver.impl;
import static org.testng.Assert.assertEquals;
import static org.testng.Assert.assertFalse;
import static org.testng.Assert.assertNotNull;
+import static org.testng.Assert.assertNull;
import static org.testng.Assert.assertTrue;
import static org.testng.Assert.fail;
@@ -42,6 +43,7 @@ import org.testng.annotations.Test;
import net.shibboleth.idp.attribute.EmptyAttributeValue;
import net.shibboleth.idp.attribute.EmptyAttributeValue.EmptyType;
+import net.shibboleth.idp.attribute.context.AttributeContext;
import net.shibboleth.idp.attribute.IdPAttribute;
import net.shibboleth.idp.attribute.IdPAttributeValue;
import net.shibboleth.idp.attribute.StringAttributeValue;
@@ -55,6 +57,7 @@ import net.shibboleth.idp.attribute.resolver.ResolverAttributeDefinitionDependen
import net.shibboleth.idp.attribute.resolver.ResolverDataConnectorDependency;
import net.shibboleth.idp.attribute.resolver.ad.impl.SimpleAttributeDefinition;
import net.shibboleth.idp.attribute.resolver.context.AttributeResolutionContext;
+import net.shibboleth.idp.attribute.resolver.context.AttributeResolverWorkContext;
import net.shibboleth.idp.attribute.resolver.dc.impl.StaticDataConnector;
import net.shibboleth.idp.saml.impl.TestSources;
import net.shibboleth.utilities.java.support.annotation.constraint.NotEmpty;
@@ -238,8 +241,37 @@ public class AttributeResolverImplTest {
resolver.resolveAttributes(context);
assertTrue(context.getResolvedIdPAttributes().isEmpty());
+ assertNull(context.getSubcontext(AttributeContext.class));
}
+ @Test public void resolvePreRequestAttribute() throws Exception {
+ final IdPAttribute attribute = new IdPAttribute("ad1");
+ attribute.setValues(Collections.singletonList(new StringAttributeValue("value1")));
+
+ final IdPAttribute attribute2 = new IdPAttribute("ad2");
+ attribute2.setValues(Collections.singletonList(new StringAttributeValue("value2")));
+
+ final LazySet<AttributeDefinition> definitions = new LazySet<>();
+ definitions.add(new MockAttributeDefinition("ad1", attribute));
+ definitions.add(new PreDefinedCheckingMockAttributeDefinition("ad2", attribute2, "ad1"));
+ for (AttributeDefinition defn:definitions) {
+ defn.initialize();
+ }
+
+ final AttributeResolverImpl resolver = newAttributeResolverImpl("foo", definitions, null);
+ resolver.setPreRequestedAttributes(List.of("ad1"));
+ resolver.initialize();
+
+ AttributeResolutionContext context = new AttributeResolutionContext();
+ resolver.resolveAttributes(context);
+
+ assertEquals(context.getResolvedIdPAttributes().size(), 2);
+ assertEquals(context.getResolvedIdPAttributes().get("ad1"), attribute);
+ assertEquals(context.getResolvedIdPAttributes().get("ad2"), attribute2);
+ assertNull(context.getSubcontext(AttributeContext.class));
+ }
+
+
/** Test that a simple resolve returns the expected results. */
@Test public void resolveFails() throws Exception {
log.debug("Log Resolve fails");
@@ -897,4 +929,25 @@ public class AttributeResolverImplTest {
result.setDataConnectors(connectors);
return result;
}
+
+ private static class PreDefinedCheckingMockAttributeDefinition extends MockAttributeDefinition {
+ private final String preResolvedName;
+
+ public PreDefinedCheckingMockAttributeDefinition(String id, IdPAttribute value, String preName)
+ throws ComponentInitializationException {
+ super(id, value);
+ preResolvedName = preName;
+ }
+
+ @Override
+ @Nullable protected IdPAttribute doAttributeDefinitionResolve(
+ @Nonnull final AttributeResolutionContext resolutionContext,
+ @Nonnull final AttributeResolverWorkContext workContext) throws ResolutionException {
+ AttributeContext context = resolutionContext.getSubcontext(AttributeContext.class);
+ assertNotNull(context);
+ assertEquals(context.getIdPAttributes().size(), 1);
+ assertTrue(context.getIdPAttributes().containsKey(preResolvedName));
+ return super.doAttributeDefinitionResolve(resolutionContext, workContext);
+ }
+ }
}
--
To stop receiving notification emails like this one, please contact
the administrator of this repository.
More information about the commits
mailing list