[java-idp-oidc] branch main updated: JOIDC-172 - Generic condition bean for matching metadata values

Henri Mikkonen henri.mikkonen at iki.fi
Tue Sep 5 16:35:27 UTC 2023


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

hjmikkon pushed a commit to branch main
in repository java-idp-oidc.

View the commit online:
http://git.shibboleth.net/view/?p=java-idp-oidc.git;a=commit;h=785f66f761ada03f7bd235c3fffba8fe3a59ebeb

The following commit(s) were added to refs/heads/main by this push:
     new 785f66f7 JOIDC-172 - Generic condition bean for matching metadata values
785f66f7 is described below

commit 785f66f761ada03f7bd235c3fffba8fe3a59ebeb
Author: Henri Mikkonen <henri.mikkonen at iki.fi>
AuthorDate: Tue Sep 5 19:33:25 2023 +0300

    JOIDC-172 - Generic condition bean for matching metadata values
    
    https://shibboleth.atlassian.net/browse/JOIDC-172
    
    A new bean "shibboleth.oidc.Conditions.MetadataValueEquals" can be used for matching values from metadata.
    For instance the following configuration returns true if application_type in metadata has value "native":
    
    <bean parent="OIDC.SSO.MDDriven">
       <property name="forcePKCEPredicate">
          <bean parent="shibboleth.oidc.Conditions.MetadataValueEquals" p:key="application_type" p:value="native" />
       </property>
    </bean>
---
 .../logic/MetadataValueEqualsCondition.java        | 122 +++++++++++++++++++++
 .../META-INF/net.shibboleth.idp/postconfig.xml     |   3 +
 .../logic/MetadataValueEqualsConditionTest.java    |  87 +++++++++++++++
 3 files changed, 212 insertions(+)

