[java-identity-provider] branch main updated: IDP-1686 - Looping detection
Scott Cantor
cantor.2 at osu.edu
Tue Feb 23 20:41:04 UTC 2021
This is an automated email from the git hooks/post-receive script.
scantor pushed a commit to branch main
in repository java-identity-provider.
View the commit online:
http://git.shibboleth.net/view/?p=java-identity-provider.git;a=commit;h=a322e3c0f3d07e7142c47518adb8873afab4bab0
The following commit(s) were added to refs/heads/main by this push:
new a322e3c0f IDP-1686 - Looping detection
a322e3c0f is described below
commit a322e3c0f3d07e7142c47518adb8873afab4bab0
Author: Scott Cantor <cantor.2 at osu.edu>
AuthorDate: Tue Feb 23 15:41:00 2021 -0500
IDP-1686 - Looping detection
https://issues.shibboleth.net/jira/browse/IDP-1686
Predicate (hopefully) useable with warning interceptor.
---
idp-profile-api/pom.xml | 7 ++
.../idp/profile/logic/LoopDetectionPredicate.java | 113 +++++++++++++++++++++
...teTest.java => LoopDetectionPredicateTest.java} | 41 ++++----
.../profile/logic/RelyingPartyIdPredicateTest.java | 1 -
4 files changed, 143 insertions(+), 19 deletions(-)
diff --git a/idp-profile-api/pom.xml b/idp-profile-api/pom.xml
index a99aebfe9..730e06f69 100644
--- a/idp-profile-api/pom.xml
+++ b/idp-profile-api/pom.xml
@@ -110,6 +110,13 @@
<artifactId>spring-test</artifactId>
<scope>test</scope>
</dependency>
+ <dependency>
+ <groupId>${opensaml.groupId}</groupId>
+ <artifactId>opensaml-core</artifactId>
+ <version>${opensaml.version}</version>
+ <type>test-jar</type>
+ <scope>test</scope>
+ </dependency>
</dependencies>
diff --git a/idp-profile-api/src/main/java/net/shibboleth/idp/profile/logic/LoopDetectionPredicate.java b/idp-profile-api/src/main/java/net/shibboleth/idp/profile/logic/LoopDetectionPredicate.java
new file mode 100644
index 000000000..edfcb9f86
--- /dev/null
+++ b/idp-profile-api/src/main/java/net/shibboleth/idp/profile/logic/LoopDetectionPredicate.java
@@ -0,0 +1,113 @@
+/*
+ * 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.profile.logic;
+
+import java.util.Collections;
+import java.util.Map;
+
+import javax.annotation.Nonnull;
+import javax.annotation.Nullable;
+
+import org.opensaml.core.metrics.MetricsSupport;
+import org.opensaml.profile.context.ProfileRequestContext;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.codahale.metrics.Meter;
+import com.codahale.metrics.MetricRegistry;
+import com.codahale.metrics.MetricRegistry.MetricSupplier;
+import com.codahale.metrics.SlidingTimeWindowMovingAverages;
+
+import net.shibboleth.idp.profile.context.RelyingPartyContext;
+import net.shibboleth.utilities.java.support.annotation.constraint.NonnullElements;
+import net.shibboleth.utilities.java.support.annotation.constraint.Positive;
+import net.shibboleth.utilities.java.support.logic.Constraint;
+
+/**
+ * A condition that relies on a {@link Meter} to detect looping SPs.
+ *
+ * @since 4.1.0
+ */
+public class LoopDetectionPredicate extends AbstractRelyingPartyPredicate {
+
+ /** Class logger. */
+ @Nonnull private final Logger log = LoggerFactory.getLogger(LoopDetectionPredicate.class);
+
+ /** Count to trigger warning. */
+ private long threshold;
+
+ /** Map of RP names to meter names. */
+ @Nonnull @NonnullElements private Map<String,String> relyingPartyMap;
+
+ /** Constructor. */
+ public LoopDetectionPredicate() {
+ threshold = 20;
+ relyingPartyMap = Collections.emptyMap();
+ }
+
+ /**
+ * Set the warning threshold for the 1 minute moving average to exceed.
+ *
+ * <p>Defaults to 20.</p>
+ *
+ * @param value threshold to use
+ */
+ public void setThreshold(@Positive final long value) {
+ threshold = Constraint.isGreaterThan(0, value, "Threshold must be positive");
+ }
+
+ /**
+ * Set the map of relying party names to meter names to track counts.
+ *
+ * @param map map of RP/meter mappings
+ */
+ public void setRelyingPartyMap(@Nullable @NonnullElements final Map<String,String> map) {
+ if (map != null) {
+ relyingPartyMap = Map.copyOf(map);
+ } else {
+ relyingPartyMap = Collections.emptyMap();
+ }
+ }
+
+ /** {@inheritDoc} */
+ public boolean test(@Nullable final ProfileRequestContext input) {
+
+ final RelyingPartyContext rpCtx = getRelyingPartyContextLookupStrategy().apply(input);
+ if (rpCtx != null) {
+ final String meterName = relyingPartyMap.get(rpCtx.getRelyingPartyId());
+ if (meterName != null) {
+ final Meter meter = MetricsSupport.getMetricRegistry().meter(
+ MetricRegistry.name("net.shibboleth.idp.loopDetection", meterName),
+ new MetricSupplier<Meter>() {
+ public Meter newMetric() {
+ return new Meter(new SlidingTimeWindowMovingAverages());
+ }
+ });
+ meter.mark();
+ final double rate = meter.getOneMinuteRate();
+ if (rate > threshold) {
+ log.warn("Meter {} rate of {} exceeded threshold of {}", meterName, rate, threshold);
+ return true;
+ }
+ }
+ }
+
+ return false;
+ }
+
+}
\ No newline at end of file
diff --git a/idp-profile-api/src/test/java/net/shibboleth/idp/profile/logic/RelyingPartyIdPredicateTest.java b/idp-profile-api/src/test/java/net/shibboleth/idp/profile/logic/LoopDetectionPredicateTest.java
similarity index 67%
copy from idp-profile-api/src/test/java/net/shibboleth/idp/profile/logic/RelyingPartyIdPredicateTest.java
copy to idp-profile-api/src/test/java/net/shibboleth/idp/profile/logic/LoopDetectionPredicateTest.java
index ac2dbe240..a1f8959f9 100644
--- a/idp-profile-api/src/test/java/net/shibboleth/idp/profile/logic/RelyingPartyIdPredicateTest.java
+++ b/idp-profile-api/src/test/java/net/shibboleth/idp/profile/logic/LoopDetectionPredicateTest.java
@@ -17,34 +17,32 @@
package net.shibboleth.idp.profile.logic;
-import java.util.Collections;
+import java.util.Map;
import net.shibboleth.idp.profile.context.RelyingPartyContext;
-import net.shibboleth.idp.profile.logic.RelyingPartyIdPredicate;
-import net.shibboleth.utilities.java.support.component.ComponentInitializationException;
+import org.opensaml.core.testing.OpenSAMLInitBaseTestCase;
import org.opensaml.profile.context.ProfileRequestContext;
import org.testng.Assert;
import org.testng.annotations.BeforeMethod;
import org.testng.annotations.Test;
-/** Unit test for {@link RelyingPartyIdPredicate}. */
-public class RelyingPartyIdPredicateTest {
+/** Unit test for {@link LoopDetectionPredicate}. */
+public class LoopDetectionPredicateTest extends OpenSAMLInitBaseTestCase {
private ProfileRequestContext prc;
-
private RelyingPartyContext rpCtx;
+ private LoopDetectionPredicate pred;
@BeforeMethod
public void setUp() {
prc = new ProfileRequestContext();
rpCtx = prc.getSubcontext(RelyingPartyContext.class, true);
+ pred = new LoopDetectionPredicate();
}
@Test
- public void testNone() throws ComponentInitializationException {
- final RelyingPartyIdPredicate pred = new RelyingPartyIdPredicate(Collections.<String>emptySet());
-
+ public void testNoMap() {
Assert.assertFalse(pred.test(prc));
rpCtx.setRelyingPartyId("foo");
@@ -52,23 +50,30 @@ public class RelyingPartyIdPredicateTest {
}
@Test
- public void testMatch() throws ComponentInitializationException {
- final RelyingPartyIdPredicate pred = new RelyingPartyIdPredicate(Collections.singleton("foo"));
-
- Assert.assertFalse(pred.test(prc));
+ public void testNoMatch() {
+ pred.setRelyingPartyMap(Map.of("bar", "bar"));
rpCtx.setRelyingPartyId("foo");
- Assert.assertTrue(pred.test(prc));
+ Assert.assertFalse(pred.test(prc));
}
@Test
- public void testNoMatch() throws ComponentInitializationException {
- final RelyingPartyIdPredicate pred = new RelyingPartyIdPredicate(Collections.singleton("bar"));
-
- Assert.assertFalse(pred.test(prc));
+ public void testMatch() {
+ pred.setRelyingPartyMap(Map.of("foo", "foo"));
rpCtx.setRelyingPartyId("foo");
Assert.assertFalse(pred.test(prc));
}
+ @Test
+ public void testExceed() throws InterruptedException {
+ pred.setRelyingPartyMap(Map.of("bar", "bar"));
+
+ 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
diff --git a/idp-profile-api/src/test/java/net/shibboleth/idp/profile/logic/RelyingPartyIdPredicateTest.java b/idp-profile-api/src/test/java/net/shibboleth/idp/profile/logic/RelyingPartyIdPredicateTest.java
index ac2dbe240..d97ddef16 100644
--- a/idp-profile-api/src/test/java/net/shibboleth/idp/profile/logic/RelyingPartyIdPredicateTest.java
+++ b/idp-profile-api/src/test/java/net/shibboleth/idp/profile/logic/RelyingPartyIdPredicateTest.java
@@ -20,7 +20,6 @@ package net.shibboleth.idp.profile.logic;
import java.util.Collections;
import net.shibboleth.idp.profile.context.RelyingPartyContext;
-import net.shibboleth.idp.profile.logic.RelyingPartyIdPredicate;
import net.shibboleth.utilities.java.support.component.ComponentInitializationException;
import org.opensaml.profile.context.ProfileRequestContext;
--
To stop receiving notification emails like this one, please contact
the administrator of this repository.
More information about the commits
mailing list