[java-identity-provider] branch maint-4 updated: IDP-2054 - Add per-SP salt for computedId connector
Scott Cantor
cantor.2 at osu.edu
Wed Dec 14 14:38:20 UTC 2022
This is an automated email from the git hooks/post-receive script.
scantor pushed a commit to branch maint-4
in repository java-identity-provider.
View the commit online:
http://git.shibboleth.net/view/?p=java-identity-provider.git;a=commit;h=d1efa94ef3ced285d527428d9fe5097b46a6e81e
The following commit(s) were added to refs/heads/maint-4 by this push:
new d1efa94ef IDP-2054 - Add per-SP salt for computedId connector
d1efa94ef is described below
commit d1efa94ef3ced285d527428d9fe5097b46a6e81e
Author: Scott Cantor <cantor.2 at osu.edu>
AuthorDate: Wed Dec 14 09:38:17 2022 -0500
IDP-2054 - Add per-SP salt for computedId connector
https://shibboleth.atlassian.net/browse/IDP-2054
---
.../attribute/impl/ComputedPairwiseIdStore.java | 74 +++++++++++++++-------
.../impl/ComputedPairwiseIdStoreTest.java | 17 +++++
.../dc/impl/ComputedIdDataConnectorParser.java | 4 ++
.../idp/attribute/resolver/spring/customBean.xml | 8 ++-
.../resolver/spring/dc/resolver/computed.xml | 1 +
.../resolver/spring/dc/resolver/stored.xml | 1 +
.../net/shibboleth/idp/conf/saml-nameid-system.xml | 1 +
.../schema/shibboleth-attribute-resolver.xsd | 20 +++++-
8 files changed, 100 insertions(+), 26 deletions(-)
diff --git a/idp-attribute-impl/src/main/java/net/shibboleth/idp/attribute/impl/ComputedPairwiseIdStore.java b/idp-attribute-impl/src/main/java/net/shibboleth/idp/attribute/impl/ComputedPairwiseIdStore.java
index 7368c0451..8a4bb261b 100644
--- a/idp-attribute-impl/src/main/java/net/shibboleth/idp/attribute/impl/ComputedPairwiseIdStore.java
+++ b/idp-attribute-impl/src/main/java/net/shibboleth/idp/attribute/impl/ComputedPairwiseIdStore.java
@@ -23,6 +23,7 @@ import java.security.NoSuchAlgorithmException;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
+import java.util.function.BiFunction;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
@@ -41,12 +42,20 @@ import net.shibboleth.utilities.java.support.component.ComponentSupport;
import net.shibboleth.utilities.java.support.logic.Constraint;
import net.shibboleth.utilities.java.support.primitive.StringSupport;
+import org.opensaml.profile.context.ProfileRequestContext;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* A {@link PairwiseIdStore} that generates a pairwise ID by computing the hash of
- * a given attribute value, the entity ID of the recipient, and a provided salt.
+ * a given attribute value, the entity ID of the recipient, and a salt.
+ *
+ * <p>The salt may be global, or produced by a lookup function, and an exception map
+ * may be injected to override those values. The precedence is [map, function, global],
+ * and either a global value or function must be supplied.<.p>
+ *
+ * <p>In this version of the software, the first argument to the salt strategy function
+ * will always be null. Future versions will change this.</p>
*
* <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
@@ -71,7 +80,7 @@ public class ComputedPairwiseIdStore extends AbstractInitializableComponent impl
BASE32,
};
- /** Salt used when computing the ID. */
+ /** Default salt used when computing the ID. */
@NonnullAfterInit private byte[] salt;
/** JCE digest algorithm name to use. */
@@ -83,6 +92,9 @@ public class ComputedPairwiseIdStore extends AbstractInitializableComponent impl
/** Override map to block or re-issue identifiers. */
@Nonnull private Map<String,Map<String,String>> exceptionMap;
+ /** Optional source of salt for request. */
+ @Nullable BiFunction<ProfileRequestContext,PairwiseId,String> saltLookupStrategy;
+
/** Constructor. */
public ComputedPairwiseIdStore() {
algorithm = "SHA";
@@ -222,6 +234,19 @@ public class ComputedPairwiseIdStore extends AbstractInitializableComponent impl
}
}
}
+
+ /**
+ * Sets an optional function to use to obtain the salt for the request.
+ *
+ * @param strategy lookup strategy
+ *
+ * @since 4.3.0
+ */
+ public void setSaltLookupStrategy(@Nullable final BiFunction<ProfileRequestContext,PairwiseId,String> strategy) {
+ ComponentSupport.ifInitializedThrowUnmodifiabledComponentException(this);
+
+ saltLookupStrategy = strategy;
+ }
/** {@inheritDoc} */
@Override
@@ -229,10 +254,10 @@ public class ComputedPairwiseIdStore extends AbstractInitializableComponent impl
super.doInitialize();
if (null == getSalt()) {
- throw new ComponentInitializationException("Salt cannot be null");
- }
-
- if (getSalt().length < 16) {
+ if (saltLookupStrategy == null) {
+ throw new ComponentInitializationException("Global salt and salt lookup strategy cannot both be null");
+ }
+ } else if (getSalt().length < 16) {
throw new ComponentInitializationException("Salt must be at least 16 bytes in size");
}
}
@@ -246,10 +271,10 @@ public class ComputedPairwiseIdStore extends AbstractInitializableComponent impl
Constraint.isNotEmpty(pid.getPrincipalName(), "Principal name cannot be null or empty");
Constraint.isNotEmpty(pid.getSourceSystemId(), "Source system ID cannot be null or empty");
- final byte[] effectiveSalt = getEffectiveSalt(pid.getPrincipalName(), pid.getRecipientEntityID());
+ final byte[] effectiveSalt = getEffectiveSalt(pid);
if (effectiveSalt == null) {
- log.warn("Pairwise ID generation blocked for relying party ({})", pid.getRecipientEntityID());
- throw new IOException("Pairwise ID generation blocked by exception rule");
+ log.warn("Pairwise ID generation blocked for relying party ({}), no salt available", pid.getRecipientEntityID());
+ throw new IOException("Pairwise ID generation blocked due to absence of salt");
}
try {
@@ -280,43 +305,48 @@ public class ComputedPairwiseIdStore extends AbstractInitializableComponent impl
/**
* Get the effective salt to apply for a particular principal/RP pair, or null to refuse to generate one.
*
- * @param principalName name of subject
- * @param relyingPartyId name of relying party scope
+ * @param pid pairwise ID input
*
* @return salt to use
*/
- @Nullable private byte[] getEffectiveSalt(@Nonnull @NotEmpty final String principalName,
- @Nonnull @NotEmpty final String relyingPartyId) {
+ @Nullable private byte[] getEffectiveSalt(@Nonnull final PairwiseId pid) {
- Map<String,String> override = exceptionMap.get(principalName);
+ Map<String,String> override = exceptionMap.get(pid.getPrincipalName());
if (override == null) {
override = exceptionMap.get(WILDCARD_OVERRIDE);
}
if (override != null) {
- if (override.containsKey(relyingPartyId)) {
- final String s = override.get(relyingPartyId);
+ if (override.containsKey(pid.getRecipientEntityID())) {
+ final String s = override.get(pid.getRecipientEntityID());
if (s != null) {
- log.debug("Overriding salt for principal '{}' and relying party '{}'", principalName,
- relyingPartyId);
+ log.debug("Overriding salt for principal '{}' and relying party '{}'", pid.getPrincipalName(),
+ pid.getRecipientEntityID());
return s.getBytes();
}
log.debug("Blocked generation of ID for principal '{}' for relying party '{}'",
- principalName, relyingPartyId);
+ pid.getPrincipalName(), pid.getRecipientEntityID());
return null;
} else if (override.containsKey(WILDCARD_OVERRIDE)) {
final String s = override.get(WILDCARD_OVERRIDE);
if (s != null) {
- log.debug("Overriding salt for principal '{}' and relying party '{}'", principalName,
- relyingPartyId);
+ log.debug("Overriding salt for principal '{}' and relying party '{}'", pid.getPrincipalName(),
+ pid.getRecipientEntityID());
return s.getBytes();
}
log.debug("Blocked generation of ID for principal '{}' for relying party '{}'",
- principalName, relyingPartyId);
+ pid.getPrincipalName(), pid.getRecipientEntityID());
return null;
}
}
+ if (saltLookupStrategy != null) {
+ final String derivedSalt = saltLookupStrategy.apply(null, pid);
+ if (derivedSalt != null) {
+ return derivedSalt.getBytes();
+ }
+ }
+
return salt;
}
diff --git a/idp-attribute-impl/src/test/java/net/shibboleth/idp/attribute/impl/ComputedPairwiseIdStoreTest.java b/idp-attribute-impl/src/test/java/net/shibboleth/idp/attribute/impl/ComputedPairwiseIdStoreTest.java
index 6f5a9f0ab..50006eed0 100644
--- a/idp-attribute-impl/src/test/java/net/shibboleth/idp/attribute/impl/ComputedPairwiseIdStoreTest.java
+++ b/idp-attribute-impl/src/test/java/net/shibboleth/idp/attribute/impl/ComputedPairwiseIdStoreTest.java
@@ -39,6 +39,8 @@ public class ComputedPairwiseIdStoreTest {
/** Value calculated using V2 version. DO NOT CHANGE WITHOUT TESTING AGAINST 2.0 */
private static final String RESULT = "Vl6z6K70iLc4AuBoNeb59Dj1rGw=";
+ private static final String RESULT_BY_FUNCTION = "ZPNsH0Q/K8s48wLwFdviHuFPuWY=";
+
private static final String RESULT2 = "kLyH1uEvYigEvg1ZLh/QXeW1VAs=";
private static final String B32RESULT = "KZPLH2FO6SELOOAC4BUDLZXZ6Q4PLLDM";
@@ -47,6 +49,8 @@ public class ComputedPairwiseIdStoreTest {
private static final String salt2 = "thisisaspecialsalt";
+ private static final String saltByFunction = "thisisasaltfromfunction";
+
private static final String INVALID_BASE64_SALT="AB==";
public static final String COMMON_ATTRIBUTE_VALUE_STRING = "at1-Data";
@@ -125,6 +129,12 @@ public class ComputedPairwiseIdStoreTest {
public void testComputedId() throws Exception {
final ComputedPairwiseIdStore store = new ComputedPairwiseIdStore();
store.setSalt(salt);
+ store.setSaltLookupStrategy((prc,pid) -> {
+ if ("fooByFunction".equals(pid.getPrincipalName())) {
+ return saltByFunction;
+ }
+ return null;
+ });
store.initialize();
PairwiseId pid = new PairwiseId();
@@ -136,6 +146,13 @@ public class ComputedPairwiseIdStoreTest {
Assert.assertNotNull(pid);
Assert.assertEquals(pid.getPairwiseId(), RESULT);
+
+ // Trigger function override.
+ pid.setPrincipalName("fooByFunction");
+ pid = store.getBySourceValue(pid, true);
+
+ Assert.assertNotNull(pid);
+ Assert.assertEquals(pid.getPairwiseId(), RESULT_BY_FUNCTION);
}
@Test
diff --git a/idp-attribute-resolver-spring/src/main/java/net/shibboleth/idp/attribute/resolver/spring/dc/impl/ComputedIdDataConnectorParser.java b/idp-attribute-resolver-spring/src/main/java/net/shibboleth/idp/attribute/resolver/spring/dc/impl/ComputedIdDataConnectorParser.java
index 1b3c78106..f45cc256a 100644
--- a/idp-attribute-resolver-spring/src/main/java/net/shibboleth/idp/attribute/resolver/spring/dc/impl/ComputedIdDataConnectorParser.java
+++ b/idp-attribute-resolver-spring/src/main/java/net/shibboleth/idp/attribute/resolver/spring/dc/impl/ComputedIdDataConnectorParser.java
@@ -76,6 +76,10 @@ public class ComputedIdDataConnectorParser extends PairwiseIdDataConnectorParser
if (config.hasAttributeNS(null, "exceptionMapRef")) {
builder.addPropertyReference("exceptionMap", config.getAttributeNS(null, "exceptionMapRef"));
}
+
+ if (config.hasAttributeNS(null, "saltLookupStrategyRef")) {
+ builder.addPropertyReference("saltLookupStrategy", config.getAttributeNS(null, "saltLookupStrategyRef"));
+ }
final String salt;
final String encodedSalt;
diff --git a/idp-attribute-resolver-spring/src/test/resources/net/shibboleth/idp/attribute/resolver/spring/customBean.xml b/idp-attribute-resolver-spring/src/test/resources/net/shibboleth/idp/attribute/resolver/spring/customBean.xml
index 8cd7aca6c..ed7728213 100644
--- a/idp-attribute-resolver-spring/src/test/resources/net/shibboleth/idp/attribute/resolver/spring/customBean.xml
+++ b/idp-attribute-resolver-spring/src/test/resources/net/shibboleth/idp/attribute/resolver/spring/customBean.xml
@@ -62,7 +62,11 @@
</property>
</bean>
</util:list>
+
+ <bean id="SaltLookupStrategy" class="net.shibboleth.utilities.java.support.logic.BiFunctionSupport" factory-method="constant">
+ <constructor-arg>
+ <null/>
+ </constructor-arg>
+ </bean>
</beans>
-
-
\ No newline at end of file
diff --git a/idp-attribute-resolver-spring/src/test/resources/net/shibboleth/idp/attribute/resolver/spring/dc/resolver/computed.xml b/idp-attribute-resolver-spring/src/test/resources/net/shibboleth/idp/attribute/resolver/spring/dc/resolver/computed.xml
index 01945a0f1..a8928678f 100644
--- a/idp-attribute-resolver-spring/src/test/resources/net/shibboleth/idp/attribute/resolver/spring/dc/resolver/computed.xml
+++ b/idp-attribute-resolver-spring/src/test/resources/net/shibboleth/idp/attribute/resolver/spring/dc/resolver/computed.xml
@@ -4,6 +4,7 @@
generatedAttributeID="jenny"
salt="abcdefghijklmnopqrst "
+ saltLookupStrategyRef="SaltLookupStrategy"
algorithm="SHA256"
encoding="BASE32"
xsi:schemaLocation="urn:mace:shibboleth:2.0:resolver http://shibboleth.net/schema/idp/shibboleth-attribute-resolver.xsd">
diff --git a/idp-attribute-resolver-spring/src/test/resources/net/shibboleth/idp/attribute/resolver/spring/dc/resolver/stored.xml b/idp-attribute-resolver-spring/src/test/resources/net/shibboleth/idp/attribute/resolver/spring/dc/resolver/stored.xml
index 77214681c..5081bcb44 100644
--- a/idp-attribute-resolver-spring/src/test/resources/net/shibboleth/idp/attribute/resolver/spring/dc/resolver/stored.xml
+++ b/idp-attribute-resolver-spring/src/test/resources/net/shibboleth/idp/attribute/resolver/spring/dc/resolver/stored.xml
@@ -8,6 +8,7 @@
retryableErrors="25000 25001"
generatedAttributeID="jenny"
salt="abcdefghijklmnopqrst"
+ saltLookupStrategyRef="SaltLookupStrategy"
xsi:schemaLocation="urn:mace:shibboleth:2.0:resolver http://shibboleth.net/schema/idp/shibboleth-attribute-resolver.xsd">
diff --git a/idp-conf-impl/src/main/resources/net/shibboleth/idp/conf/saml-nameid-system.xml b/idp-conf-impl/src/main/resources/net/shibboleth/idp/conf/saml-nameid-system.xml
index cc1336119..2ba7ab2f1 100644
--- a/idp-conf-impl/src/main/resources/net/shibboleth/idp/conf/saml-nameid-system.xml
+++ b/idp-conf-impl/src/main/resources/net/shibboleth/idp/conf/saml-nameid-system.xml
@@ -62,6 +62,7 @@
p:salt="%{idp.persistentId.salt:}"
p:encodedSalt="%{idp.persistentId.encodedSalt:}"
p:exceptionMap="#{getObject('%{idp.persistentId.exceptionMap:shibboleth.ComputedIdExceptionMap}'.trim())}"
+ p:saltLookupStrategy="#{getObject('shibboleth.ComputedIdSaltLookupStrategy')}"
p:algorithm="%{idp.persistentId.algorithm:SHA}"
p:encoding="#{ T(net.shibboleth.idp.attribute.impl.ComputedPairwiseIdStore.Encoding).%{idp.persistentId.encoding:BASE64} }" />
diff --git a/idp-schema/src/main/resources/schema/shibboleth-attribute-resolver.xsd b/idp-schema/src/main/resources/schema/shibboleth-attribute-resolver.xsd
index d83497c81..fbddae33e 100644
--- a/idp-schema/src/main/resources/schema/shibboleth-attribute-resolver.xsd
+++ b/idp-schema/src/main/resources/schema/shibboleth-attribute-resolver.xsd
@@ -821,7 +821,7 @@
</documentation>
</annotation>
</attribute>
- <attribute name="exceptionMapRef" type="string">
+ <attribute name="exceptionMapRef" type="resolver:string">
<annotation>
<documentation>
Spring bean reference to a map of overrides that alter salt or suppress generation
@@ -829,6 +829,14 @@
</documentation>
</annotation>
</attribute>
+ <attribute name="saltLookupStrategyRef" type="resolver:string">
+ <annotation>
+ <documentation>
+ Spring bean reference to a BiFunction<ProfileRequestContext,PairwiseId>
+ to obtain the salt.
+ </documentation>
+ </annotation>
+ </attribute>
</extension>
</complexContent>
</complexType>
@@ -1749,7 +1757,7 @@
</documentation>
</annotation>
</attribute>
- <attribute name="exceptionMapRef" type="string">
+ <attribute name="exceptionMapRef" type="resolver:string">
<annotation>
<documentation>
Spring bean reference to a map of overrides that alter salt or suppress generation
@@ -1757,6 +1765,14 @@
</documentation>
</annotation>
</attribute>
+ <attribute name="saltLookupStrategyRef" type="resolver:string">
+ <annotation>
+ <documentation>
+ Spring bean reference to a BiFunction<ProfileRequestContext,PairwiseId>
+ to obtain the salt.
+ </documentation>
+ </annotation>
+ </attribute>
</extension>
</complexContent>
</complexType>
--
To stop receiving notification emails like this one, please contact
the administrator of this repository.
More information about the commits
mailing list