[java-identity-provider] 01/02: IDP-1111 - Provide a case-insensitive computed persistent ID strategy

Scott Cantor cantor.2 at osu.edu
Thu Sep 28 21:13:50 EDT 2017


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

scantor pushed a commit to branch maint-3.3
in repository java-identity-provider.

View the commit online:
http://git.shibboleth.net/view/?p=java-identity-provider.git;a=commit;h=50632325e1590960e9271adcdc1807f56f573bb3

commit 50632325e1590960e9271adcdc1807f56f573bb3
Author: Scott Cantor <cantor.2 at osu.edu>
AuthorDate: Fri Jan 20 22:50:09 2017 +0000

    IDP-1111 - Provide a case-insensitive computed persistent ID strategy
    
    https://issues.shibboleth.net/jira/browse/IDP-1111
---
 .../src/main/resources/conf/saml-nameid.properties |  2 ++
 .../resources/system/conf/saml-nameid-system.xml   |  3 +-
 .../ComputedPersistentIdGenerationStrategy.java    | 37 +++++++++++++++++++++-
 .../impl/PersistentSAML2NameIDGeneratorTest.java   | 29 +++++++++++++++++
 4 files changed, 69 insertions(+), 2 deletions(-)

diff --git a/idp-conf/src/main/resources/conf/saml-nameid.properties b/idp-conf/src/main/resources/conf/saml-nameid.properties
index 8530c4f..bbc1597 100644
--- a/idp-conf/src/main/resources/conf/saml-nameid.properties
+++ b/idp-conf/src/main/resources/conf/saml-nameid.properties
@@ -24,6 +24,8 @@
 # Do *NOT* share the salt with other people, it's like divulging your private key.
 #idp.persistentId.algorithm = SHA
 #idp.persistentId.salt = changethistosomethingrandom
+# BASE64 will match V2 values, we recommend BASE32 encoding for new installs.
+idp.persistentId.encoding = BASE32
 
 # To use a database, use shibboleth.StoredPersistentIdGenerator
 #idp.persistentId.generator = shibboleth.ComputedPersistentIdGenerator
diff --git a/idp-conf/src/main/resources/system/conf/saml-nameid-system.xml b/idp-conf/src/main/resources/system/conf/saml-nameid-system.xml
index aabec4d..5399d2d 100644
--- a/idp-conf/src/main/resources/system/conf/saml-nameid-system.xml
+++ b/idp-conf/src/main/resources/system/conf/saml-nameid-system.xml
@@ -61,7 +61,8 @@
         class="net.shibboleth.idp.saml.nameid.impl.ComputedPersistentIdGenerationStrategy"
         p:salt="%{idp.persistentId.salt:}"
         p:encodedSalt="%{idp.persistentId.encodedSalt:}"
-        p:algorithm="%{idp.persistentId.algorithm:SHA}" />
+        p:algorithm="%{idp.persistentId.algorithm:SHA}"
+        p:encoding="#{ T(net.shibboleth.idp.saml.nameid.impl.ComputedPersistentIdGenerationStrategy.Encoding).%{idp.persistentId.encoding:BASE64} }" />
 
     <bean id="shibboleth.StoredPersistentIdGenerator" lazy-init="true"
         class="net.shibboleth.idp.saml.nameid.impl.StoredPersistentIdGenerationStrategy"
diff --git a/idp-saml-impl/src/main/java/net/shibboleth/idp/saml/nameid/impl/ComputedPersistentIdGenerationStrategy.java b/idp-saml-impl/src/main/java/net/shibboleth/idp/saml/nameid/impl/ComputedPersistentIdGenerationStrategy.java
index b761463..b4d6eb8 100644
--- a/idp-saml-impl/src/main/java/net/shibboleth/idp/saml/nameid/impl/ComputedPersistentIdGenerationStrategy.java
+++ b/idp-saml-impl/src/main/java/net/shibboleth/idp/saml/nameid/impl/ComputedPersistentIdGenerationStrategy.java
@@ -25,6 +25,7 @@ import javax.annotation.Nullable;
 
 import net.shibboleth.utilities.java.support.annotation.constraint.NonnullAfterInit;
 import net.shibboleth.utilities.java.support.annotation.constraint.NotEmpty;
+import net.shibboleth.utilities.java.support.codec.Base32Support;
 import net.shibboleth.utilities.java.support.codec.Base64Support;
 import net.shibboleth.utilities.java.support.component.AbstractInitializableComponent;
 import net.shibboleth.utilities.java.support.component.ComponentInitializationException;
