[java-identity-provider] branch master updated: IDP-1446 - Create CAS transcoders
Scott Cantor
cantor.2 at osu.edu
Tue May 14 20:45:15 EDT 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=e56cc890ce4c83b9410e3d6fa77903ee559b9ed5
The following commit(s) were added to refs/heads/master by this push:
new e56cc89 IDP-1446 - Create CAS transcoders
e56cc89 is described below
commit e56cc890ce4c83b9410e3d6fa77903ee559b9ed5
Author: Scott Cantor <cantor.2 at osu.edu>
AuthorDate: Tue May 14 20:45:09 2019 -0400
IDP-1446 - Create CAS transcoders
https://issues.shibboleth.net/jira/browse/IDP-1446
Replace CAS attribute logic with new classes.
---
.../idp/cas/protocol/TicketValidationResponse.java | 45 +++---
.../BuildSamlValidationSuccessMessageAction.java | 6 +-
.../PrepareTicketValidationResponseAction.java | 154 ++++++++++++++++++---
.../system/flows/cas/validate-abstract-beans.xml | 3 +-
.../resources/system/views/cas/validateSuccess.vm | 8 +-
5 files changed, 165 insertions(+), 51 deletions(-)
diff --git a/idp-cas-api/src/main/java/net/shibboleth/idp/cas/protocol/TicketValidationResponse.java b/idp-cas-api/src/main/java/net/shibboleth/idp/cas/protocol/TicketValidationResponse.java
index a42a72b..a812392 100644
--- a/idp-cas-api/src/main/java/net/shibboleth/idp/cas/protocol/TicketValidationResponse.java
+++ b/idp-cas-api/src/main/java/net/shibboleth/idp/cas/protocol/TicketValidationResponse.java
@@ -17,14 +17,18 @@
package net.shibboleth.idp.cas.protocol;
+import net.shibboleth.idp.cas.attribute.Attribute;
+import net.shibboleth.utilities.java.support.annotation.constraint.NonnullElements;
+import net.shibboleth.utilities.java.support.annotation.constraint.NotEmpty;
+import net.shibboleth.utilities.java.support.annotation.constraint.NotLive;
+import net.shibboleth.utilities.java.support.annotation.constraint.Unmodifiable;
import net.shibboleth.utilities.java.support.logic.Constraint;
import net.shibboleth.utilities.java.support.primitive.StringSupport;
import java.util.ArrayList;
+import java.util.Collection;
import java.util.Collections;
-import java.util.HashMap;
import java.util.List;
-import java.util.Map;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
@@ -40,21 +44,26 @@ public class TicketValidationResponse extends AbstractProtocolResponse {
@Nullable private String userName;
/** User attributes. */
- @Nonnull private Map<String, List<String>> attributes = new HashMap<>();
+ @Nonnull @NonnullElements private final List<Attribute> attributes;
/** Proxy granting ticket IOU. */
@Nullable private String pgtIou;
/** Proxies traversed. */
- @Nonnull private List<String> proxies = new ArrayList<>();
+ @Nonnull @NonnullElements private final List<String> proxies;
+ /** Constructor. */
+ public TicketValidationResponse() {
+ attributes = new ArrayList<>();
+ proxies = new ArrayList<>();
+ }
/**
* Get the non-null subject principal on ticket validation success.
*
* @return non-null subject principal on ticket validation success
*/
- @Nullable public String getUserName() {
+ @Nullable @NotEmpty public String getUserName() {
return userName;
}
@@ -63,32 +72,26 @@ public class TicketValidationResponse extends AbstractProtocolResponse {
*
* @param user non-null subject principal on ticket validation success
*/
- public void setUserName(@Nonnull final String user) {
+ public void setUserName(@Nonnull @NotEmpty final String user) {
userName = Constraint.isNotNull(user, "Username cannot be null");
}
/**
- * Get the Immutable map of user attributes.
+ * Get the immutable collection of user attributes.
*
- * @return immutable map of user attributes
+ * @return immutable collection of user attributes
*/
- @Nonnull public Map<String, List<String>> getAttributes() {
- return Collections.unmodifiableMap(attributes);
+ @Nonnull @NonnullElements @NotLive @Unmodifiable public Collection<Attribute> getAttributes() {
+ return Collections.unmodifiableList(attributes);
}
/**
- * Add an attribute to the attribute mapping.
+ * Add an attribute to the attribute collection.
*
- * @param name attribute name
- * @param value attribute value
+ * @param attribute the attribute
*/
- public void addAttribute(@Nonnull final String name, @Nonnull final String value) {
- List<String> values = attributes.get(name);
- if (values == null) {
- values = new ArrayList<>();
- attributes.put(name, values);
- }
- values.add(value);
+ public void addAttribute(@Nonnull final Attribute attribute) {
+ attributes.add(attribute);
}
/**
@@ -114,7 +117,7 @@ public class TicketValidationResponse extends AbstractProtocolResponse {
*
* @return immutable list of proxies traversed in order of most recent to last recent
*/
- @Nonnull public List<String> getProxies() {
+ @Nonnull @NonnullElements @NotLive @Unmodifiable public List<String> getProxies() {
return Collections.unmodifiableList(proxies);
}
diff --git a/idp-cas-impl/src/main/java/net/shibboleth/idp/cas/flow/impl/BuildSamlValidationSuccessMessageAction.java b/idp-cas-impl/src/main/java/net/shibboleth/idp/cas/flow/impl/BuildSamlValidationSuccessMessageAction.java
index 4f6aabd..cf02a88 100644
--- a/idp-cas-impl/src/main/java/net/shibboleth/idp/cas/flow/impl/BuildSamlValidationSuccessMessageAction.java
+++ b/idp-cas-impl/src/main/java/net/shibboleth/idp/cas/flow/impl/BuildSamlValidationSuccessMessageAction.java
@@ -144,11 +144,11 @@ public class BuildSamlValidationSuccessMessageAction extends AbstractOutgoingSam
final AttributeStatement attrStatement = newSAMLObject(
AttributeStatement.class, AttributeStatement.DEFAULT_ELEMENT_NAME);
attrStatement.setSubject(newSubject(state.getPrincipalName()));
- for (final String attrName : ticketResponse.getAttributes().keySet()) {
+ for (final net.shibboleth.idp.cas.attribute.Attribute casAttr : ticketResponse.getAttributes()) {
final Attribute attribute = newSAMLObject(Attribute.class, Attribute.DEFAULT_ELEMENT_NAME);
- attribute.setAttributeName(attrName);
+ attribute.setAttributeName(casAttr.getName());
attribute.setAttributeNamespace(NAMESPACE);
- for (final String value : ticketResponse.getAttributes().get(attrName)) {
+ for (final String value : casAttr.getValues()) {
attribute.getAttributeValues().add(newAttributeValue(value));
}
attrStatement.getAttributes().add(attribute);
diff --git a/idp-cas-impl/src/main/java/net/shibboleth/idp/cas/flow/impl/PrepareTicketValidationResponseAction.java b/idp-cas-impl/src/main/java/net/shibboleth/idp/cas/flow/impl/PrepareTicketValidationResponseAction.java
index 339cfd8..a82acf2 100644
--- a/idp-cas-impl/src/main/java/net/shibboleth/idp/cas/flow/impl/PrepareTicketValidationResponseAction.java
+++ b/idp-cas-impl/src/main/java/net/shibboleth/idp/cas/flow/impl/PrepareTicketValidationResponseAction.java
@@ -17,26 +17,47 @@
package net.shibboleth.idp.cas.flow.impl;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
import java.util.function.Function;
import javax.annotation.Nonnull;
+import net.shibboleth.idp.attribute.AttributeEncodingException;
import net.shibboleth.idp.attribute.IdPAttribute;
-import net.shibboleth.idp.attribute.IdPAttributeValue;
import net.shibboleth.idp.attribute.context.AttributeContext;
+import net.shibboleth.idp.attribute.transcoding.AttributeTranscoder;
+import net.shibboleth.idp.attribute.transcoding.AttributeTranscoderRegistry;
+import net.shibboleth.idp.attribute.transcoding.TranscoderSupport;
+import net.shibboleth.idp.attribute.transcoding.TranscodingRule;
+import net.shibboleth.idp.cas.attribute.Attribute;
+import net.shibboleth.idp.cas.attribute.transcoding.impl.CASStringAttributeTranscoder;
import net.shibboleth.idp.cas.config.impl.ConfigLookupFunction;
import net.shibboleth.idp.cas.config.impl.ValidateConfiguration;
import net.shibboleth.idp.cas.protocol.ProtocolError;
import net.shibboleth.idp.cas.protocol.TicketValidationRequest;
import net.shibboleth.idp.cas.protocol.TicketValidationResponse;
import net.shibboleth.idp.cas.ticket.TicketPrincipalLookupFunction;
+import net.shibboleth.idp.profile.IdPEventIds;
import net.shibboleth.idp.profile.context.RelyingPartyContext;
+import net.shibboleth.utilities.java.support.annotation.constraint.Live;
+import net.shibboleth.utilities.java.support.annotation.constraint.NonnullAfterInit;
+import net.shibboleth.utilities.java.support.annotation.constraint.NonnullElements;
+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 net.shibboleth.utilities.java.support.service.ReloadableService;
+import net.shibboleth.utilities.java.support.service.ServiceableComponent;
+
import org.opensaml.messaging.context.navigate.ChildContextLookup;
+import org.opensaml.profile.action.ActionSupport;
import org.opensaml.profile.context.ProfileRequestContext;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
-import org.springframework.webflow.execution.Event;
-import org.springframework.webflow.execution.RequestContext;
+
+import com.google.common.base.Predicates;
+import com.google.common.collect.Collections2;
/**
* Prepares {@link TicketValidationResponse} for use in CAS protocol response views. Possible outcomes:
@@ -54,25 +75,58 @@ public class PrepareTicketValidationResponseAction extends
@Nonnull private final Logger log = LoggerFactory.getLogger(PrepareTicketValidationResponseAction.class);
/** Function used to retrieve AttributeContext. */
- @Nonnull
- private Function<ProfileRequestContext,AttributeContext> attributeContextFunction =
- new ChildContextLookup<>(AttributeContext.class, true).compose(
- new ChildContextLookup<>(RelyingPartyContext.class));
+ @Nonnull private Function<ProfileRequestContext,AttributeContext> attributeContextFunction;
/** Function used to retrieve subject principal. */
- @Nonnull private Function<ProfileRequestContext,String> principalLookupFunction =
- new TicketPrincipalLookupFunction();
+ @Nonnull private Function<ProfileRequestContext,String> principalLookupFunction;
/** Profile configuration lookup function. */
- @Nonnull private final ConfigLookupFunction<ValidateConfiguration> configLookupFunction =
- new ConfigLookupFunction<>(ValidateConfiguration.class);
-
+ @Nonnull private final ConfigLookupFunction<ValidateConfiguration> configLookupFunction;
+
+ /** Transcoder registry service object. */
+ @NonnullAfterInit private ReloadableService<AttributeTranscoderRegistry> transcoderRegistry;
+
+ /** Fallback rule that does a simple/default encode. */
+ @NonnullAfterInit private TranscodingRule defaultTranscodingRule;
+
+ /** Constructor. */
+ public PrepareTicketValidationResponseAction() {
+ attributeContextFunction =
+ new ChildContextLookup<>(AttributeContext.class, true).compose(
+ new ChildContextLookup<>(RelyingPartyContext.class));
+ principalLookupFunction = new TicketPrincipalLookupFunction();
+ configLookupFunction = new ConfigLookupFunction<>(ValidateConfiguration.class);
+ }
- @Nonnull
+ /**
+ * Sets the registry of transcoding rules to apply to encode attributes.
+ *
+ * @param registry registry service interface
+ */
+ public void setTranscoderRegistry(@Nonnull final ReloadableService<AttributeTranscoderRegistry> registry) {
+ ComponentSupport.ifInitializedThrowUnmodifiabledComponentException(this);
+
+ transcoderRegistry = Constraint.isNotNull(registry, "AttributeTranscoderRegistry cannot be null");
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ protected void doInitialize() throws ComponentInitializationException {
+ super.doInitialize();
+
+ if (transcoderRegistry == null) {
+ throw new ComponentInitializationException("AttributeTranscoderRegistry cannot be null");
+ }
+
+ final AttributeTranscoder transcoder = new CASStringAttributeTranscoder();
+ transcoder.initialize();
+ defaultTranscodingRule = new TranscodingRule(
+ Collections.singletonMap(AttributeTranscoderRegistry.PROP_TRANSCODER, transcoder));
+ }
+
+ /** {@inheritDoc} */
@Override
- protected Event doExecute(
- final @Nonnull RequestContext springRequestContext,
- final @Nonnull ProfileRequestContext profileRequestContext) {
+ protected void doExecute(final @Nonnull ProfileRequestContext profileRequestContext) {
final AttributeContext ac = attributeContextFunction.apply(profileRequestContext);
if (ac == null) {
@@ -105,12 +159,68 @@ public class PrepareTicketValidationResponseAction extends
final TicketValidationResponse response = getCASResponse(profileRequestContext);
response.setUserName(principal);
- for (final IdPAttribute attribute : ac.getIdPAttributes().values()) {
- log.debug("Processing {}", attribute);
- for (final IdPAttributeValue<?> value : attribute.getValues()) {
- response.addAttribute(attribute.getId(), value.getValue().toString());
+
+ final Collection<IdPAttribute> inputAttributes = ac.getIdPAttributes().values();
+ final ArrayList<Attribute> encodedAttributes = new ArrayList<>(inputAttributes.size());
+
+ ServiceableComponent<AttributeTranscoderRegistry> component = null;
+ try {
+ component = transcoderRegistry.getServiceableComponent();
+ if (component == null) {
+ log.error("{} Attribute transoding service unavailable", getLogPrefix());
+ ActionSupport.buildEvent(profileRequestContext, IdPEventIds.UNABLE_ENCODE_ATTRIBUTE);
+ return;
+ }
+ for (final IdPAttribute attribute : Collections2.filter(inputAttributes, Predicates.notNull())) {
+ encodeAttribute(component.getComponent(), profileRequestContext, attribute, encodedAttributes);
+ }
+ } finally {
+ if (null != component) {
+ component.unpinComponent();
+ }
+ }
+
+ encodedAttributes.forEach(a -> response.addAttribute(a));
+ }
+
+ /**
+ * Access the registry of transcoding rules to transform the input attribute into a target type.
+ *
+ * @param registry registry of transcoding rules
+ * @param profileRequestContext current profile request context
+ * @param attribute input attribute
+ * @param results collection to add results to
+ *
+ * @return number of results added
+ */
+ protected int encodeAttribute(@Nonnull final AttributeTranscoderRegistry registry,
+ @Nonnull final ProfileRequestContext profileRequestContext, @Nonnull final IdPAttribute attribute,
+ @Nonnull @NonnullElements @Live final Collection<Attribute> results) {
+
+ Collection<TranscodingRule> transcodingRules = registry.getTranscodingRules(attribute, Attribute.class);
+ if (transcodingRules.isEmpty()) {
+ log.debug("{} Attribute {} does not have any transcoding rules, applying default", getLogPrefix(),
+ attribute.getId());
+ transcodingRules = Collections.singletonList(defaultTranscodingRule);
+ }
+
+ int count = 0;
+
+ for (final TranscodingRule rules : transcodingRules) {
+ try {
+ final AttributeTranscoder<Attribute> transcoder = TranscoderSupport.<Attribute>getTranscoder(rules);
+ final Attribute encodedAttribute =
+ transcoder.encode(profileRequestContext, attribute, Attribute.class, rules);
+ if (encodedAttribute != null) {
+ results.add(encodedAttribute);
+ count++;
+ }
+ } catch (final AttributeEncodingException e) {
+ log.debug("{} Unable to encode attribute {}", getLogPrefix(), attribute.getId(), e);
}
}
- return null;
+
+ return count;
}
-}
+
+}
\ No newline at end of file
diff --git a/idp-conf/src/main/resources/system/flows/cas/validate-abstract-beans.xml b/idp-conf/src/main/resources/system/flows/cas/validate-abstract-beans.xml
index 53f4d17..a4a7c62 100644
--- a/idp-conf/src/main/resources/system/flows/cas/validate-abstract-beans.xml
+++ b/idp-conf/src/main/resources/system/flows/cas/validate-abstract-beans.xml
@@ -38,7 +38,8 @@
c:ticketService="#{getObject('shibboleth.CASTicketService') ?: getObject('shibboleth.DefaultCASTicketService')}" />
<bean id="PrepareTicketValidationResponse"
- class="net.shibboleth.idp.cas.flow.impl.PrepareTicketValidationResponseAction" />
+ class="net.shibboleth.idp.cas.flow.impl.PrepareTicketValidationResponseAction"
+ p:transcoderRegistry-ref="shibboleth.AttributeRegistryService" />
<bean id="UpdateIdPSessionWithSPSession"
class="net.shibboleth.idp.cas.flow.impl.UpdateIdPSessionWithSPSessionAction"
diff --git a/idp-conf/src/main/resources/system/views/cas/validateSuccess.vm b/idp-conf/src/main/resources/system/views/cas/validateSuccess.vm
index 0877b2c..5a9b0a4 100644
--- a/idp-conf/src/main/resources/system/views/cas/validateSuccess.vm
+++ b/idp-conf/src/main/resources/system/views/cas/validateSuccess.vm
@@ -4,11 +4,11 @@
#if($ticketValidationResponse.pgtIou)
<cas:proxyGrantingTicket>$escapeUtils.escapeXml($ticketValidationResponse.pgtIou)</cas:proxyGrantingTicket>
#end
- #if($ticketValidationResponse.attributes.size() > 0)
+ #if(!$ticketValidationResponse.attributes.isEmpty())
<cas:attributes>
- #foreach($attr in $ticketValidationResponse.attributes.keySet())
- #foreach($value in $ticketValidationResponse.attributes.get($attr))
- <cas:$escapeUtils.escapeXml($attr)>$escapeUtils.escapeXml($value)</cas:$escapeUtils.escapeXml($attr)>
+ #foreach($attr in $ticketValidationResponse.attributes)
+ #foreach($value in $$attr.values)
+ <cas:$escapeUtils.escapeXml($attr.name)>$escapeUtils.escapeXml($value)</cas:$escapeUtils.escapeXml($attr.name)>
#end
#end
</cas:attributes>
--
To stop receiving notification emails like this one, please contact
the administrator of this repository.
More information about the commits
mailing list