diff --git a/src/main/java/uk/org/iay/incommon/mda/validate/string/AsLiteralTailStringValidator.java b/src/main/java/uk/org/iay/incommon/mda/validate/string/AsLiteralTailStringValidator.java new file mode 100644 index 0000000..167ee30 --- /dev/null +++ b/src/main/java/uk/org/iay/incommon/mda/validate/string/AsLiteralTailStringValidator.java @@ -0,0 +1,100 @@ +/* + * 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 uk.org.iay.incommon.mda.validate.string; + +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +import javax.annotation.Nonnull; + +import net.shibboleth.metadata.validate.Validator; +import uk.org.iay.incommon.mda.validate.BaseAsValidator; + +/** + * A Validator that assists in the validation of regular-expression <shibmd:Scope> + * values that include a literal tail. + * + * A literal tail is: + * + * + * + *

For example, the literal tail in the regular expression + * '^([a-zA-Z0-9-]{1,63}\.){0,2}ddd\.ccc\.bbb\.aa$' is 'ccc.bbb.aa'.

+ * + *

The literal tail is extracted from the regular expression, has its encoded '.' + * characters converted to normal ones, and then validated as a {@link String} by a new sequence of + * validators.

+ * + *

This validator fails (and returns {@link net.shibboleth.metadata.validate.Validator.Action#DONE}) if the + * value does not possess a literal tail.

+ * + *

Otherwise, the validator applies the sequence of validators to the new value and returns + * the value of that sequence.

+ */ +public class AsLiteralTailStringValidator extends BaseAsValidator + implements Validator { + + /** + * Regular expression to match and extract the literal tail. + * + * The component parts of this expression are: + * + * + * + *

The matching of DNS labels is not exact. For example, labels starting or ending with hyphens + * are accepted as part of a literal tail. This will normally be detected by the nested validator + * sequence applied to the result.

+ * + *

Similarly, upper-case characters are permitted in the literal tail although these would + * not normally be permitted in scopes. Again, these characters are permitted so that a more + * specific error can be reported, rather than just a generic failure to convert.

+ */ + private final Pattern pattern = Pattern.compile(".*?\\\\.(([a-zA-Z0-9-]+\\\\.)+[a-zA-Z0-9-]+)\\$"); + + @Override + protected String convert(@Nonnull final String regex) throws IllegalArgumentException { + // Match against the regular expression + final Matcher matcher = pattern.matcher(regex); + + // If the pattern does not match, signal that the string does not have a literal tail + if (!matcher.matches()) { + throw new IllegalArgumentException(); + } + + // Remove all '\' characters from the result. + return matcher.group(1).replaceAll("\\\\", ""); + } + +} diff --git a/src/main/resources/uk/org/iay/incommon/mda/beans.xml b/src/main/resources/uk/org/iay/incommon/mda/beans.xml index d6e4cc4..6939823 100644 --- a/src/main/resources/uk/org/iay/incommon/mda/beans.xml +++ b/src/main/resources/uk/org/iay/incommon/mda/beans.xml @@ -47,6 +47,9 @@ + + diff --git a/src/test/java/uk/org/iay/incommon/mda/validate/string/AsLiteralTailStringValidatorTest.java b/src/test/java/uk/org/iay/incommon/mda/validate/string/AsLiteralTailStringValidatorTest.java new file mode 100644 index 0000000..10fe9fd --- /dev/null +++ b/src/test/java/uk/org/iay/incommon/mda/validate/string/AsLiteralTailStringValidatorTest.java @@ -0,0 +1,67 @@ + +package uk.org.iay.incommon.mda.validate.string; + +import java.util.ArrayList; +import java.util.List; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +import org.testng.Assert; +import org.testng.annotations.Test; + +import net.shibboleth.metadata.Item; +import net.shibboleth.metadata.pipeline.StageProcessingException; +import net.shibboleth.metadata.validate.Validator; +import net.shibboleth.metadata.validate.Validator.Action; +import uk.org.iay.incommon.mda.validate.BaseLocalValidator; +import uk.org.ukfederation.mda.MockItem; + +public class AsLiteralTailStringValidatorTest { + + private static class CountingCapturingValidator extends BaseLocalValidator implements Validator { + public int count; + public String value; + private final Action action; + + @Override + public Action validate(String e, Item item, String stageId) throws StageProcessingException { + count++; + value = e; + return action; + } + + /** Constructor. */ + public CountingCapturingValidator(final Action a) { + action = a; + } + } + + @Test + public void testAssumptions() throws Exception { + final Pattern pattern = Pattern.compile(".*?\\\\.(([a-zA-Z0-9-]+\\\\.)+[a-zA-Z0-9-]+)\\$"); + final String value = "^([a-zA-Z0-9-]{1,63}\\.){0,2}vho\\.aaf\\.edu\\.au$"; + final Matcher matcher = pattern.matcher(value); + Assert.assertTrue(matcher.matches()); + } + + @Test + public void testExample() throws Exception { + final CountingCapturingValidator ccv = new CountingCapturingValidator(Action.CONTINUE); + ccv.setId("ccv"); + ccv.initialize(); + + final List> nvs = new ArrayList<>(); + nvs.add(ccv); + + final AsLiteralTailStringValidator val = new AsLiteralTailStringValidator(); + val.setId("val"); + val.setValidators(nvs); + val.initialize(); + + final Item item = new MockItem("content"); + Assert.assertEquals(val.validate("^([a-zA-Z0-9-]{1,63}\\.){0,2}vho\\.aaf\\.edu\\.au$", item, "stage"), Action.CONTINUE); + Assert.assertEquals(ccv.count, 1); + Assert.assertEquals(ccv.value, "aaf.edu.au"); + } + +}