[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