[java-oidc-common] branch main updated: JCOMOIDC-96 - Support custom/additional metadata policy operators
Henri Mikkonen
henri.mikkonen at iki.fi
Fri Jan 19 12:41:10 UTC 2024
This is an automated email from the git hooks/post-receive script.
hjmikkon pushed a commit to branch main
in repository java-oidc-common.
View the commit online:
http://git.shibboleth.net/view/?p=java-oidc-common.git;a=commit;h=ed435c1aac06078cfe7af080e6bf363ca8a96afa
The following commit(s) were added to refs/heads/main by this push:
new ed435c1 JCOMOIDC-96 - Support custom/additional metadata policy operators
ed435c1 is described below
commit ed435c1aac06078cfe7af080e6bf363ca8a96afa
Author: Henri Mikkonen <henri.mikkonen at iki.fi>
AuthorDate: Fri Jan 19 14:38:07 2024 +0200
JCOMOIDC-96 - Support custom/additional metadata policy operators
https://shibboleth.atlassian.net/browse/JCOMOIDC-96
The MetadataPolicy -class now include a map of custom metadata policy operators.
The default policy enforcer and validator functions be wired with a map of
CustomMetadataPolicyOperator, key describing the operator name used within the
metadata policies. An example implementation BeanMetadataPolicyOperator can be used
for using a bean that implements the CustomMetadataPolicyOperator interface as a
custom metadata policy operator.
---
.../oidc/metadata/policy/MetadataPolicy.java | 57 +++++++-
.../policy/impl/BeanMetadataPolicyOperator.java | 69 ++++++++++
.../policy/impl/CustomMetadataPolicyOperator.java | 47 +++++++
.../policy/impl/DefaultMetadataPolicyEnforcer.java | 52 +++++++-
.../impl/DefaultMetadataPolicyValidator.java | 38 +++++-
.../impl/BeanMetadataPolicyOperatorTest.java | 144 +++++++++++++++++++++
.../impl/DefaultMetadataPolicyEnforcerTest.java | 23 ++++
.../impl/DefaultMetadataPolicyValidatorTest.java | 32 +++++
.../impl/OIDCMetadataPolicyResolverTest.java | 81 +++++++++++-
.../metadata/impl/metadata-policy1-custom.json | 22 ++++
10 files changed, 552 insertions(+), 13 deletions(-)
diff --git a/oidc-common-metadata-api/src/main/java/net/shibboleth/oidc/metadata/policy/MetadataPolicy.java b/oidc-common-metadata-api/src/main/java/net/shibboleth/oidc/metadata/policy/MetadataPolicy.java
index 0801f84..55c39b4 100644
--- a/oidc-common-metadata-api/src/main/java/net/shibboleth/oidc/metadata/policy/MetadataPolicy.java
+++ b/oidc-common-metadata-api/src/main/java/net/shibboleth/oidc/metadata/policy/MetadataPolicy.java
@@ -14,8 +14,12 @@
package net.shibboleth.oidc.metadata.policy;
+import java.util.HashMap;
import java.util.List;
+import java.util.Map;
+import com.fasterxml.jackson.annotation.JsonAnyGetter;
+import com.fasterxml.jackson.annotation.JsonAnySetter;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.google.common.base.MoreObjects;
@@ -49,6 +53,9 @@ public class MetadataPolicy {
/** The regular expression that the claim value must meet. */
@JsonProperty("regexp") private String regexp;
+ /** The map of any other operators not directly mapped. */
+ private final Map<String, Object> customOperators = new HashMap<>();
+
/**
* Get the (forced) value for the claim.
*
@@ -201,7 +208,32 @@ public class MetadataPolicy {
public void setRegexp(final String value) {
regexp = value;
}
-
+
+ /**
+ * Get the map of custom operators.
+ *
+ * @return The map of any other operators not directly mapped.
+ *
+ * @since 3.1.0
+ */
+ @JsonAnyGetter
+ public Map<String, Object> getCustomOperators() {
+ return customOperators;
+ }
+
+ /**
+ * Add a custom operator to the map of custom operators.
+ *
+ * @param name The name of the custom operator.
+ * @param value The value of the custom operator.
+ *
+ * @since 3.1.0
+ */
+ @JsonAnySetter
+ public void setCustomOperator(final String name, final Object value) {
+ customOperators.put(name, value);
+ }
+
/**
* {@inheritDoc}
*/
@@ -245,12 +277,15 @@ public class MetadataPolicy {
/** The regular expression that the claim value must meet. */
private String regexp;
-
+
+ /** The map of any other operators not directly mapped. */
+ private final Map<String, Object> customOperators;
+
/**
* Constructor.
*/
public Builder() {
-
+ this.customOperators = new HashMap<>();
}
/**
@@ -341,6 +376,19 @@ public class MetadataPolicy {
return this;
}
+ /**
+ * Add a custom operator to the map of custom operators.
+ *
+ * @param name The name of the custom operator.
+ * @param value The value of the custom operator.
+ *
+ * @since 3.1.0
+ */
+ public Builder withCustomOperator(final String name, final Object value) {
+ this.customOperators.put(name, value);
+ return this;
+ }
+
/**
* Build the metadata policy corresponding to the current builder state.
*
@@ -356,6 +404,9 @@ public class MetadataPolicy {
policy.setSupersetOfValues(this.supersetOfValues);
policy.setEssential(this.essential);
policy.setRegexp(this.regexp);
+ for (final String key : this.customOperators.keySet()) {
+ policy.setCustomOperator(key, this.customOperators.get(key));
+ }
return policy;
}
}
diff --git a/oidc-common-metadata-impl/src/main/java/net/shibboleth/oidc/metadata/policy/impl/BeanMetadataPolicyOperator.java b/oidc-common-metadata-impl/src/main/java/net/shibboleth/oidc/metadata/policy/impl/BeanMetadataPolicyOperator.java
new file mode 100644
index 0000000..b8f182b
--- /dev/null
+++ b/oidc-common-metadata-impl/src/main/java/net/shibboleth/oidc/metadata/policy/impl/BeanMetadataPolicyOperator.java
@@ -0,0 +1,69 @@
+/*
+ * 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.oidc.metadata.policy.impl;
+
+import javax.annotation.Nonnull;
+import javax.annotation.Nullable;
+
+import org.springframework.beans.BeansException;
+import org.springframework.context.ApplicationContext;
+import org.springframework.context.ApplicationContextAware;
+
+import net.shibboleth.oidc.metadata.policy.MetadataPolicy;
+import net.shibboleth.shared.logic.Constraint;
+import net.shibboleth.shared.logic.ConstraintViolationException;
+
+/**
+ * A custom metadata policy operator that fetches a bean from {@link ApplicationContext} and uses it for as
+ * {@link CustomMetadataPolicyOperator}.
+ */
+public class BeanMetadataPolicyOperator implements CustomMetadataPolicyOperator, ApplicationContextAware {
+
+ /** The operator name to be used within {@link MetadataPolicy} custom operators. */
+ public static final String BEAN_OPERATOR_NAME = "bean";
+
+ /** The application context from where to fetch the custom policy operators. */
+ private ApplicationContext applicationContext;
+
+ @Override
+ public boolean validate(@Nonnull final MetadataPolicy policy) {
+ return true;
+ }
+
+ @Override
+ public Object apply(final @Nullable Object inputValue, final @Nonnull MetadataPolicy policy)
+ throws ConstraintViolationException {
+ Constraint.isNotNull(inputValue, "input value (bean ID) cannot be null");
+ Constraint.isNotNull(policy, "metadata policy cannot be null");
+ final Object rawBeanId = policy.getCustomOperators().get(BEAN_OPERATOR_NAME);
+ if (rawBeanId instanceof String beanId) {
+ try {
+ final CustomMetadataPolicyOperator operator =
+ applicationContext.getBean(beanId, CustomMetadataPolicyOperator.class);
+ return operator.apply(inputValue, policy);
+ } catch (final BeansException e) {
+ throw new ConstraintViolationException("Could not wire a compatible bean " + beanId);
+ }
+ } else {
+ throw new ConstraintViolationException("Could not parse the bean name from policy");
+ }
+ }
+
+ @Override
+ public void setApplicationContext(@Nonnull final ApplicationContext context) throws BeansException {
+ applicationContext = context;
+ }
+
+}
diff --git a/oidc-common-metadata-impl/src/main/java/net/shibboleth/oidc/metadata/policy/impl/CustomMetadataPolicyOperator.java b/oidc-common-metadata-impl/src/main/java/net/shibboleth/oidc/metadata/policy/impl/CustomMetadataPolicyOperator.java
new file mode 100644
index 0000000..40a873e
--- /dev/null
+++ b/oidc-common-metadata-impl/src/main/java/net/shibboleth/oidc/metadata/policy/impl/CustomMetadataPolicyOperator.java
@@ -0,0 +1,47 @@
+/*
+ * 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.oidc.metadata.policy.impl;
+
+import javax.annotation.Nonnull;
+import javax.annotation.Nullable;
+
+import net.shibboleth.oidc.metadata.policy.MetadataPolicy;
+import net.shibboleth.shared.logic.ConstraintViolationException;
+
+/**
+ * Interface describing a custom policy operator to be used with {@link MetadataPolicy} objects.
+ */
+public interface CustomMetadataPolicyOperator {
+
+ /**
+ * Validate whether the operator is compatible with the other operators in the policy.
+ *
+ * @param policy The metadata policy to be used by the custom policy operator.
+ * @return true if
+ */
+ public boolean validate(@Nonnull final MetadataPolicy policy);
+
+ /**
+ * Apply the operator for the given input that has the given metadata policy attached.
+ *
+ * @param inputValue The value to be used by the custom policy operator.
+ * @param policy The metadata policy to be used by the custom policy operator.
+ * @return The value returned by the custom policy operator.
+ * @throws ConstraintViolationException If the value-check of the custom operator fails.
+ */
+ @Nullable public Object apply(@Nullable final Object inputValue, @Nonnull final MetadataPolicy policy)
+ throws ConstraintViolationException;
+
+}
diff --git a/oidc-common-metadata-impl/src/main/java/net/shibboleth/oidc/metadata/policy/impl/DefaultMetadataPolicyEnforcer.java b/oidc-common-metadata-impl/src/main/java/net/shibboleth/oidc/metadata/policy/impl/DefaultMetadataPolicyEnforcer.java
index f0dfe7c..d5ce8d1 100644
--- a/oidc-common-metadata-impl/src/main/java/net/shibboleth/oidc/metadata/policy/impl/DefaultMetadataPolicyEnforcer.java
+++ b/oidc-common-metadata-impl/src/main/java/net/shibboleth/oidc/metadata/policy/impl/DefaultMetadataPolicyEnforcer.java
@@ -17,6 +17,7 @@ package net.shibboleth.oidc.metadata.policy.impl;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
+import java.util.Map;
import java.util.function.BiFunction;
import java.util.regex.Pattern;
@@ -28,6 +29,8 @@ import org.slf4j.Logger;
import net.shibboleth.oidc.metadata.policy.MetadataPolicy;
import net.shibboleth.shared.collection.CollectionSupport;
import net.shibboleth.shared.collection.Pair;
+import net.shibboleth.shared.component.AbstractInitializableComponent;
+import net.shibboleth.shared.logic.Constraint;
import net.shibboleth.shared.logic.ConstraintViolationException;
import net.shibboleth.shared.primitive.LoggerFactory;
@@ -53,11 +56,31 @@ import net.shibboleth.shared.primitive.LoggerFactory;
* been applied to, and a flag indicating if the object was compatible with the value checks of the metadata policy.
* </p>
*/
-public class DefaultMetadataPolicyEnforcer implements BiFunction<Object,MetadataPolicy,Pair<Object,Boolean>> {
+public class DefaultMetadataPolicyEnforcer extends AbstractInitializableComponent
+ implements BiFunction<Object,MetadataPolicy,Pair<Object,Boolean>> {
/** Class logger. */
@Nonnull private final Logger log = LoggerFactory.getLogger(DefaultMetadataPolicyEnforcer.class);
+ /** Map of custom metadata policy operators that are applied after the standard operators. */
+ @Nonnull private Map<String, CustomMetadataPolicyOperator> customOperators;
+
+ /**
+ * Constructor.
+ */
+ public DefaultMetadataPolicyEnforcer() {
+ customOperators = CollectionSupport.emptyMap();
+ }
+
+ /**
+ * Set the map of custom metadata policy operators that are applied after the standard operators.
+ * @param operators What to set
+ */
+ public void setCustomMetadataPolicyOperators(@Nonnull final Map<String, CustomMetadataPolicyOperator> operators) {
+ checkSetterPreconditions();
+ customOperators = Constraint.isNotNull(operators, "Map of custom operators cannot be null");
+ }
+
/** {@inheritDoc} */
@Override
@Nonnull public Pair<Object, Boolean> apply(@Nullable final Object candidate,
@@ -84,9 +107,32 @@ public class DefaultMetadataPolicyEnforcer implements BiFunction<Object,Metadata
}
final boolean validation = doValueChecks(result, policy);
- return new Pair<>(result, Boolean.valueOf(validation));
+ return customOperators.isEmpty() || !validation
+ ? new Pair<>(result, Boolean.valueOf(validation))
+ : applyCustomOperators(result, policy);
}
+ /**
+ * Applies the custom operators attached to this enforcer.
+ *
+ * @param initialResult The result after standard operators have been applied
+ * @param policy The metadata policy to be applied to the initial result
+ * @return a {@link Pair} as required to return by this enforcer function
+ */
+ @Nonnull protected Pair<Object, Boolean> applyCustomOperators(@Nullable final Object initialResult,
+ @Nonnull final MetadataPolicy policy) {
+ Object result = initialResult;
+ for (final String customOperator : customOperators.keySet()) {
+ try {
+ result = customOperators.get(customOperator).apply(result, policy);
+ } catch (final ConstraintViolationException e) {
+ log.debug("The custom operator {} did not accept the value {}", customOperator, result);
+ return new Pair<>(result, Boolean.FALSE);
+ }
+ }
+ return new Pair<>(result, Boolean.TRUE);
+ }
+
/**
* Applies the given add value modifier for the given candidate and returns the result of the operation.
*
@@ -147,7 +193,7 @@ public class DefaultMetadataPolicyEnforcer implements BiFunction<Object,Metadata
log.warn("The candidate {} contains multiple values, not compatible with one_of", candidate);
validation = false;
} else {
- if (oneOfValues != null && !MetadataPolicyHelper.isSubsetOfValues(candidate, oneOfValues)) {
+ if (!MetadataPolicyHelper.isSubsetOfValues(candidate, oneOfValues)) {
log.warn("The candidate {} is not compatible with one_of {}", candidate, oneOfValues);
validation = false;
}
diff --git a/oidc-common-metadata-impl/src/main/java/net/shibboleth/oidc/metadata/policy/impl/DefaultMetadataPolicyValidator.java b/oidc-common-metadata-impl/src/main/java/net/shibboleth/oidc/metadata/policy/impl/DefaultMetadataPolicyValidator.java
index 9a25c8c..1d4a345 100644
--- a/oidc-common-metadata-impl/src/main/java/net/shibboleth/oidc/metadata/policy/impl/DefaultMetadataPolicyValidator.java
+++ b/oidc-common-metadata-impl/src/main/java/net/shibboleth/oidc/metadata/policy/impl/DefaultMetadataPolicyValidator.java
@@ -24,7 +24,10 @@ import javax.annotation.Nullable;
import org.slf4j.Logger;
import net.shibboleth.oidc.metadata.policy.MetadataPolicy;
+import net.shibboleth.shared.collection.CollectionSupport;
import net.shibboleth.shared.collection.Pair;
+import net.shibboleth.shared.component.AbstractInitializableComponent;
+import net.shibboleth.shared.logic.Constraint;
import net.shibboleth.shared.primitive.LoggerFactory;
/**
@@ -59,11 +62,30 @@ import net.shibboleth.shared.primitive.LoggerFactory;
* </li>
* </ul>
*/
-public class DefaultMetadataPolicyValidator implements Predicate<Map<String, MetadataPolicy>> {
+public class DefaultMetadataPolicyValidator extends AbstractInitializableComponent
+ implements Predicate<Map<String, MetadataPolicy>> {
/** Class logger. */
@Nonnull private final Logger log = LoggerFactory.getLogger(DefaultMetadataPolicyValidator.class);
-
+
+ /** Map of custom metadata policy operators that are applied after the standard operators. */
+ @Nonnull private Map<String, CustomMetadataPolicyOperator> customOperators;
+
+ /**
+ * Constructor.
+ */
+ public DefaultMetadataPolicyValidator() {
+ customOperators = CollectionSupport.emptyMap();
+ }
+
+ /**
+ * Set the map of custom metadata policy operators that are applied after the standard operators.
+ * @param operators What to set
+ */
+ public void setCustomMetadataPolicyOperators(@Nonnull final Map<String, CustomMetadataPolicyOperator> operators) {
+ checkSetterPreconditions();
+ customOperators = Constraint.isNotNull(operators, "Map of custom operators cannot be null");
+ }
/** {@inheritDoc} */
// Checkstyle: CyclomaticComplexity OFF
@@ -113,6 +135,18 @@ public class DefaultMetadataPolicyValidator implements Predicate<Map<String, Met
result = false;
}
+ if (!policy.getCustomOperators().isEmpty()) {
+ for (final String operatorName : policy.getCustomOperators().keySet()) {
+ final CustomMetadataPolicyOperator customOperator = customOperators.get(operatorName);
+ if (customOperator == null) {
+ log.warn("Claim {}: could not find a custom operator {}", claim, operatorName);
+ result = false;
+ } else if (!customOperator.validate(policy)) {
+ log.warn("Claimn {}: policy is not compatible with the custom operator {}", claim, operatorName);
+ result = false;
+ }
+ }
+ }
}
return result;
}
diff --git a/oidc-common-metadata-impl/src/test/java/net/shibboleth/oidc/metadata/policy/impl/BeanMetadataPolicyOperatorTest.java b/oidc-common-metadata-impl/src/test/java/net/shibboleth/oidc/metadata/policy/impl/BeanMetadataPolicyOperatorTest.java
new file mode 100644
index 0000000..a879bb2
--- /dev/null
+++ b/oidc-common-metadata-impl/src/test/java/net/shibboleth/oidc/metadata/policy/impl/BeanMetadataPolicyOperatorTest.java
@@ -0,0 +1,144 @@
+/*
+ * 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.oidc.metadata.policy.impl;
+
+import javax.annotation.Nonnull;
+
+import org.mockito.Mockito;
+import org.springframework.beans.BeansException;
+import org.springframework.context.ApplicationContext;
+import org.testng.Assert;
+import org.testng.annotations.BeforeMethod;
+import org.testng.annotations.Test;
+
+import net.shibboleth.oidc.metadata.policy.MetadataPolicy;
+import net.shibboleth.shared.logic.ConstraintViolationException;
+
+/**
+ * Unit tests for {@link BeanMetadataPolicyOperator}.
+ */
+ at SuppressWarnings("null")
+public class BeanMetadataPolicyOperatorTest {
+
+ BeanMetadataPolicyOperator operator;
+ ApplicationContext applicationContext = Mockito.mock(ApplicationContext.class);
+
+ @BeforeMethod
+ public void init() {
+ operator = new BeanMetadataPolicyOperator();
+ operator.setApplicationContext(applicationContext);
+ }
+
+ @Test
+ public void testSame() {
+ Mockito.when(applicationContext.getBean(Mockito.any(), Mockito.eq(CustomMetadataPolicyOperator.class)))
+ .thenReturn(alwaysSameOperator());
+ Assert.assertEquals(operator.apply("mockValue", metadataPolicy("alwaysSame")), "mockValue");
+ }
+
+ @Test
+ public void testChanged() {
+ Mockito.when(applicationContext.getBean(Mockito.any(), Mockito.eq(CustomMetadataPolicyOperator.class)))
+ .thenReturn(alwaysChangedOperator());
+ Assert.assertEquals(operator.apply("changedValue", metadataPolicy("alwaysChanged")), "changedValue");
+ }
+
+ @Test(expectedExceptions = { ConstraintViolationException.class })
+ public void testBeanFailing() {
+ Mockito.when(applicationContext.getBean(Mockito.any(), Mockito.eq(CustomMetadataPolicyOperator.class)))
+ .thenReturn(alwaysFailingOperator());
+ operator.apply("changedValue", metadataPolicy("alwaysChanged"));
+ }
+
+ @Test(expectedExceptions = { ConstraintViolationException.class })
+ public void testNotFound() {
+ Mockito.doThrow(CustomBeansException.class)
+ .when(applicationContext).getBean(Mockito.any(), Mockito.eq(CustomMetadataPolicyOperator.class));
+ operator.apply("changedValue", metadataPolicy("alwaysChanged"));
+ }
+
+ @Test(expectedExceptions = { ConstraintViolationException.class })
+ public void testNullId() {
+ Mockito.doThrow(CustomBeansException.class)
+ .when(applicationContext).getBean(Mockito.any(), Mockito.eq(CustomMetadataPolicyOperator.class));
+ operator.apply("changedValue", metadataPolicy(null));
+ }
+
+ @Test(expectedExceptions = { ConstraintViolationException.class })
+ public void testNonStringId() {
+ Mockito.doThrow(CustomBeansException.class)
+ .when(applicationContext).getBean(Mockito.any(), Mockito.eq(CustomMetadataPolicyOperator.class));
+ operator.apply("changedValue", metadataPolicy(1L));
+ }
+
+ @Nonnull protected MetadataPolicy metadataPolicy(final Object beanId) {
+ return new MetadataPolicy.Builder()
+ .withCustomOperator(BeanMetadataPolicyOperator.BEAN_OPERATOR_NAME, beanId)
+ .build();
+ }
+ protected CustomMetadataPolicyOperator alwaysSameOperator() {
+ return new CustomMetadataPolicyOperator() {
+
+ @Override
+ public Object apply(Object inputValue, MetadataPolicy policy) throws ConstraintViolationException {
+ return inputValue;
+ }
+
+ @Override
+ public boolean validate(MetadataPolicy policy) {
+ return true;
+ }
+ };
+ }
+
+ protected CustomMetadataPolicyOperator alwaysChangedOperator() {
+ return new CustomMetadataPolicyOperator() {
+
+ @Override
+ public Object apply(Object inputValue, MetadataPolicy policy) throws ConstraintViolationException {
+ return "changedValue";
+ }
+
+ @Override
+ public boolean validate(MetadataPolicy policy) {
+ return true;
+ }
+ };
+ }
+
+ protected CustomMetadataPolicyOperator alwaysFailingOperator() {
+ return new CustomMetadataPolicyOperator() {
+
+ @Override
+ public Object apply(Object inputValue, MetadataPolicy policy) throws ConstraintViolationException {
+ throw new ConstraintViolationException("mock");
+ }
+
+ @Override
+ public boolean validate(MetadataPolicy policy) {
+ return true;
+ }
+ };
+ }
+
+ @SuppressWarnings("serial")
+ class CustomBeansException extends BeansException {
+
+ public CustomBeansException(String msg) {
+ super(msg);
+ }
+
+ }
+}
diff --git a/oidc-common-metadata-impl/src/test/java/net/shibboleth/oidc/metadata/policy/impl/DefaultMetadataPolicyEnforcerTest.java b/oidc-common-metadata-impl/src/test/java/net/shibboleth/oidc/metadata/policy/impl/DefaultMetadataPolicyEnforcerTest.java
index 7995b56..a1fec01 100644
--- a/oidc-common-metadata-impl/src/test/java/net/shibboleth/oidc/metadata/policy/impl/DefaultMetadataPolicyEnforcerTest.java
+++ b/oidc-common-metadata-impl/src/test/java/net/shibboleth/oidc/metadata/policy/impl/DefaultMetadataPolicyEnforcerTest.java
@@ -16,12 +16,15 @@ package net.shibboleth.oidc.metadata.policy.impl;
import java.util.List;
+import org.mockito.Mockito;
import org.testng.Assert;
import org.testng.annotations.BeforeMethod;
import org.testng.annotations.Test;
import net.shibboleth.oidc.metadata.policy.MetadataPolicy;
+import net.shibboleth.shared.collection.CollectionSupport;
import net.shibboleth.shared.collection.Pair;
+import net.shibboleth.shared.logic.ConstraintViolationException;
/**
* Unit tests for {@link DefaultMetadataPolicyEnforcer}.
@@ -500,6 +503,26 @@ public class DefaultMetadataPolicyEnforcerTest {
new MetadataPolicy.Builder().withRegexp(regex).build()));
}
+ @Test
+ public void apply_whenCustomOperatorAcceptsValue_resultIsCandidateWithTrue() {
+ final String candidate = "expectdValue";
+ CustomMetadataPolicyOperator customOperator = Mockito.mock(CustomMetadataPolicyOperator.class);
+ Mockito.when(customOperator.apply(Mockito.any(), Mockito.any())).thenReturn(candidate);
+ applier.setCustomMetadataPolicyOperators(CollectionSupport.singletonMap("customOperator", customOperator));
+ assertResultEquals(applier.apply(candidate,
+ new MetadataPolicy.Builder().withCustomOperator("customOperator", "mockId").build()), candidate);
+ }
+
+ @Test
+ public void apply_whenCustomOperatorDoesNotAcceptValue_resultIsFalse() {
+ final String candidate = "expectdValue";
+ CustomMetadataPolicyOperator customOperator = Mockito.mock(CustomMetadataPolicyOperator.class);
+ Mockito.doThrow(ConstraintViolationException.class).when(customOperator).apply(Mockito.any(), Mockito.any());
+ applier.setCustomMetadataPolicyOperators(CollectionSupport.singletonMap("customOperator", customOperator));
+ assertResultFalse(applier.apply(candidate,
+ new MetadataPolicy.Builder().withCustomOperator("customOperator", "mockId").build()));
+ }
+
public static void assertResultEquals(final Pair<Object, Boolean> pair, final Object expected) {
final Boolean flag = pair.getSecond();
Assert.assertTrue(flag != null && flag);
diff --git a/oidc-common-metadata-impl/src/test/java/net/shibboleth/oidc/metadata/policy/impl/DefaultMetadataPolicyValidatorTest.java b/oidc-common-metadata-impl/src/test/java/net/shibboleth/oidc/metadata/policy/impl/DefaultMetadataPolicyValidatorTest.java
index a3acc6a..cd2c264 100644
--- a/oidc-common-metadata-impl/src/test/java/net/shibboleth/oidc/metadata/policy/impl/DefaultMetadataPolicyValidatorTest.java
+++ b/oidc-common-metadata-impl/src/test/java/net/shibboleth/oidc/metadata/policy/impl/DefaultMetadataPolicyValidatorTest.java
@@ -17,11 +17,13 @@ package net.shibboleth.oidc.metadata.policy.impl;
import java.util.List;
import java.util.Map;
+import org.mockito.Mockito;
import org.testng.Assert;
import org.testng.annotations.BeforeMethod;
import org.testng.annotations.Test;
import net.shibboleth.oidc.metadata.policy.MetadataPolicy;
+import net.shibboleth.shared.collection.CollectionSupport;
/**
* Unit tests for {@link DefaultMetadataPolicyValidator}.
@@ -277,4 +279,34 @@ public class DefaultMetadataPolicyValidatorTest {
}
+ @Test
+ public void test_whenCustomOperatorMissing_shouldReturnFalse() {
+ final Map<String, MetadataPolicy> map = Map.of("mockClaim", new MetadataPolicy.Builder()
+ .withCustomOperator("customOperator", "obsoleteValue")
+ .build());
+ Assert.assertFalse(validator.test(map));
+ }
+
+ @Test
+ public void test_whenCustomOperatorExists_noOtherPolicyItems_shouldReturnFalse_customValidationFails() {
+ final CustomMetadataPolicyOperator operator = Mockito.mock(CustomMetadataPolicyOperator.class);
+ Mockito.when(operator.validate(Mockito.any())).thenReturn(false);
+ validator.setCustomMetadataPolicyOperators(CollectionSupport.singletonMap("customOperator", operator));
+ final Map<String, MetadataPolicy> map = Map.of("mockClaim", new MetadataPolicy.Builder()
+ .withCustomOperator("customOperator", "obsoleteValue")
+ .build());
+ Assert.assertFalse(validator.test(map));
+ }
+
+ @Test
+ public void test_whenCustomOperatorExists_noOtherPolicyItems_shouldReturnTrue() {
+ final CustomMetadataPolicyOperator operator = Mockito.mock(CustomMetadataPolicyOperator.class);
+ Mockito.when(operator.validate(Mockito.any())).thenReturn(true);
+ validator.setCustomMetadataPolicyOperators(CollectionSupport.singletonMap("customOperator", operator));
+ final Map<String, MetadataPolicy> map = Map.of("mockClaim", new MetadataPolicy.Builder()
+ .withCustomOperator("customOperator", "obsoleteValue")
+ .build());
+ Assert.assertTrue(validator.test(map));
+ }
+
}
diff --git a/oidc-common-metadata-impl/src/test/java/net/shibboleth/oidc/metadata/policy/impl/OIDCMetadataPolicyResolverTest.java b/oidc-common-metadata-impl/src/test/java/net/shibboleth/oidc/metadata/policy/impl/OIDCMetadataPolicyResolverTest.java
index bdf7463..315500f 100644
--- a/oidc-common-metadata-impl/src/test/java/net/shibboleth/oidc/metadata/policy/impl/OIDCMetadataPolicyResolverTest.java
+++ b/oidc-common-metadata-impl/src/test/java/net/shibboleth/oidc/metadata/policy/impl/OIDCMetadataPolicyResolverTest.java
@@ -33,7 +33,9 @@ import net.shibboleth.oidc.metadata.cache.impl.DefaultJSONMapParsingStrategy;
import net.shibboleth.oidc.metadata.cache.impl.DefaultSourceMetadataExpirationTimeStrategy;
import net.shibboleth.oidc.metadata.cache.impl.MetadataCacheBuilder;
import net.shibboleth.oidc.metadata.policy.MetadataPolicy;
+import net.shibboleth.shared.collection.CollectionSupport;
import net.shibboleth.shared.component.ComponentInitializationException;
+import net.shibboleth.shared.logic.ConstraintViolationException;
import net.shibboleth.shared.resolver.CriteriaSet;
/**
@@ -45,12 +47,17 @@ public class OIDCMetadataPolicyResolverTest {
OIDCMetadataPolicyResolver resolver;
public void initTest(final String filename) throws Exception {
- resolver = new OIDCMetadataPolicyResolver(buildCache(filename));
+ initTest(filename, null);
+ }
+
+ public void initTest(final String filename, final CustomMetadataPolicyOperator customOperator) throws Exception {
+ resolver = new OIDCMetadataPolicyResolver(buildCache(filename, customOperator));
resolver.setId("mockId");
resolver.initialize();
}
-
- protected BatchMetadataCache<String, Map<String, MetadataPolicy>> buildCache(final String filename)
+
+ protected BatchMetadataCache<String, Map<String, MetadataPolicy>> buildCache(final String filename,
+ final CustomMetadataPolicyOperator customOperator)
throws IOException, ComponentInitializationException {
final Resource file = filename == null || filename.isEmpty()? null : new ClassPathResource(filename);
@@ -64,7 +71,11 @@ public class OIDCMetadataPolicyResolverTest {
spec.setSourceMetadataExpiryStrategy(new DefaultSourceMetadataExpirationTimeStrategy(Duration.ofMinutes(5)));
spec.setCriteriaToIdentifierStrategy(crit -> "id");
spec.setIdentifierExtractionStrategy(crit -> "id");
- spec.setMetadataValidPredicate(new DefaultMetadataPolicyValidator());
+ final DefaultMetadataPolicyValidator policyValidator = new DefaultMetadataPolicyValidator();
+ if (customOperator != null) {
+ policyValidator.setCustomMetadataPolicyOperators(CollectionSupport.singletonMap("bean", customOperator));
+ }
+ spec.setMetadataValidPredicate(policyValidator);
spec.setMatchRequired(true);
@@ -98,7 +109,67 @@ public class OIDCMetadataPolicyResolverTest {
Assert.assertTrue(iter.hasNext());
final Map<String, MetadataPolicy> client = iter.next();
Assert.assertEquals(client.size(), 6);
-
+ assertStandardOperators(client);
+ }
+
+ @Test
+ public void testFoundWithCustomFoundAndValid() throws Exception {
+ final CustomMetadataPolicyOperator customOperator = new CustomMetadataPolicyOperator() {
+
+ @Override
+ public boolean validate(final MetadataPolicy policy) {
+ return true;
+ }
+
+ @Override
+ public Object apply(final Object inputValue, final MetadataPolicy policy)
+ throws ConstraintViolationException {
+ return null;
+ }
+
+ };
+ initTest("/net/shibboleth/oidc/metadata/impl/metadata-policy1-custom.json", customOperator);
+ final Iterator<Map<String, MetadataPolicy>> iter = resolver.resolve(new CriteriaSet()).iterator();
+ Assert.assertTrue(iter.hasNext());
+ final Map<String, MetadataPolicy> client = iter.next();
+ Assert.assertEquals(client.size(), 6);
+ assertStandardOperators(client);
+ final MetadataPolicy clientName = client.get("client_name");
+ Assert.assertFalse(clientName.getCustomOperators().isEmpty());
+ final Object beanOperator = clientName.getCustomOperators().get("bean");
+ Assert.assertTrue(beanOperator != null);
+ Assert.assertEquals(beanOperator, "customMetadataPolicyOperator");
+ }
+
+ @Test
+ public void testFoundWithCustomFoundButNotValid() throws Exception {
+ final CustomMetadataPolicyOperator customOperator = new CustomMetadataPolicyOperator() {
+
+ @Override
+ public boolean validate(final MetadataPolicy policy) {
+ return false;
+ }
+
+ @Override
+ public Object apply(final Object inputValue, final MetadataPolicy policy)
+ throws ConstraintViolationException {
+ return null;
+ }
+
+ };
+ initTest("/net/shibboleth/oidc/metadata/impl/metadata-policy1-custom.json", customOperator);
+ final Iterator<Map<String, MetadataPolicy>> iter = resolver.resolve(new CriteriaSet()).iterator();
+ Assert.assertFalse(iter.hasNext());
+ }
+
+ @Test
+ public void testFoundWithCustomNotFound() throws Exception {
+ initTest("/net/shibboleth/oidc/metadata/impl/metadata-policy1-custom.json");
+ final Iterator<Map<String, MetadataPolicy>> iter = resolver.resolve(new CriteriaSet()).iterator();
+ Assert.assertFalse(iter.hasNext());
+ }
+
+ protected void assertStandardOperators(final Map<String, MetadataPolicy> client) {
final MetadataPolicy grantTypes = client.get("grant_types");
Assert.assertNotNull(grantTypes);
Assert.assertEquals(grantTypes.getOneOfValues(), List.of("authorization_code", "implicit"));
diff --git a/oidc-common-metadata-impl/src/test/resources/net/shibboleth/oidc/metadata/impl/metadata-policy1-custom.json b/oidc-common-metadata-impl/src/test/resources/net/shibboleth/oidc/metadata/impl/metadata-policy1-custom.json
new file mode 100644
index 0000000..e7b7be9
--- /dev/null
+++ b/oidc-common-metadata-impl/src/test/resources/net/shibboleth/oidc/metadata/impl/metadata-policy1-custom.json
@@ -0,0 +1,22 @@
+{
+ "grant_types": {
+ "one_of": ["authorization_code","implicit"]
+ },
+ "client_name": {
+ "default": "A known test application",
+ "bean": "customMetadataPolicyOperator"
+ },
+ "organization_name": {
+ "value": "A trusted organization"
+ },
+ "redirect_uris": {
+ "regexp": "^https:\/\/(?:([^.]+).)?example.org\/(.*)",
+ "essential": true
+ },
+ "id_token_signing_alg_values_supported": {
+ "subset_of": ["RS256", "RS384", "RS512"]
+ },
+ "scopes": {
+ "subset_of": ["openid", "profile", "email", "phone"]
+ }
+}
\ 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