[java-shib-profile] branch main updated: JSPROF-10 - Enable loop detection via Condition
Scott Cantor
cantor.2 at osu.edu
Mon Feb 17 15:37:26 UTC 2025
This is an automated email from the git hooks/post-receive script.
scantor pushed a commit to branch main
in repository java-shib-profile.
View the commit online:
http://git.shibboleth.net/view/?p=java-shib-profile.git;a=commit;h=4a6abcf06ca7533e198b4abb496cc37a5dd36020
The following commit(s) were added to refs/heads/main by this push:
new 4a6abcf JSPROF-10 - Enable loop detection via Condition
4a6abcf is described below
commit 4a6abcf06ca7533e198b4abb496cc37a5dd36020
Author: Scott Cantor <cantor.2 at osu.edu>
AuthorDate: Mon Feb 17 10:37:24 2025 -0500
JSPROF-10 - Enable loop detection via Condition
https://shibboleth.atlassian.net/browse/JSPROF-10
---
.../context/logic/LoopDetectionPredicate.java | 85 +++++++++++++++++++++-
.../context/logic/LoopDetectionPredicateTest.java | 17 ++++-
2 files changed, 98 insertions(+), 4 deletions(-)
diff --git a/shib-profile-api/src/main/java/net/shibboleth/profile/context/logic/LoopDetectionPredicate.java b/shib-profile-api/src/main/java/net/shibboleth/profile/context/logic/LoopDetectionPredicate.java
index b14b8c2..cd4d060 100644
--- a/shib-profile-api/src/main/java/net/shibboleth/profile/context/logic/LoopDetectionPredicate.java
+++ b/shib-profile-api/src/main/java/net/shibboleth/profile/context/logic/LoopDetectionPredicate.java
@@ -14,8 +14,10 @@
package net.shibboleth.profile.context.logic;
+import java.security.NoSuchAlgorithmException;
import java.util.Map;
import java.util.function.Function;
+import java.util.function.Predicate;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
@@ -30,9 +32,12 @@ import com.codahale.metrics.SlidingTimeWindowMovingAverages;
import net.shibboleth.profile.context.RelyingPartyContext;
import net.shibboleth.shared.annotation.constraint.Positive;
+import net.shibboleth.shared.codec.StringDigester;
+import net.shibboleth.shared.codec.StringDigester.OutputFormat;
import net.shibboleth.shared.collection.CollectionSupport;
import net.shibboleth.shared.logic.Constraint;
import net.shibboleth.shared.logic.FunctionSupport;
+import net.shibboleth.shared.logic.PredicateSupport;
import net.shibboleth.shared.primitive.LoggerFactory;
/**
@@ -54,14 +59,26 @@ public class LoopDetectionPredicate extends AbstractRelyingPartyPredicate {
/** Map of RP names to meter names. */
@Nonnull private Map<String,String> relyingPartyMap;
+ /** Generalized condition in place of dedicated map. */
+ @Nonnull private Predicate<ProfileRequestContext> activationCondition;
+
+ /** Used with generalized condition to compute name to use in loop metric. */
+ @Nonnull private Function<ProfileRequestContext,String> tagGenerationStrategy;
+
/** Lookup strategy to obtain subject name. */
@Nonnull private Function<ProfileRequestContext,String> usernameLookupStrategy;
- /** Constructor. */
- public LoopDetectionPredicate() {
+ /**
+ * Constructor.
+ *
+ * @throws NoSuchAlgorithmException if unable to create digester
+ */
+ public LoopDetectionPredicate() throws NoSuchAlgorithmException {
privateRegistry = new MetricRegistry();
threshold = 20;
relyingPartyMap = CollectionSupport.emptyMap();
+ activationCondition = PredicateSupport.alwaysFalse();
+ tagGenerationStrategy = new DefaultTagGenerator();
usernameLookupStrategy = FunctionSupport.constant(null);
}
@@ -98,6 +115,32 @@ public class LoopDetectionPredicate extends AbstractRelyingPartyPredicate {
usernameLookupStrategy = Constraint.isNotNull(strategy, "Username lookup strategy cannot be null");
}
+ /**
+ * Sets a generalized activation condition to apply in addition to the hardcoded map of RPs.
+ *
+ * <p>Defaults to false.</p>
+ *
+ * @param condition condition to set
+ *
+ * @since 5.2.0
+ */
+ public void setActivationCondition(@Nonnull final Predicate<ProfileRequestContext> condition) {
+ activationCondition = Constraint.isNotNull(condition, "Activation condition cannot be null");
+ }
+
+ /**
+ * Sets a generalized tag generation strategy to produce the loop detection metric name.
+ *
+ * <p>Defaults to the SHA-1 hash of the RP name.</p>
+ *
+ * @param strategy function to produce metric name
+ *
+ * @since 5.2.0
+ */
+ public void setTagGenerationStrategy(@Nonnull final Function<ProfileRequestContext,String> strategy) {
+ tagGenerationStrategy = Constraint.isNotNull(strategy, "Tag generation function cannot be null");
+ }
+
/** {@inheritDoc} */
public boolean test(@Nullable final ProfileRequestContext input) {
@@ -106,6 +149,13 @@ public class LoopDetectionPredicate extends AbstractRelyingPartyPredicate {
if (username != null && rpCtx != null && rpCtx.getRelyingPartyId() != null) {
String meterName = relyingPartyMap.get(rpCtx.getRelyingPartyId());
+ if (meterName == null) {
+ // Check generalized predicate.
+ if (activationCondition.test(input)) {
+ meterName = tagGenerationStrategy.apply(input);
+ }
+ }
+
if (meterName != null) {
try {
meterName = MetricRegistry.name("net.shibboleth.idp.loopDetection", meterName,
@@ -134,4 +184,35 @@ public class LoopDetectionPredicate extends AbstractRelyingPartyPredicate {
return false;
}
+ /**
+ * Default tag generator that hashes the RP ID.
+ */
+ private class DefaultTagGenerator implements Function<ProfileRequestContext,String> {
+
+ /** Digester to prooduce tag. */
+ @Nonnull private final StringDigester digester;
+
+ /**
+ * Constructor.
+ *
+ * @throws NoSuchAlgorithmException if unable to obtain digester
+ */
+ public DefaultTagGenerator() throws NoSuchAlgorithmException {
+ digester = new StringDigester("SHA1", OutputFormat.HEX_LOWER);
+ }
+
+
+ /** {@inheritDoc} */
+ @Nullable public String apply(@Nullable final ProfileRequestContext input) {
+
+ final RelyingPartyContext rpCtx = getRelyingPartyContextLookupStrategy().apply(input);
+
+ if (rpCtx != null && rpCtx.getRelyingPartyId() != null) {
+ return digester.apply(rpCtx.getRelyingPartyId());
+ }
+
+ return null;
+ }
+ }
+
}
\ No newline at end of file
diff --git a/shib-profile-api/src/test/java/net/shibboleth/profile/context/logic/LoopDetectionPredicateTest.java b/shib-profile-api/src/test/java/net/shibboleth/profile/context/logic/LoopDetectionPredicateTest.java
index 4903d7e..8ae7f9e 100644
--- a/shib-profile-api/src/test/java/net/shibboleth/profile/context/logic/LoopDetectionPredicateTest.java
+++ b/shib-profile-api/src/test/java/net/shibboleth/profile/context/logic/LoopDetectionPredicateTest.java
@@ -14,10 +14,12 @@
package net.shibboleth.profile.context.logic;
+import java.security.NoSuchAlgorithmException;
import java.util.Map;
import net.shibboleth.profile.context.RelyingPartyContext;
import net.shibboleth.shared.logic.FunctionSupport;
+import net.shibboleth.shared.logic.PredicateSupport;
import org.opensaml.core.testing.OpenSAMLInitBaseTestCase;
import org.opensaml.profile.context.ProfileRequestContext;
@@ -34,7 +36,7 @@ public class LoopDetectionPredicateTest extends OpenSAMLInitBaseTestCase {
private LoopDetectionPredicate pred;
@BeforeMethod
- public void setUp() {
+ public void setUp() throws NoSuchAlgorithmException {
prc = new ProfileRequestContext();
rpCtx = prc.ensureSubcontext(RelyingPartyContext.class);
pred = new LoopDetectionPredicate();
@@ -56,7 +58,7 @@ public class LoopDetectionPredicateTest extends OpenSAMLInitBaseTestCase {
rpCtx.setRelyingPartyId("foo");
Assert.assertFalse(pred.test(prc));
}
-
+
@Test
public void testMatch() {
pred.setRelyingPartyMap(Map.of("foo", "foo"));
@@ -76,4 +78,15 @@ public class LoopDetectionPredicateTest extends OpenSAMLInitBaseTestCase {
Assert.assertTrue(pred.test(prc));
}
+ @Test
+ public void testExceedUsingActivationCondition() throws InterruptedException {
+ pred.setActivationCondition(PredicateSupport.alwaysTrue());
+
+ rpCtx.setRelyingPartyId("bar");
+ for (int i=0; i<20; ++i) {
+ Assert.assertFalse(pred.test(prc));
+ }
+ Assert.assertTrue(pred.test(prc));
+ }
+
}
\ No newline at end of file
--
To stop receiving notification emails like this one, please contact
the administrator of this repository.
More information about the commits
mailing list