[java-identity-provider] branch master updated: IDP-1446 - Create CAS transcoders
Scott Cantor
cantor.2 at osu.edu
Tue May 14 19:30:51 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=d6b0e7480aab52ce7bf7b59e3349ba1b0d8f838a
The following commit(s) were added to refs/heads/master by this push:
new d6b0e74 IDP-1446 - Create CAS transcoders
d6b0e74 is described below
commit d6b0e7480aab52ce7bf7b59e3349ba1b0d8f838a
Author: Scott Cantor <cantor.2 at osu.edu>
AuthorDate: Tue May 14 19:30:43 2019 -0400
IDP-1446 - Create CAS transcoders
https://issues.shibboleth.net/jira/browse/IDP-1446
String and ScopeString CAS transcoders.
---
idp-cas-api/pom.xml | 10 +
.../attribute/AbstractCASAttributeTranscoder.java | 237 ++++++++++++++++++++
.../shibboleth/idp/cas/attribute/Attribute.java | 74 ++++++
.../idp/cas/attribute/CASAttributeTranscoder.java | 33 +++
.../shibboleth/idp/cas/attribute/package-info.java | 22 ++
.../impl/CASScopedStringAttributeTranscoder.java | 83 +++++++
.../impl/CASStringAttributeTranscoder.java | 73 ++++++
.../attribute/transcoding/impl/package-info.java | 22 ++
.../CASScopedStringAttributeTranscoderTest.java | 248 +++++++++++++++++++++
.../impl/CASStringAttributeTranscoderTest.java | 225 +++++++++++++++++++
.../system/conf/attribute-registry-system.xml | 8 +
11 files changed, 1035 insertions(+)
diff --git a/idp-cas-api/pom.xml b/idp-cas-api/pom.xml
index bb6ef29..df7b5a6 100644
--- a/idp-cas-api/pom.xml
+++ b/idp-cas-api/pom.xml
@@ -23,6 +23,16 @@
<dependencies>
<!-- Compile Dependencies -->
<dependency>
+ <groupId>${project.groupId}</groupId>
+ <artifactId>idp-attribute-api</artifactId>
+ <version>${project.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>${project.groupId}</groupId>
+ <artifactId>idp-saml-api</artifactId>
+ <version>${project.version}</version>
+ </dependency>
+ <dependency>
<groupId>${opensaml.groupId}</groupId>
<artifactId>opensaml-profile-api</artifactId>
</dependency>
diff --git a/idp-cas-api/src/main/java/net/shibboleth/idp/cas/attribute/AbstractCASAttributeTranscoder.java b/idp-cas-api/src/main/java/net/shibboleth/idp/cas/attribute/AbstractCASAttributeTranscoder.java
new file mode 100644
index 0000000..fa2dc67
--- /dev/null
+++ b/idp-cas-api/src/main/java/net/shibboleth/idp/cas/attribute/AbstractCASAttributeTranscoder.java
@@ -0,0 +1,237 @@
+/*
+ * 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.cas.attribute;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.function.Function;
+
+import javax.annotation.Nonnull;
+import javax.annotation.Nullable;
+
+import net.shibboleth.idp.attribute.AttributeDecodingException;
+import net.shibboleth.idp.attribute.AttributeEncodingException;
+import net.shibboleth.idp.attribute.IdPAttribute;
+import net.shibboleth.idp.attribute.IdPAttributeValue;
+import net.shibboleth.idp.attribute.transcoding.AbstractAttributeTranscoder;
+import net.shibboleth.idp.attribute.transcoding.AttributeTranscoderRegistry;
+import net.shibboleth.idp.attribute.transcoding.TranscodingRule;
+import net.shibboleth.utilities.java.support.annotation.constraint.NonnullElements;
+
+import org.opensaml.profile.context.ProfileRequestContext;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.google.common.base.Strings;
+
+/**
+ * Base class for transcoders that support CAS attributes.
+ *
+ * @param <EncodedType> the type of data that can be handled by the transcoder
+ */
+public abstract class AbstractCASAttributeTranscoder<EncodedType extends IdPAttributeValue>
+ extends AbstractAttributeTranscoder<Attribute> implements CASAttributeTranscoder {
+
+ /** Class logger. */
+ @Nonnull private final Logger log = LoggerFactory.getLogger(AbstractCASAttributeTranscoder.class);
+
+ /** {@inheritDoc} */
+ @Nonnull public Class<Attribute> getEncodedType() {
+ return Attribute.class;
+ }
+
+ /** {@inheritDoc} */
+ @Nullable public String getEncodedName(@Nonnull final TranscodingRule rule) {
+
+ // CAS naming should be based on only what needs to be available from the properties alone.
+ final String name = rule.getOrDefault(PROP_NAME, String.class,
+ rule.get(AttributeTranscoderRegistry.PROP_ID, String.class));
+ if (name != null) {
+ return new NamingFunction().apply(new Attribute(name));
+ } else {
+ return null;
+ }
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ @Nullable public Attribute doEncode(@Nullable final ProfileRequestContext profileRequestContext,
+ @Nonnull final IdPAttribute attribute, @Nonnull final Class<? extends Attribute> to,
+ @Nonnull final TranscodingRule rule) throws AttributeEncodingException {
+
+ final String attributeId = attribute.getId();
+
+ log.debug("Beginning to encode attribute {}", attributeId);
+
+ final String name = rule.getOrDefault(PROP_NAME, String.class, attributeId);
+
+ final Attribute casAttribute = new Attribute(name);
+
+ for (final IdPAttributeValue o : attribute.getValues()) {
+ if (o == null) {
+ // filtered out upstream leave in test for sanity
+ log.debug("Skipping null value of attribute {}", attributeId);
+ continue;
+ }
+
+ if (!canEncodeValue(attribute, o)) {
+ log.warn("Skipping value of attribute '{}'; Type {} cannot be encoded by this encoder ({}).",
+ attributeId, o.getClass().getSimpleName(), this.getClass().getSimpleName());
+ continue;
+ }
+
+ final EncodedType attributeValue = (EncodedType) o;
+ final String casAttributeValue = encodeValue(profileRequestContext, attribute, rule, attributeValue);
+ if (casAttributeValue == null) {
+ log.debug("Skipping null value for attribute {}", attributeId);
+ } else {
+ casAttribute.getValues().add(casAttributeValue);
+ }
+ }
+
+ if (!attribute.getValues().isEmpty() && casAttribute.getValues().isEmpty()) {
+ throw new AttributeEncodingException("Failed to encode any values for attribute " + attribute.getId());
+ }
+
+ log.debug("Encoded {} values for attribute {}", casAttribute.getValues().size(), attributeId);
+ return casAttribute;
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ @Nullable public IdPAttribute doDecode(@Nullable final ProfileRequestContext profileRequestContext,
+ @Nonnull final Attribute input, @Nonnull final TranscodingRule rule) throws AttributeDecodingException {
+
+ final String attributeName = getEncodedName(rule);
+
+ log.debug("Beginning to decode attribute {}", attributeName);
+
+ final List<IdPAttributeValue<?>> idpAttributeValues = new ArrayList<>();
+
+ for (final String o : input.getValues()) {
+ if (o == null) {
+ // filtered out upstream leave in test for sanity
+ log.debug("Skipping null value of attribute {}", attributeName);
+ continue;
+ }
+
+ final IdPAttributeValue<?> idpAttributeValue = decodeValue(profileRequestContext, input, rule, o);
+ if (idpAttributeValue == null) {
+ log.debug("Unable to decode value of attribute {}", attributeName);
+ } else {
+ idpAttributeValues.add(idpAttributeValue);
+ }
+ }
+
+ if (!idpAttributeValues.isEmpty()) {
+ log.debug("Decoded {} values for attribute {}", idpAttributeValues.size(), attributeName);
+ }
+ return buildIdPAttribute(profileRequestContext, input, rule, idpAttributeValues);
+ }
+
+ /**
+ * Checks if the given value can be handled by the transcoder.
+ *
+ * <p>In many cases this is simply a check to see if the given object is of the right type.</p>
+ *
+ * @param idpAttribute the attribute being encoded, never null
+ * @param value the value to check, never null
+ *
+ * @return true if the transcoder can encode this value, false if not
+ */
+ protected abstract boolean canEncodeValue(@Nonnull final IdPAttribute idpAttribute,
+ @Nonnull final IdPAttributeValue value);
+
+ /**
+ * Encodes an attribute value into a string.
+ *
+ * @param profileRequestContext current profile request
+ * @param attribute the attribute being encoded
+ * @param rule properties to control encoding
+ * @param value the value to encode
+ *
+ * @return the attribute value or null if the resulting attribute value would be empty
+ *
+ * @throws AttributeEncodingException thrown if there is a problem encoding the attribute value
+ */
+ @Nullable protected abstract String encodeValue(@Nullable final ProfileRequestContext profileRequestContext,
+ @Nonnull final IdPAttribute attribute, @Nonnull final TranscodingRule rule,
+ @Nonnull final EncodedType value) throws AttributeEncodingException;
+
+ /**
+ * Builds an {@link IdPAttribute} from the given values.
+ *
+ * @param profileRequestContext current profile request
+ * @param attribute the attribute being decoded
+ * @param rule properties to control decoding
+ * @param attributeValues the decoded values for the attribute
+ *
+ * @return the IdPAttribute object
+ *
+ * @throws AttributeDecodingException thrown if there is a problem constructing the IdPAttribute
+ */
+ @Nonnull protected IdPAttribute buildIdPAttribute(
+ @Nullable final ProfileRequestContext profileRequestContext, @Nonnull final Attribute attribute,
+ @Nonnull final TranscodingRule rule,
+ @Nonnull @NonnullElements final List<IdPAttributeValue<?>> attributeValues)
+ throws AttributeDecodingException {
+
+ final String id = rule.get(AttributeTranscoderRegistry.PROP_ID, String.class);
+ if (Strings.isNullOrEmpty(id)) {
+ throw new AttributeDecodingException("Required transcoder property 'id' not found");
+ }
+
+ if (!((Attribute) attribute).getValues().isEmpty() && attributeValues.isEmpty()) {
+ throw new AttributeDecodingException("Failed to decode any values for attribute " + attribute.getName());
+ }
+
+ final IdPAttribute idpAttribute = new IdPAttribute(id);
+ idpAttribute.setValues(attributeValues);
+ return idpAttribute;
+ }
+
+ /**
+ * Function to decode a single string value into an {@link IdPAttributeValue}.
+ *
+ * @param profileRequestContext current profile request
+ * @param attribute the attribute being decoded
+ * @param rule properties to control decoding
+ * @param value the value to decode
+ *
+ * @return the returned final {@link IdPAttributeValue} or null if decoding failed
+ */
+ @Nullable protected abstract IdPAttributeValue<?> decodeValue(
+ @Nullable final ProfileRequestContext profileRequestContext, @Nonnull final Attribute attribute,
+ @Nonnull final TranscodingRule rule, @Nullable final String value);
+
+ /** A function to produce a "canonical" name for a CAS {@link Attribute} for transcoding rules. */
+ public static class NamingFunction implements Function<Attribute,String> {
+
+ /** {@inheritDoc} */
+ @Nullable public String apply(@Nullable final Attribute input) {
+
+ if (input == null || input.getName() == null) {
+ return null;
+ }
+
+ return "CAS:" + input.getName();
+ }
+
+ }
+
+}
\ No newline at end of file
diff --git a/idp-cas-api/src/main/java/net/shibboleth/idp/cas/attribute/Attribute.java b/idp-cas-api/src/main/java/net/shibboleth/idp/cas/attribute/Attribute.java
new file mode 100644
index 0000000..7eeacb4
--- /dev/null
+++ b/idp-cas-api/src/main/java/net/shibboleth/idp/cas/attribute/Attribute.java
@@ -0,0 +1,74 @@
+/*
+ * 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.cas.attribute;
+
+import java.util.ArrayList;
+import java.util.Collection;
+
+import javax.annotation.Nonnull;
+
+import net.shibboleth.utilities.java.support.annotation.constraint.Live;
+import net.shibboleth.utilities.java.support.annotation.constraint.NonnullElements;
+import net.shibboleth.utilities.java.support.annotation.constraint.NotEmpty;
+import net.shibboleth.utilities.java.support.logic.Constraint;
+import net.shibboleth.utilities.java.support.primitive.StringSupport;
+
+/**
+ * Wrapper class for a CAS attribute/values construct in a validate response.
+ */
+public class Attribute {
+
+ /** Name of attribute. */
+ @Nonnull @NotEmpty private String name;
+
+ /** String values. */
+ @Nonnull @NonnullElements private final Collection<String> values;
+
+ /**
+ * Constructor.
+ *
+ * @param theName name of attribute
+ *
+ */
+ public Attribute(@Nonnull @NotEmpty final String theName) {
+ name = Constraint.isNotNull(StringSupport.trimOrNull(theName),
+ "CAS attribute name cannot be null or empty.");
+
+ values = new ArrayList<>();
+ }
+
+ /**
+ * Get the attribute's name.
+ *
+ * @return the name
+ *
+ */
+ @Nonnull @NotEmpty public String getName() {
+ return name;
+ }
+
+ /**
+ * Get string values.
+ *
+ * @return string value collection
+ */
+ @Nonnull @NonnullElements @Live public Collection<String> getValues() {
+ return values;
+ }
+
+}
\ No newline at end of file
diff --git a/idp-cas-api/src/main/java/net/shibboleth/idp/cas/attribute/CASAttributeTranscoder.java b/idp-cas-api/src/main/java/net/shibboleth/idp/cas/attribute/CASAttributeTranscoder.java
new file mode 100644
index 0000000..7d69678
--- /dev/null
+++ b/idp-cas-api/src/main/java/net/shibboleth/idp/cas/attribute/CASAttributeTranscoder.java
@@ -0,0 +1,33 @@
+/*
+ * 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.cas.attribute;
+
+import javax.annotation.Nonnull;
+
+import net.shibboleth.idp.attribute.transcoding.AttributeTranscoder;
+import net.shibboleth.utilities.java.support.annotation.constraint.NotEmpty;
+
+/**
+ * Marker interface for transcoders that support CAS attributes.
+ */
+public interface CASAttributeTranscoder extends AttributeTranscoder<Attribute> {
+
+ /** The attribute name. */
+ @Nonnull @NotEmpty static final String PROP_NAME = "name";
+
+}
\ No newline at end of file
diff --git a/idp-cas-api/src/main/java/net/shibboleth/idp/cas/attribute/package-info.java b/idp-cas-api/src/main/java/net/shibboleth/idp/cas/attribute/package-info.java
new file mode 100644
index 0000000..b087d34
--- /dev/null
+++ b/idp-cas-api/src/main/java/net/shibboleth/idp/cas/attribute/package-info.java
@@ -0,0 +1,22 @@
+/*
+ * 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.
+ */
+
+/**
+ * APIs for CAS attribute support.
+ */
+
+package net.shibboleth.idp.cas.attribute;
\ No newline at end of file
diff --git a/idp-cas-impl/src/main/java/net/shibboleth/idp/cas/attribute/transcoding/impl/CASScopedStringAttributeTranscoder.java b/idp-cas-impl/src/main/java/net/shibboleth/idp/cas/attribute/transcoding/impl/CASScopedStringAttributeTranscoder.java
new file mode 100644
index 0000000..8886d48
--- /dev/null
+++ b/idp-cas-impl/src/main/java/net/shibboleth/idp/cas/attribute/transcoding/impl/CASScopedStringAttributeTranscoder.java
@@ -0,0 +1,83 @@
+/*
+ * 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.cas.attribute.transcoding.impl;
+
+import javax.annotation.Nonnull;
+import javax.annotation.Nullable;
+
+import net.shibboleth.idp.attribute.AttributeEncodingException;
+import net.shibboleth.idp.attribute.IdPAttribute;
+import net.shibboleth.idp.attribute.IdPAttributeValue;
+import net.shibboleth.idp.attribute.ScopedStringAttributeValue;
+import net.shibboleth.idp.attribute.transcoding.TranscodingRule;
+import net.shibboleth.idp.cas.attribute.AbstractCASAttributeTranscoder;
+import net.shibboleth.idp.cas.attribute.Attribute;
+import net.shibboleth.utilities.java.support.annotation.constraint.NotEmpty;
+
+import org.opensaml.profile.context.ProfileRequestContext;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * {@link net.shibboleth.idp.attribute.AttributeTranscoder} that supports {@link Attribute} and
+ * {@link ScopedStringAttributeValue} objects.
+ */
+public class CASScopedStringAttributeTranscoder extends AbstractCASAttributeTranscoder<ScopedStringAttributeValue> {
+
+ /** Scope delimiter. */
+ @Nonnull @NotEmpty public static final String PROP_SCOPE_DELIMITER = "scopeDelimiter";
+
+ /** Class logger. */
+ @Nonnull private final Logger log = LoggerFactory.getLogger(CASScopedStringAttributeTranscoder.class);
+
+ /** {@inheritDoc} */
+ @Override protected boolean canEncodeValue(@Nonnull final IdPAttribute attribute,
+ @Nonnull final IdPAttributeValue value) {
+ return value instanceof ScopedStringAttributeValue;
+ }
+
+ /** {@inheritDoc} */
+ @Override @Nullable protected String encodeValue(@Nullable final ProfileRequestContext profileRequestContext,
+ @Nonnull final IdPAttribute attribute, @Nonnull final TranscodingRule rule,
+ @Nonnull final ScopedStringAttributeValue value) throws AttributeEncodingException {
+
+ final String scopeDelimiter = rule.getOrDefault(PROP_SCOPE_DELIMITER, String.class, "@");
+ return value.getValue() + scopeDelimiter + value.getScope();
+ }
+
+ /** {@inheritDoc} */
+ @Override @Nullable protected IdPAttributeValue<?> decodeValue(
+ @Nullable final ProfileRequestContext profileRequestContext, @Nonnull final Attribute attribute,
+ @Nonnull final TranscodingRule rule, @Nullable final String value) {
+
+ if (value == null) {
+ return null;
+ }
+
+ final String scopeDelimiter = rule.getOrDefault(PROP_SCOPE_DELIMITER, String.class, "@");
+ final int offset = value.indexOf(scopeDelimiter);
+ if (offset < 0) {
+ log.warn("Ignoring value with no scope delimiter ({})", scopeDelimiter);
+ return null;
+ }
+
+ return ScopedStringAttributeValue.valueOf(value.substring(0, offset),
+ value.substring(offset + scopeDelimiter.length()));
+ }
+
+}
\ No newline at end of file
diff --git a/idp-cas-impl/src/main/java/net/shibboleth/idp/cas/attribute/transcoding/impl/CASStringAttributeTranscoder.java b/idp-cas-impl/src/main/java/net/shibboleth/idp/cas/attribute/transcoding/impl/CASStringAttributeTranscoder.java
new file mode 100644
index 0000000..f958d60
--- /dev/null
+++ b/idp-cas-impl/src/main/java/net/shibboleth/idp/cas/attribute/transcoding/impl/CASStringAttributeTranscoder.java
@@ -0,0 +1,73 @@
+/*
+ * 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.cas.attribute.transcoding.impl;
+
+import javax.annotation.Nonnull;
+import javax.annotation.Nullable;
+
+import net.shibboleth.idp.attribute.AttributeEncodingException;
+import net.shibboleth.idp.attribute.IdPAttribute;
+import net.shibboleth.idp.attribute.IdPAttributeValue;
+import net.shibboleth.idp.attribute.LocalizedStringAttributeValue;
+import net.shibboleth.idp.attribute.ScopedStringAttributeValue;
+import net.shibboleth.idp.attribute.StringAttributeValue;
+import net.shibboleth.idp.attribute.transcoding.TranscodingRule;
+import net.shibboleth.idp.cas.attribute.AbstractCASAttributeTranscoder;
+import net.shibboleth.idp.cas.attribute.Attribute;
+
+import org.opensaml.profile.context.ProfileRequestContext;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * {@link net.shibboleth.idp.attribute.AttributeTranscoder} that supports {@link Attribute} and
+ * {@link StringAttributeValue} objects.
+ */
+public class CASStringAttributeTranscoder extends AbstractCASAttributeTranscoder<StringAttributeValue> {
+
+ /** Class logger. */
+ @Nonnull private final Logger log = LoggerFactory.getLogger(CASStringAttributeTranscoder.class);
+
+ /** {@inheritDoc} */
+ @Override protected boolean canEncodeValue(@Nonnull final IdPAttribute attribute,
+ @Nonnull final IdPAttributeValue value) {
+ return value instanceof StringAttributeValue;
+ }
+
+ /** {@inheritDoc} */
+ @Override @Nullable protected String encodeValue(@Nullable final ProfileRequestContext profileRequestContext,
+ @Nonnull final IdPAttribute attribute, @Nonnull final TranscodingRule rule,
+ @Nonnull final StringAttributeValue value) throws AttributeEncodingException {
+
+ if (value instanceof LocalizedStringAttributeValue || value instanceof ScopedStringAttributeValue) {
+ log.warn("Attribute '{}': Lossy encoding of attribute value of type {} to SAML1 String Attribute",
+ attribute.getId(), value.getClass().getSimpleName());
+ }
+
+ return value.getValue();
+ }
+
+ /** {@inheritDoc} */
+ @Override @Nullable protected IdPAttributeValue<?> decodeValue(
+ @Nullable final ProfileRequestContext profileRequestContext, @Nonnull final Attribute attribute,
+ @Nonnull final TranscodingRule rule, @Nullable final String value) {
+
+ return value != null ? StringAttributeValue.valueOf(value) : null;
+ }
+
+}
\ No newline at end of file
diff --git a/idp-cas-impl/src/main/java/net/shibboleth/idp/cas/attribute/transcoding/impl/package-info.java b/idp-cas-impl/src/main/java/net/shibboleth/idp/cas/attribute/transcoding/impl/package-info.java
new file mode 100644
index 0000000..0a7d8e3
--- /dev/null
+++ b/idp-cas-impl/src/main/java/net/shibboleth/idp/cas/attribute/transcoding/impl/package-info.java
@@ -0,0 +1,22 @@
+/*
+ * 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.
+ */
+
+/**
+ * Implementation classes for CAS attribute support.
+ */
+
+package net.shibboleth.idp.cas.attribute.transcoding.impl;
\ No newline at end of file
diff --git a/idp-cas-impl/src/test/java/net/shibboleth/idp/cas/attribute/transcoding/impl/CASScopedStringAttributeTranscoderTest.java b/idp-cas-impl/src/test/java/net/shibboleth/idp/cas/attribute/transcoding/impl/CASScopedStringAttributeTranscoderTest.java
new file mode 100644
index 0000000..4986af5
--- /dev/null
+++ b/idp-cas-impl/src/test/java/net/shibboleth/idp/cas/attribute/transcoding/impl/CASScopedStringAttributeTranscoderTest.java
@@ -0,0 +1,248 @@
+/*
+ * 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.cas.attribute.transcoding.impl;
+
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.Map;
+
+import net.shibboleth.idp.attribute.AttributeEncodingException;
+import net.shibboleth.idp.attribute.ByteAttributeValue;
+import net.shibboleth.idp.attribute.IdPAttribute;
+import net.shibboleth.idp.attribute.IdPAttributeValue;
+import net.shibboleth.idp.attribute.ScopedStringAttributeValue;
+import net.shibboleth.idp.attribute.StringAttributeValue;
+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.attribute.transcoding.impl.AttributeTranscoderRegistryImpl;
+import net.shibboleth.idp.cas.attribute.AbstractCASAttributeTranscoder;
+import net.shibboleth.idp.cas.attribute.Attribute;
+import net.shibboleth.idp.cas.attribute.CASAttributeTranscoder;
+import net.shibboleth.utilities.java.support.component.ComponentInitializationException;
+
+import org.testng.Assert;
+import org.testng.annotations.AfterClass;
+import org.testng.annotations.BeforeClass;
+import org.testng.annotations.Test;
+
+/** {@link CASScopedStringAttributeTranscoder} unit test. */
+public class CASScopedStringAttributeTranscoderTest {
+
+ private AttributeTranscoderRegistryImpl registry;
+
+ private final static String ATTR_ID = "foo";
+ private final static String ATTR_NAME = "bar";
+ private final static String STRING_1 = "Value The First";
+ private final static String STRING_2 = "Second string the value is";
+ private final static String SCOPE_1 = "scope1.example.org";
+ private final static String SCOPE_2 = "scope2";
+ private final static String DELIMITER = "#";
+
+ @BeforeClass public void setUp() throws ComponentInitializationException {
+
+ registry = new AttributeTranscoderRegistryImpl();
+ registry.setId("test");
+
+ final CASScopedStringAttributeTranscoder transcoder = new CASScopedStringAttributeTranscoder();
+ transcoder.initialize();
+
+ registry.setNamingRegistry(Collections.singletonMap(transcoder.getEncodedType(),
+ new AbstractCASAttributeTranscoder.NamingFunction()));
+
+ final Map<String,Object> ruleset1 = new HashMap<>();
+ ruleset1.put(AttributeTranscoderRegistry.PROP_ID, ATTR_ID);
+ ruleset1.put(AttributeTranscoderRegistry.PROP_TRANSCODER, transcoder);
+ ruleset1.put(CASAttributeTranscoder.PROP_NAME, ATTR_NAME);
+ ruleset1.put(CASScopedStringAttributeTranscoder.PROP_SCOPE_DELIMITER, DELIMITER);
+
+ registry.setTranscoderRegistry(Collections.singletonList(new TranscodingRule(ruleset1)));
+
+ registry.initialize();
+ }
+
+ @AfterClass public void tearDown() {
+ registry.destroy();
+ registry = null;
+ }
+
+ @Test public void emptyEncode() throws Exception {
+ final IdPAttribute inputAttribute = new IdPAttribute(ATTR_ID);
+
+ final Collection<TranscodingRule> rulesets = registry.getTranscodingRules(inputAttribute, Attribute.class);
+ Assert.assertEquals(rulesets.size(), 1);
+ final TranscodingRule ruleset = rulesets.iterator().next();
+
+ final Attribute attr = TranscoderSupport.<Attribute>getTranscoder(ruleset).encode(
+ null, inputAttribute, Attribute.class, ruleset);
+ Assert.assertNotNull(attr);
+ Assert.assertEquals(attr.getName(), ATTR_NAME);
+ Assert.assertTrue(attr.getValues().isEmpty());
+ }
+
+ @Test public void emptyDecode() throws Exception {
+
+ final Attribute casAttribute = new Attribute(ATTR_NAME);
+
+ final Collection<TranscodingRule> rulesets = registry.getTranscodingRules(casAttribute);
+ Assert.assertEquals(rulesets.size(), 1);
+ final TranscodingRule ruleset = rulesets.iterator().next();
+
+ final IdPAttribute attr = TranscoderSupport.getTranscoder(ruleset).decode(null, casAttribute, ruleset);
+
+ Assert.assertNotNull(attr);
+ Assert.assertEquals(attr.getId(), ATTR_ID);
+ Assert.assertTrue(attr.getValues().isEmpty());
+ }
+
+ @Test(expectedExceptions = {AttributeEncodingException.class,}) public void inappropriate() throws Exception {
+ final int[] intArray = {1, 2, 3, 4};
+ final Collection<IdPAttributeValue<?>> values =
+ Arrays.asList(new ByteAttributeValue(new byte[] {1, 2, 3,}), new IdPAttributeValue<Object>() {
+ @Override
+ public Object getValue() {
+ return intArray;
+ }
+ @Override
+ public String getDisplayValue() {
+ return intArray.toString();
+ }
+ });
+
+ final IdPAttribute inputAttribute = new IdPAttribute(ATTR_ID);
+ inputAttribute.setValues(values);
+
+ final Collection<TranscodingRule> rulesets = registry.getTranscodingRules(inputAttribute, Attribute.class);
+ Assert.assertEquals(rulesets.size(), 1);
+ final TranscodingRule ruleset = rulesets.iterator().next();
+
+ TranscoderSupport.getTranscoder(ruleset).encode(null, inputAttribute, Attribute.class, ruleset);
+ }
+
+ @Test public void single() throws Exception {
+ final Collection<IdPAttributeValue<?>> values =
+ Arrays.asList(new ByteAttributeValue(new byte[] {1, 2, 3,}),
+ new ScopedStringAttributeValue(STRING_1, SCOPE_1),
+ new StringAttributeValue(STRING_1),
+ new StringAttributeValue(STRING_1 + "@" + SCOPE_1));
+
+ final IdPAttribute inputAttribute = new IdPAttribute(ATTR_ID);
+ inputAttribute.setValues(values);
+
+ final Collection<TranscodingRule> rulesets = registry.getTranscodingRules(inputAttribute, Attribute.class);
+ Assert.assertEquals(rulesets.size(), 1);
+ final TranscodingRule ruleset = rulesets.iterator().next();
+
+ final Attribute attr = TranscoderSupport.<Attribute>getTranscoder(ruleset).encode(
+ null, inputAttribute, Attribute.class, ruleset);
+
+ Assert.assertNotNull(attr);
+ Assert.assertEquals(attr.getName(), ATTR_NAME);
+
+ final Collection<String> children = attr.getValues();
+
+ Assert.assertEquals(children.size(), 1, "Encoding one entry");
+
+ final String child = children.iterator().next();
+
+ Assert.assertEquals(child, STRING_1 + DELIMITER + SCOPE_1, "Input equals output");
+ }
+
+ @Test public void singleDecode() throws Exception {
+
+ final Attribute casAttribute = new Attribute(ATTR_NAME);
+ casAttribute.getValues().add(STRING_1 + DELIMITER + SCOPE_1);
+
+ final Collection<TranscodingRule> rulesets = registry.getTranscodingRules(casAttribute);
+ Assert.assertEquals(rulesets.size(), 1);
+ final TranscodingRule ruleset = rulesets.iterator().next();
+
+ final IdPAttribute attr = TranscoderSupport.getTranscoder(ruleset).decode(null, casAttribute, ruleset);
+
+ Assert.assertNotNull(attr);
+ Assert.assertEquals(attr.getId(), ATTR_ID);
+ Assert.assertEquals(attr.getValues().size(), 1);
+
+ final ScopedStringAttributeValue value = (ScopedStringAttributeValue) attr.getValues().get(0);
+ Assert.assertEquals(value.getValue(), STRING_1);
+ Assert.assertEquals(value.getScope(), SCOPE_1);
+ }
+
+ @Test public void multi() throws Exception {
+ final Collection<IdPAttributeValue<?>> values =
+ Arrays.asList(new ByteAttributeValue(new byte[] {1, 2, 3,}),
+ new ScopedStringAttributeValue(STRING_1, SCOPE_1),
+ new ScopedStringAttributeValue(STRING_2, SCOPE_2));
+
+ final IdPAttribute inputAttribute = new IdPAttribute(ATTR_ID);
+ inputAttribute.setValues(values);
+
+ final Collection<TranscodingRule> rulesets = registry.getTranscodingRules(inputAttribute, Attribute.class);
+ Assert.assertEquals(rulesets.size(), 1);
+ final TranscodingRule ruleset = rulesets.iterator().next();
+
+ final Attribute attr = TranscoderSupport.<Attribute>getTranscoder(ruleset).encode(
+ null, inputAttribute, Attribute.class, ruleset);
+
+ Assert.assertNotNull(attr);
+ Assert.assertEquals(attr.getName(), ATTR_NAME);
+
+ final Collection<String> children = attr.getValues();
+ Assert.assertEquals(children.size(), 2, "Encoding 2 entries");
+
+ final Iterator<String> iter = children.iterator();
+ final String child1 = iter.next();
+ final String child2 = iter.next();
+
+ final String value1 = STRING_1 + DELIMITER + SCOPE_1;
+ final String value2 = STRING_2 + DELIMITER + SCOPE_2;
+
+ Assert.assertTrue(child1.equals(value1) || child1.equals(value2));
+ Assert.assertTrue(child2.equals(value1) || child2.equals(value2));
+ }
+
+ @Test public void multiDecode() throws Exception {
+
+ final Attribute casAttribute = new Attribute(ATTR_NAME);
+ casAttribute.getValues().add(STRING_1 + DELIMITER + SCOPE_1);
+ casAttribute.getValues().add(STRING_2 + DELIMITER + SCOPE_2);
+ casAttribute.getValues().add(STRING_2 + '@' + SCOPE_2);
+ casAttribute.getValues().add(STRING_2);
+
+ final Collection<TranscodingRule> rulesets = registry.getTranscodingRules(casAttribute);
+ Assert.assertEquals(rulesets.size(), 1);
+ final TranscodingRule ruleset = rulesets.iterator().next();
+
+ final IdPAttribute attr = TranscoderSupport.getTranscoder(ruleset).decode(null, casAttribute, ruleset);
+
+ Assert.assertNotNull(attr);
+ Assert.assertEquals(attr.getId(), ATTR_ID);
+ Assert.assertEquals(attr.getValues().size(), 2);
+
+ final ScopedStringAttributeValue value1 = (ScopedStringAttributeValue) attr.getValues().get(0);
+ final ScopedStringAttributeValue value2 = (ScopedStringAttributeValue) attr.getValues().get(1);
+ Assert.assertTrue(STRING_1.equals(value1.getValue()) || STRING_1.equals(value2.getValue()));
+ Assert.assertTrue(STRING_2.equals(value1.getValue()) || STRING_2.equals(value2.getValue()));
+ Assert.assertTrue(SCOPE_1.equals(value1.getScope()) || SCOPE_1.equals(value2.getScope()));
+ Assert.assertTrue(SCOPE_2.equals(value1.getScope()) || SCOPE_2.equals(value2.getScope()));
+ }
+
+}
\ No newline at end of file
diff --git a/idp-cas-impl/src/test/java/net/shibboleth/idp/cas/attribute/transcoding/impl/CASStringAttributeTranscoderTest.java b/idp-cas-impl/src/test/java/net/shibboleth/idp/cas/attribute/transcoding/impl/CASStringAttributeTranscoderTest.java
new file mode 100644
index 0000000..aadebaf
--- /dev/null
+++ b/idp-cas-impl/src/test/java/net/shibboleth/idp/cas/attribute/transcoding/impl/CASStringAttributeTranscoderTest.java
@@ -0,0 +1,225 @@
+/*
+ * 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.cas.attribute.transcoding.impl;
+
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Map;
+
+import net.shibboleth.idp.attribute.AttributeEncodingException;
+import net.shibboleth.idp.attribute.ByteAttributeValue;
+import net.shibboleth.idp.attribute.IdPAttribute;
+import net.shibboleth.idp.attribute.IdPAttributeValue;
+import net.shibboleth.idp.attribute.ScopedStringAttributeValue;
+import net.shibboleth.idp.attribute.StringAttributeValue;
+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.attribute.transcoding.impl.AttributeTranscoderRegistryImpl;
+import net.shibboleth.idp.cas.attribute.AbstractCASAttributeTranscoder;
+import net.shibboleth.idp.cas.attribute.Attribute;
+import net.shibboleth.idp.cas.attribute.CASAttributeTranscoder;
+import net.shibboleth.utilities.java.support.component.ComponentInitializationException;
+
+import org.testng.Assert;
+import org.testng.annotations.AfterClass;
+import org.testng.annotations.BeforeClass;
+import org.testng.annotations.Test;
+
+/** {@link CASStringAttributeTranscoder} unit test. */
+public class CASStringAttributeTranscoderTest {
+
+ private AttributeTranscoderRegistryImpl registry;
+
+ private final static String ATTR_ID = "foo";
+ private final static String ATTR_NAME = "bar";
+ private final static String STRING_1 = "Value The First";
+ private final static String STRING_2 = "Second string the value is";
+
+ @BeforeClass public void setUp() throws ComponentInitializationException {
+
+ registry = new AttributeTranscoderRegistryImpl();
+ registry.setId("test");
+
+ final CASStringAttributeTranscoder transcoder = new CASStringAttributeTranscoder();
+ transcoder.initialize();
+
+ registry.setNamingRegistry(Collections.singletonMap(transcoder.getEncodedType(),
+ new AbstractCASAttributeTranscoder.NamingFunction()));
+
+ final Map<String,Object> ruleset1 = new HashMap<>();
+ ruleset1.put(AttributeTranscoderRegistry.PROP_ID, ATTR_ID);
+ ruleset1.put(AttributeTranscoderRegistry.PROP_TRANSCODER, transcoder);
+ ruleset1.put(CASAttributeTranscoder.PROP_NAME, ATTR_NAME);
+
+ registry.setTranscoderRegistry(Collections.singletonList(new TranscodingRule(ruleset1)));
+
+ registry.initialize();
+ }
+
+ @AfterClass public void tearDown() {
+ registry.destroy();
+ registry = null;
+ }
+
+ @Test public void emptyEncode() throws Exception {
+ final IdPAttribute inputAttribute = new IdPAttribute(ATTR_ID);
+
+ final Collection<TranscodingRule> rulesets = registry.getTranscodingRules(inputAttribute, Attribute.class);
+ Assert.assertEquals(rulesets.size(), 1);
+ final TranscodingRule ruleset = rulesets.iterator().next();
+
+ final Attribute attr = TranscoderSupport.<Attribute>getTranscoder(ruleset).encode(
+ null, inputAttribute, Attribute.class, ruleset);
+ Assert.assertNotNull(attr);
+ Assert.assertEquals(attr.getName(), ATTR_NAME);
+ Assert.assertTrue(attr.getValues().isEmpty());
+ }
+
+ @Test public void emptyDecode() throws Exception {
+
+ final Attribute casAttribute = new Attribute(ATTR_NAME);
+
+ final Collection<TranscodingRule> rulesets = registry.getTranscodingRules(casAttribute);
+ Assert.assertEquals(rulesets.size(), 1);
+ final TranscodingRule ruleset = rulesets.iterator().next();
+
+ final IdPAttribute attr = TranscoderSupport.getTranscoder(ruleset).decode(null, casAttribute, ruleset);
+
+ Assert.assertNotNull(attr);
+ Assert.assertEquals(attr.getId(), ATTR_ID);
+ Assert.assertTrue(attr.getValues().isEmpty());
+ }
+
+ @Test(expectedExceptions = {AttributeEncodingException.class,}) public void inappropriate() throws Exception {
+ final int[] intArray = {1, 2, 3, 4};
+ final Collection<IdPAttributeValue<?>> values =
+ Arrays.asList(new ByteAttributeValue(new byte[] {1, 2, 3,}), new IdPAttributeValue<Object>() {
+ @Override
+ public Object getValue() {
+ return intArray;
+ }
+ @Override
+ public String getDisplayValue() {
+ return intArray.toString();
+ }
+ });
+
+ final IdPAttribute inputAttribute = new IdPAttribute(ATTR_ID);
+ inputAttribute.setValues(values);
+
+ final Collection<TranscodingRule> rulesets = registry.getTranscodingRules(inputAttribute, Attribute.class);
+ Assert.assertEquals(rulesets.size(), 1);
+ final TranscodingRule ruleset = rulesets.iterator().next();
+
+ TranscoderSupport.getTranscoder(ruleset).encode(null, inputAttribute, Attribute.class, ruleset);
+ }
+
+ @Test public void single() throws Exception {
+ final Collection<IdPAttributeValue<?>> values =
+ Arrays.asList(new ByteAttributeValue(new byte[] {1, 2, 3,}), new StringAttributeValue(STRING_1));
+
+ final IdPAttribute inputAttribute = new IdPAttribute(ATTR_ID);
+ inputAttribute.setValues(values);
+
+ final Collection<TranscodingRule> rulesets = registry.getTranscodingRules(inputAttribute, Attribute.class);
+ Assert.assertEquals(rulesets.size(), 1);
+ final TranscodingRule ruleset = rulesets.iterator().next();
+
+ final Attribute attr = TranscoderSupport.<Attribute>getTranscoder(ruleset).encode(
+ null, inputAttribute, Attribute.class, ruleset);
+
+ Assert.assertNotNull(attr);
+ Assert.assertEquals(attr.getName(), ATTR_NAME);
+
+ final Collection<String> children = attr.getValues();
+
+ Assert.assertEquals(children.size(), 1, "Encoding one entry");
+
+ final String child = children.iterator().next();
+
+ Assert.assertEquals(child, STRING_1);
+ }
+
+ @Test public void singleDecode() throws Exception {
+
+ final Attribute casAttribute = new Attribute(ATTR_NAME);
+ casAttribute.getValues().add(STRING_1);
+
+ final Collection<TranscodingRule> rulesets = registry.getTranscodingRules(casAttribute);
+ Assert.assertEquals(rulesets.size(), 1);
+ final TranscodingRule ruleset = rulesets.iterator().next();
+
+ final IdPAttribute attr = TranscoderSupport.getTranscoder(ruleset).decode(null, casAttribute, ruleset);
+
+ Assert.assertNotNull(attr);
+ Assert.assertEquals(attr.getId(), ATTR_ID);
+ Assert.assertEquals(attr.getValues().size(), 1);
+ Assert.assertEquals(attr.getValues().get(0).getValue().toString(), STRING_1);
+ }
+
+ @Test public void multi() throws Exception {
+ final Collection<IdPAttributeValue<?>> values =
+ Arrays.asList(new ByteAttributeValue(new byte[] {1, 2, 3,}),
+ new StringAttributeValue(STRING_1),
+ new StringAttributeValue(STRING_2),
+ new ScopedStringAttributeValue(STRING_1, STRING_2));
+
+ final IdPAttribute inputAttribute = new IdPAttribute(ATTR_ID);
+ inputAttribute.setValues(values);
+
+ final Collection<TranscodingRule> rulesets = registry.getTranscodingRules(inputAttribute, Attribute.class);
+ Assert.assertEquals(rulesets.size(), 1);
+ final TranscodingRule ruleset = rulesets.iterator().next();
+
+ final Attribute attr = TranscoderSupport.<Attribute>getTranscoder(ruleset).encode(
+ null, inputAttribute, Attribute.class, ruleset);
+
+ Assert.assertNotNull(attr);
+ Assert.assertEquals(attr.getName(), ATTR_NAME);
+
+ final Collection<String> children = attr.getValues();
+ Assert.assertEquals(children.size(), 3, "Encoding three entries");
+
+ for (final String child: children) {
+ Assert.assertTrue(STRING_1.equals(child)||STRING_2.equals(child));
+ }
+ }
+
+ @Test public void multiDecode() throws Exception {
+
+ final Attribute casAttribute = new Attribute(ATTR_NAME);
+ casAttribute.getValues().add(STRING_1);
+ casAttribute.getValues().add(STRING_2);
+
+ final Collection<TranscodingRule> rulesets = registry.getTranscodingRules(casAttribute);
+ Assert.assertEquals(rulesets.size(), 1);
+ final TranscodingRule ruleset = rulesets.iterator().next();
+
+ final IdPAttribute attr = TranscoderSupport.getTranscoder(ruleset).decode(null, casAttribute, ruleset);
+
+ Assert.assertNotNull(attr);
+ Assert.assertEquals(attr.getId(), ATTR_ID);
+ Assert.assertEquals(attr.getValues().size(), 2);
+ Assert.assertEquals(attr.getValues().get(0).getValue().toString(), STRING_1);
+ Assert.assertEquals(attr.getValues().get(1).getValue().toString(), STRING_2);
+ }
+
+}
\ No newline at end of file
diff --git a/idp-conf/src/main/resources/system/conf/attribute-registry-system.xml b/idp-conf/src/main/resources/system/conf/attribute-registry-system.xml
index cf21b80..ddde56a 100644
--- a/idp-conf/src/main/resources/system/conf/attribute-registry-system.xml
+++ b/idp-conf/src/main/resources/system/conf/attribute-registry-system.xml
@@ -30,6 +30,11 @@
<bean id="SAML1XMLObjectTranscoder"
class="net.shibboleth.idp.saml.attribute.transcoding.impl.SAML1XMLObjectAttributeTranscoder" />
+ <bean id="CASStringTranscoder"
+ class="net.shibboleth.idp.cas.attribute.transcoding.impl.CASStringAttributeTranscoder" />
+ <bean id="CASScopedStringTranscoder"
+ class="net.shibboleth.idp.cas.attribute.transcoding.impl.CASScopedStringAttributeTranscoder" />
+
<util:map id="DefaultNamingRegistry">
<entry key="#{T(org.opensaml.saml.saml2.core.Attribute)}">
<bean class="net.shibboleth.idp.saml.attribute.transcoding.AbstractSAML2AttributeTranscoder.NamingFunction" />
@@ -37,6 +42,9 @@
<entry key="#{T(org.opensaml.saml.saml1.core.AttributeDesignator)}">
<bean class="net.shibboleth.idp.saml.attribute.transcoding.AbstractSAML1AttributeTranscoder.NamingFunction" />
</entry>
+ <entry key="#{T(net.shibboleth.idp.cas.attribute.Attribute)}">
+ <bean class="net.shibboleth.idp.cas.attribute.AbstractCASAttributeTranscoder.NamingFunction" />
+ </entry>
</util:map>
<bean id="shibboleth.TranscodingRule"
--
To stop receiving notification emails like this one, please contact
the administrator of this repository.
More information about the commits
mailing list