diff --git a/idp-oidc-extension-impl/src/main/java/net/shibboleth/idp/plugin/oidc/op/profile/logic/MetadataValueEqualsCondition.java b/idp-oidc-extension-impl/src/main/java/net/shibboleth/idp/plugin/oidc/op/profile/logic/MetadataValueEqualsCondition.java
new file mode 100644
index 00000000..9be09626
--- /dev/null
+++ b/idp-oidc-extension-impl/src/main/java/net/shibboleth/idp/plugin/oidc/op/profile/logic/MetadataValueEqualsCondition.java
@@ -0,0 +1,122 @@
+/*
+ * Licensed 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.plugin.oidc.op.profile.logic;
+
+import java.util.function.Function;
+import java.util.function.Predicate;
+
+import javax.annotation.Nonnull;
+import javax.annotation.Nullable;
+
+import org.opensaml.profile.context.ProfileRequestContext;
+
+import net.shibboleth.idp.plugin.oidc.op.profile.context.navigate.DefaultOIDCMetadataContextLookupFunction;
+import net.shibboleth.oidc.metadata.context.OIDCMetadataContext;
+import net.shibboleth.shared.annotation.constraint.NonnullAfterInit;
+import net.shibboleth.shared.component.AbstractIdentifiableInitializableComponent;
+import net.shibboleth.shared.component.ComponentInitializationException;
+import net.shibboleth.shared.logic.Constraint;
+import net.shibboleth.shared.primitive.StringSupport;
+
+/**
+ * A predicate for matching if the OIDC metadata value with a configurable key is equal to a configurable value.
+ */
+public class MetadataValueEqualsCondition extends AbstractIdentifiableInitializableComponent
+    implements Predicate<ProfileRequestContext> {
+
+    /** The lookup strategy for OIDCMetadataContext. */
+    @Nonnull private Function<ProfileRequestContext, OIDCMetadataContext> oidcMetadataContextLookupStrategy;
+
+    /** The metadata key whose value is used for matching. */
+    @NonnullAfterInit private String metadataKey;
+
+    /** The metadata value to be matched. */
+    @NonnullAfterInit private Object metadataValue;
+
+    /** The value used for matching if metadata value was null. */
+    @Nullable private Object defaultValue;
+
+    /**
+     * Constructor.
+     */
+    public MetadataValueEqualsCondition() {
+        oidcMetadataContextLookupStrategy = new DefaultOIDCMetadataContextLookupFunction();
+    }
+
+    /**
+     * Set the lookup strategy for OIDCMetadataContext.
+     * 
+     * @param strategy What to set.
+     */
+    public void setOidcMetadataContextLookupStrategy(
+            @Nonnull final Function<ProfileRequestContext, OIDCMetadataContext> strategy) {
+        checkSetterPreconditions();
+        oidcMetadataContextLookupStrategy = Constraint.isNotNull(strategy, "Lookup strategy cannot be null");
+    }
+
+    /**
+     * Set the metadata key whose value is used for matching.
+     * 
+     * @param function What to set.
+     */
+    public void setKey(@Nonnull final String key) {
+        checkSetterPreconditions();
+        metadataKey = Constraint.isNotEmpty(key, "Key value cannot be empty");
+    }
+
+    /**
+     * Set the metadata value to be matched.
+     * 
+     * @param function What to set.
+     */
+    public void setValue(@Nonnull final Object value) {
+        checkSetterPreconditions();
+        metadataValue = Constraint.isNotNull(value, "Value cannot be empty");
+    }
+
+    /**
+     * Set the value used for matching if metadata value was null.
+     * 
+     * @param value What to set.
+     */
+    public void setDefaultValue(@Nullable final Object value) {
+        checkSetterPreconditions();
+        defaultValue = value;
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    protected void doInitialize() throws ComponentInitializationException {
+        super.doInitialize();
+        
+        if (StringSupport.trimOrNull(metadataKey) == null) {
+            throw new ComponentInitializationException("Key value cannot be empty");
+        }
+        if (metadataValue == null) {
+            throw new ComponentInitializationException("Value cannot be empty");
+        }
+    }
+
+    @Override
+    public boolean test(@Nullable final ProfileRequestContext input) {
+        final OIDCMetadataContext oidcMetadataCtx = oidcMetadataContextLookupStrategy.apply(input);
+        if (oidcMetadataCtx == null || oidcMetadataCtx.getClientInformation() == null) {
+            return false;
+        }
+        final Object value = oidcMetadataCtx.getClientInformation().getOIDCMetadata().toJSONObject().get(metadataKey);
+        return metadataValue.equals(value != null ? value : defaultValue);
+    }
+    
+}
diff --git a/idp-oidc-extension-impl/src/main/resources/META-INF/net.shibboleth.idp/postconfig.xml b/idp-oidc-extension-impl/src/main/resources/META-INF/net.shibboleth.idp/postconfig.xml
index ff84ee14..5bbf1a48 100644
--- a/idp-oidc-extension-impl/src/main/resources/META-INF/net.shibboleth.idp/postconfig.xml
+++ b/idp-oidc-extension-impl/src/main/resources/META-INF/net.shibboleth.idp/postconfig.xml
@@ -738,4 +738,7 @@
         <!--  PRC given to the apply-method can be null as the default function doesn't exploit that -->
     </bean>
 
+    <bean id="shibboleth.oidc.Conditions.MetadataValueEquals"
+        class="net.shibboleth.idp.plugin.oidc.op.profile.logic.MetadataValueEqualsCondition" abstract="true" />
+
 </beans>
diff --git a/idp-oidc-extension-impl/src/test/java/net/shibboleth/idp/plugin/oidc/op/profile/logic/MetadataValueEqualsConditionTest.java b/idp-oidc-extension-impl/src/test/java/net/shibboleth/idp/plugin/oidc/op/profile/logic/MetadataValueEqualsConditionTest.java
new file mode 100644
index 00000000..59fde8c1
--- /dev/null
+++ b/idp-oidc-extension-impl/src/test/java/net/shibboleth/idp/plugin/oidc/op/profile/logic/MetadataValueEqualsConditionTest.java
@@ -0,0 +1,87 @@
+/*
+ * Licensed 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.plugin.oidc.op.profile.logic;
+
+import net.shibboleth.oidc.metadata.context.OIDCMetadataContext;
+import net.shibboleth.shared.component.ComponentInitializationException;
+
+import org.opensaml.profile.context.ProfileRequestContext;
+import org.testng.Assert;
+import org.testng.annotations.Test;
+
+import com.nimbusds.oauth2.sdk.id.ClientID;
+import com.nimbusds.openid.connect.sdk.rp.ApplicationType;
+import com.nimbusds.openid.connect.sdk.rp.OIDCClientInformation;
+import com.nimbusds.openid.connect.sdk.rp.OIDCClientMetadata;
+
+/** {@link MetadataValueEqualsCondition} unit test. */
+public class MetadataValueEqualsConditionTest {
+
+    MetadataValueEqualsCondition predicate;
+    
+    public void setup(final OIDCClientMetadata metadata, final String key, final Object value, final Object defValue)
+            throws ComponentInitializationException {
+        predicate = new MetadataValueEqualsCondition();
+        predicate.setKey(key);
+        predicate.setValue(value);
+        predicate.setDefaultValue(defValue);
+        final OIDCMetadataContext oidcMetadataCtx = new OIDCMetadataContext();
+        final OIDCClientInformation clientInformation = new OIDCClientInformation(new ClientID("mockId"), metadata);
+        oidcMetadataCtx.setClientInformation(clientInformation);
+        predicate.setOidcMetadataContextLookupStrategy(prc -> oidcMetadataCtx);
+        predicate.setId("mockId");
+        predicate.initialize();
+    }
+        
+    @Test
+    public void testApplicationTypeMatch() throws ComponentInitializationException {
+        final OIDCClientMetadata metadata = new OIDCClientMetadata();
+        metadata.setApplicationType(ApplicationType.NATIVE);
+        setup(metadata, "application_type", "native", null);
+        Assert.assertTrue(predicate.test(new ProfileRequestContext()));
+    }
+
+    @Test
+    public void testApplicationTypeNoMatch() throws ComponentInitializationException {
+        final OIDCClientMetadata metadata = new OIDCClientMetadata();
+        metadata.setApplicationType(ApplicationType.WEB);
+        setup(metadata, "application_type", "native", null);
+        Assert.assertFalse(predicate.test(new ProfileRequestContext()));
+    }
+
+    @Test
+    public void testClientNameMatch() throws ComponentInitializationException {
+        final OIDCClientMetadata metadata = new OIDCClientMetadata();
+        metadata.setName("TestApp");
+        setup(metadata, "client_name", "TestApp", null);
+        Assert.assertTrue(predicate.test(new ProfileRequestContext()));
+    }
+
+    @Test
+    public void testClientNameNoMatch() throws ComponentInitializationException {
+        final OIDCClientMetadata metadata = new OIDCClientMetadata();
+        metadata.setName("TestApp");
+        setup(metadata, "client_name", "NotMatching", null);
+        Assert.assertFalse(predicate.test(new ProfileRequestContext()));
+    }
+
+    @Test
+    public void testClientNameDefaultMatch() throws ComponentInitializationException {
+        final OIDCClientMetadata metadata = new OIDCClientMetadata();
+        setup(metadata, "client_name", "DefaultApp", "DefaultApp");
+        Assert.assertTrue(predicate.test(new ProfileRequestContext()));
+    }
+
+}
\ 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