@@ -39,6 +40,10 @@ import org.slf4j.LoggerFactory;
 /**
  * The basis of a {@link PersistentIdGenerationStrategy} that generates a unique ID by computing the hash of
  * a given attribute value, the entity ID of the inbound message issuer, and a provided salt.
+ * 
+ * <p>The original implementation and values in common use relied on base64 encoding of the result,
+ * but due to discovery of the lack of appropriate case handling of identifiers by applications, the
+ * ability to use base32 has been added to eliminate the possibility of case conflicts.</p> 
  */
 public class ComputedPersistentIdGenerationStrategy extends AbstractInitializableComponent
         implements PersistentIdGenerationStrategy {
@@ -46,15 +51,28 @@ public class ComputedPersistentIdGenerationStrategy extends AbstractInitializabl
     /** Class logger. */
     @Nonnull private final Logger log = LoggerFactory.getLogger(ComputedPersistentIdGenerationStrategy.class);
 
+    /** Post-digest encoding types. */
+    public enum Encoding {
+        /** Use Base64 encoding. */
+        BASE64,
+        
+        /** Use Base32 encoding. */
+        BASE32,
+    };
+
     /** Salt used when computing the ID. */
     @NonnullAfterInit private byte[] salt;
 
     /** JCE digest algorithm name to use. */
     @Nonnull @NotEmpty private String algorithm;
+
+    /** The encoding to apply to the digest. */
+    @Nonnull private Encoding encoding;
     
     /** Constructor. */
     public ComputedPersistentIdGenerationStrategy() {
         algorithm = "SHA";
+        encoding = Encoding.BASE64;
     }
     
     /**
@@ -108,6 +126,17 @@ public class ComputedPersistentIdGenerationStrategy extends AbstractInitializabl
         
         algorithm = Constraint.isNotNull(StringSupport.trimOrNull(alg), "Digest algorithm cannot be null or empty");
     }
+    
+    /**
+     * Set the post-digest encoding to use.
+     * 
+     * @param enc encoding
+     */
+    public void setEncoding(@Nonnull final Encoding enc) {
+        ComponentSupport.ifInitializedThrowUnmodifiabledComponentException(this);
+        
+        encoding = Constraint.isNotNull(enc, "Encoding cannot be null");
+    }
 
     /** {@inheritDoc} */
     @Override
@@ -138,7 +167,13 @@ public class ComputedPersistentIdGenerationStrategy extends AbstractInitializabl
             md.update(sourceId.getBytes());
             md.update((byte) '!');
 
-            return Base64Support.encode(md.digest(salt), Base64Support.UNCHUNKED);
+            if (encoding == Encoding.BASE32) {
+                return Base32Support.encode(md.digest(salt), Base32Support.UNCHUNKED);
+            } else if (encoding == Encoding.BASE64) {
+                return Base64Support.encode(md.digest(salt), Base64Support.UNCHUNKED);
+            } else {
+                throw new SAMLException("Desired encoding was not recognized, unable to compute ID");
+            }
         } catch (final NoSuchAlgorithmException e) {
             log.error("Digest algorithm {} is not supported", algorithm);
             throw new SAMLException("Digest algorithm was not supported, unable to compute ID", e);
diff --git a/idp-saml-impl/src/test/java/net/shibboleth/idp/saml/nameid/impl/PersistentSAML2NameIDGeneratorTest.java b/idp-saml-impl/src/test/java/net/shibboleth/idp/saml/nameid/impl/PersistentSAML2NameIDGeneratorTest.java
index 0272b15..1b12be0 100644
--- a/idp-saml-impl/src/test/java/net/shibboleth/idp/saml/nameid/impl/PersistentSAML2NameIDGeneratorTest.java
+++ b/idp-saml-impl/src/test/java/net/shibboleth/idp/saml/nameid/impl/PersistentSAML2NameIDGeneratorTest.java
@@ -28,6 +28,7 @@ import net.shibboleth.idp.authn.context.SubjectContext;
 import net.shibboleth.idp.profile.RequestContextBuilder;
 import net.shibboleth.idp.profile.context.RelyingPartyContext;
 import net.shibboleth.idp.saml.impl.TestSources;
+import net.shibboleth.idp.saml.nameid.impl.ComputedPersistentIdGenerationStrategy.Encoding;
 import net.shibboleth.idp.testing.DatabaseTestingSupport;
 import net.shibboleth.utilities.java.support.codec.Base64Support;
 import net.shibboleth.utilities.java.support.component.ComponentInitializationException;
@@ -51,6 +52,8 @@ public class PersistentSAML2NameIDGeneratorTest extends OpenSAMLInitBaseTestCase
 
     /** Value calculated using V2 version. DO NOT CHANGE WITHOUT TESTING AGAINST 2.0 */
     private static final String RESULT = "Vl6z6K70iLc4AuBoNeb59Dj1rGw=";
+    
+    private static final String B32RESULT = "KZPLH2FO6SELOOAC4BUDLZXZ6Q4PLLDM";
 
     private static final byte salt[] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15};
 
@@ -170,6 +173,32 @@ public class PersistentSAML2NameIDGeneratorTest extends OpenSAMLInitBaseTestCase
     }
 
     @Test
+    public void testBase32ComputedId() throws Exception {
+        final ComputedPersistentIdGenerationStrategy strategy = new ComputedPersistentIdGenerationStrategy();
+        strategy.setSalt(salt);
+        strategy.setEncoding(Encoding.BASE32);
+        strategy.initialize();
+
+        generator.setPersistentIdGenerator(strategy);
+        generator.setAttributeSourceIds(Collections.singletonList("SOURCE"));
+        generator.initialize();
+        
+        prc.getSubcontext(SubjectContext.class, true).setPrincipalName("foo");
+        Assert.assertNull(generator.generate(prc, NameID.PERSISTENT));
+        
+        final IdPAttribute source = new IdPAttribute("SOURCE");
+        source.setValues(Collections.singleton(new StringAttributeValue(TestSources.COMMON_ATTRIBUTE_VALUE_STRING)));
+        prc.getSubcontext(RelyingPartyContext.class).getSubcontext(AttributeContext.class, true).setUnfilteredIdPAttributes(
+                Collections.singleton(source));
+        final NameID id = generator.generate(prc, NameID.PERSISTENT);
+        Assert.assertNotNull(id);
+        Assert.assertEquals(id.getValue(), B32RESULT);
+        Assert.assertEquals(id.getFormat(), NameID.PERSISTENT);
+        Assert.assertEquals(id.getNameQualifier(), TestSources.IDP_ENTITY_ID);
+        Assert.assertEquals(id.getSPNameQualifier(), TestSources.SP_ENTITY_ID);
+    }
+
+    @Test
     public void testStoredId() throws Exception {
         final StoredPersistentIdGenerationStrategy strategy = new StoredPersistentIdGenerationStrategy();
         strategy.setDataSource(testSource);

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


More information about the commits mailing list