URLPatternMatcherTest.java revision c4329510051cce0c6b3efc1fae122ec4c5d61efa
/*
* The contents of this file are subject to the terms of the Common Development and
* Distribution License (the License). You may not use this file except in compliance with the
* License.
*
* You can obtain a copy of the License at legal/CDDLv1.0.txt. See the License for the
* specific language governing permission and limitations under the License.
*
* When distributing Covered Software, include this CDDL Header Notice in each file and include
* the License file at legal/CDDLv1.0.txt. If applicable, add the following below the CDDL
* Header, with the fields enclosed by brackets [] replaced by your own identifying
* information: "Portions copyright [year] [name of copyright owner]".
*
* Copyright 2014 ForgeRock AS.
*/
/**
* This tests for wildcard matching for whitelisting. This is NOT the same
* system as used by policy matching. Specifically:
*
* Wildcard is always single-level only (until the next slash), unless it's the last value, and
* it's preceeded by the delimiter.
*
* A combination of delimiter-wildcard (e.g. /*) at the end of a URL's path will
* continue to match indefinitely.
*
* When matching query parameters, use the single-level-only wildcard (default -*-) instead
* of the standard wildcard to continue to enforce a precise number of levels prior to the
* quesiton mark. See tests eighteen and nineteen for examples.
*
*/
public class URLPatternMatcherTest {
private void performTestAndAssert(String url, boolean result, String pattern) throws MalformedURLException {
boolean answer = urlPatternMatcher.match(url, Collections.singleton(pattern), true); //wildcard always enabled
}
return new Object[][]{
{"https://www.google.com:443/hello/there", false},
{"https://www.google.com:443/hello/there/", true}
};
}
// tests basic matching, including trailing slash
}
public Object[][] testBasicOne() {
return new Object[][]{
{"http://www.good.com", true},
{"http://www.good.com/", true},
{"http://www.good.com:80", true},
{"http://www.good.com:80/", true},
{"http://www.good.com:80/hello/world", false},
{"https://www.hello.good.com", false},
{"https://www.hello.good.com:443", false},
{"https://www.hello.good.com:443/hello/world", false},
{"http://www.hello.good.com/hello/world", false},
{"http://www.hello.good.com/hello/world?key=value", false},
{"http://www.hello.good.com:80/hello/world", false},
};
}
// tests basic matching, without trailing slash
}
public Object[][] testBasicTwo() {
return new Object[][]{
{"http://www.good.com", false},
{"http://www.good.com/", false},
{"http://www.good.com:80", false},
{"http://www.good.com:80/", false},
{"http://www.good.com/hello.html", true},
{"http://www.good.com/hello.html/", false},
{"http://www.good.com:80/hello.html", true},
{"http://www.good.com:80/hello.html/", false},
{"http://www.good.com:80/hello/world", false},
{"https://www.hello.good.com", false},
{"https://www.hello.good.com:443", false},
{"https://www.hello.good.com:443/hello/world", false},
{"http://www.hello.good.com/hello/world", false},
{"http://www.hello.good.com/hello/world?key=value", false},
{"http://www.hello.good.com:80/hello/world", false},
};
}
// tests basic matching with path
}
return new Object[][] {
{"http://www.good.com", true},
{"http://www.good.com/", true},
{"http://www.good.com:80", true},
{"http://www.good.com:80/", true},
{"http://www.good.com:80/hello/world", true},
{"https://www.good.com", true},
{"https://www.good.com/", true},
{"https://www.good.com:443", true},
{"https://www.good.com:443/", true},
{"https://www.good.com:443/hello/world", true},
{"http://www.good.com/hello/world", true},
{"http://www.good.com/hello/world?key=value", false},
{"http://www.good.com:80/hello/world", true},
{"http://www.good.com:80/hello/world?key=value", false},
};
}
// tests basic wildcards, should match everything except URLs with question marks in path
}
return new Object[][] {
{"http://www.good.com", true},
{"http://www.good.com:80", true},
{"http://www.good.com:80/hello/world", false},
{"https://www.good.com", false},
{"https://www.good.com:443", false},
{"https://www.good.com:443/hello/world", false},
{"http://www.good.com/hello/world", false},
{"http://www.good.com/hello/world?key=value", false},
{"http://www.good.com:80/hello/world", false},
{"http://www.good.com:80/hello/world?key=value", false},
{"http://www.bad.com:80/hello/world/.good.com:80", false},
};
}
//testing wildcard in-location. Should only match domain, and default port (with or without trailing slash)
}
return new Object[][] {
{"http://www.good.com", true},
{"http://www.good.com:80", true},
{"http://www.good.com:80/hello/world", false},
{"https://www.good.com", false},
{"https://www.good.com:443", false},
{"https://www.good.com:443/hello/world", false},
{"http://www.good.com/hello/world", false},
{"http://www.good.com/hello/world?key=value", false},
{"http://www.good.com:80/hello/world", false},
{"http://www.good.com:80/hello/world?key=value", false},
{"http://www.bad.com:80/hello/world/.good.com:80", false},
{"http://bad.com:80/hello/world/.good.com:80", false},
};
}
//as above, but allows the port to be anything other than 80
}
return new Object[][] {
{"http://www.good.com", true},
{"http://www.good.com:80", true},
{"http://www.good.com:80/hello/world", true},
{"https://www.good.com", false},
{"https://www.good.com:443", false},
{"https://www.good.com:443/hello/world", false},
{"http://www.good.com/hello/world", true},
{"http://www.good.com/hello/world?key=value", false},
{"http://www.good.com:80/hello/world", true},
{"http://www.good.com:80/hello/world?key=value", false},
{"http://www.bad.com:80/hello/world", true},
{"http://www.bad.com", true},
{"http://www.bad.com:80", true},
};
}
//default port, random host and random path of indeterminable length (excluding question mark)
}
return new Object[][] {
{"http://www.good.com", true},
{"http://www.good.com/", true},
{"http://www.good.com:80", true},
{"http://www.good.com:80/", true},
{"http://www.good.com:80/hello/world", false},
{"https://www.good.com", false},
{"https://www.good.com:443", false},
{"https://www.good.com:443/hello/world", false},
{"http://www.good.com/hello/world", false},
{"http://www.good.com/hello/world?key=value", false},
{"http://www.good.com:80/hello/world", false},
{"http://www.good.com:80/hello/world?key=value", false},
{"http://www.bad.com:80/hello/world/.good.com:80", false},
};
}
//random domain, random port, no path but allowed to have optional trailing slash (see testThree)
}
return new Object[][] {
{"http://www.good.com", false},
{"http://www.good.com:80", false},
{"http://www.good.com:80/hello/world", false},
{"http://www.hello.good.com", true},
{"http://www.hello.good.com/", true},
{"http://www.hello.good.com:80", true},
{"http://www.hello.good.com:80/", true},
{"http://www.hello.good.com:80/hello/world", false},
{"https://www.hello.good.com", false},
{"https://www.hello.good.com:443", false},
{"https://www.hello.good.com:443/hello/world", false},
{"http://www.hello.good.com/hello/world", false},
{"http://www.hello.good.com/hello/world?key=value", false},
{"http://www.hello.good.com:80/hello/world", false},
};
}
//random subdomain, but only so long as it's actually a subdomain and not part of the path
}
return new Object[][] {
{"http://www.hello.good.com", true},
{"http://www.hello.good.com/", true},
{"http://www.hello.good.com:80", true},
{"http://www.hello.good.com:80/", true},
{"http://www.hello.good.com:80/hello/world", false},
{"https://www.hello.good.com", false},
{"https://www.hello.good.com:443", false},
{"https://www.hello.good.com:443/hello/world", false},
{"http://www.hello.good.com/hello/world", false},
{"http://www.hello.good.com/hello/world?key=value", false},
{"http://www.hello.good.com:80/hello/world", false},
};
}
//random subdomain with trailing slash, same as testSix in different format
}
return new Object[][] {
{"http://www.hello.good.com", true},
{"http://www.hello.good.com:80", true},
{"http://www.hello.good.com:80/hello/world", true},
{"https://www.hello.good.com", false},
{"https://www.hello.good.com:443", false},
{"https://www.hello.good.com:443/hello/world", false},
{"http://www.hello.good.com/hello/world", true},
{"http://www.hello.good.com/hello/world?key=value", false},
{"http://www.hello.good.com:80/hello/world", true},
};
}
//random subdomain, default port, indeterminable length path, no question marks
}
return new Object[][] {
{"https://www.good.com", false},
{"https://www.good.com/", false},
{"https://www.good.com:443", false},
{"https://www.good.com:443/", false},
{"http://www.hello.good.com/path/", false},
{"https://www.hello.good.com/path/", true},
{"https://www.hello.good.com/", true},
{"https://www.hello.good.com", true},
{"https://www.good.com:443/path/", false},
{"https://www.subdomain.good.com:443/path/", true},
{"https://www.bad.com/.good.com:443/evil", false},
{"https://www.hello.good.com:80/path/", true},
{"https://www.bad.com:443/.good.com:443/evil", false}
};
}
//random subdomain, random port random path of indeterminable length, no question marks
}
return new Object[][] {
{"https://www.one.good.com", false},
{"https://www.one.good.com:80", false},
{"https://www.good.com/bad", false},
{"https://www.bad.com/.good.com", false},
{"https://www.one.good.com/hello/blah", true},
{"https://www.one.good.com/hello/world/blah", false},
};
}
//testing single-level wildcards. After the (random) port, should have a single level before blah
}
public Object[][] testEleven() {
return new Object[][] {
{"http://www.good.com", false},
{"http://www.good.com:80", false},
{"http://www.good.com:80/hello/world", false},
{"https://www.good.com", false},
{"https://www.good.com:443", false},
{"https://www.good.com:443/hello/world", false},
{"http://www.good.com/hello/world", false},
{"http://www.good.com/hello/world?key=value", true},
{"http://www.good.com:80/hello/world", false},
{"http://www.good.com:80/hello/world?", true},
{"http://www.good.com:80/hello/world?key=value", true},
{"http://www.bad.com:80/hello/world/.good.com:80", false},
};
}
//allows for anything which contains a question mark in it, regardless of scheme, host or port
}
public Object[][] testTwelve() {
return new Object[][] {
{"http://www.good.com", false},
{"http://www.good.com:80", false},
{"http://www.good.com:80/hello/world", false},
{"https://www.good.com", false},
{"https://www.good.com:443", false},
{"https://www.good.com:443/hello/world", false},
{"http://www.good.com/hello/world", false},
{"http://www.good.com/hello/world?key=value", true},
{"http://www.good.com:80/hello/world", false},
{"http://www.good.com:80/hello/world?key=value", true},
{"http://www.bad.com:80/hello/world/.good.com:80", false},
};
}
//random subdomain, default port, any length path with question mark
}
public Object[][] testThirteen() {
return new Object[][] {
{"http://www.good.com", false},
{"http://www.good.com:80", false},
{"http://www.good.com:80/hello/world", false},
{"http://www.good.com:80/abc/world", true},
{"http://www.good.com:80/abc", true},
{"http://www.good.com/abc", true},
{"https://www.good.com", false},
{"https://www.good.com:443", false},
{"http://www.good.com/hello/world", false},
{"http://www.good.com/hello/world?key=value", false},
{"http://www.good.com:80/hello/world", false},
{"http://www.good.com:80/hello/world?key=value", false},
{"http://www.bad.com:80/hello/world/.good.com:80", false},
};
}
}
return new Object[][] {
{"http://www.good.com", true},
{"http://www.good.com:80", true},
{"http://www.good.com:808", true},
{"http://www.good.com:808/", true},
{"http://www.good.com:808/asdf", false},
{"http://www.good.com:80/hello/world", false},
{"http://www.good.com:80/abc/world", false},
{"http://www.good.com:80/abc", false},
{"http://www.good.com/abc", false},
{"https://www.good.com", false},
{"https://www.good.com:443", false},
{"http://www.good.com/hello/world", false},
{"http://www.good.com/hello/world?key=value", false},
{"http://www.good.com:80/hello/world?key=value", false},
{"http://www.bad.com:80/hello/world/.good.com:80", false},
};
}
//wildcard after port
}
public Object[][] testFifteen() {
return new Object[][] {
{"https://www.good.com", false},
{"https://www.good.com/", false},
{"https://www.bad.good.com/", true},
{"https://www.good.com:443", false},
{"https://www.good.com:443/", false},
{"http://www.hello.good.com/path/", false},
{"https://www.hello.good.com/path/", true},
{"https://www.good.com:443/path/", false},
{"https://www.subdomain.good.com:443/path/", true},
{"https://www.bad.com/.good.com:443/evil", false},
{"https://www.hello.good.com:80/path/", false},
{"https://www.bad.com:443/.good.com:443/evil", false}
};
}
//any subdomain, any path
}
public Object[][] testSixteen() {
return new Object[][] {
{"https://www.good.com", false},
{"https://www.good.com/", false},
{"https://www.bad.good.com/", false},
{"https://www.good.com:443", false},
{"https://www.good.com:443/", false},
{"http://www.hello.good.com/path/", false},
{"https://www.hello.good.com/path/", false},
{"https://www.good.com:443/path/", false},
{"https://www.subdomain.good.com:443/path/", false},
{"https://www.bad.com/.good.com:443/evil", false},
{"http://www.hello.good.com:80/asdf123/path/blah", false},
{"https://www.good.com:443/asdf123/blah", true},
{"https://www.good.com:443/asdf123/456/blah", false},
{"https://www.bad.com:443/.good.com:443/evil", false}
};
}
//continuation after "asdf", but no additional path elements
}
public Object[][] testSeventeen() {
return new Object[][] {
{"http://www.good.com", false},
{"http://www.good.com:80", false},
{"http://www.good.com:80/hello/bob/hello/?bob=bob", false},
{"http://www.good.com:80/hello/bob?bob=bob", false},
{"http://www.good.com:80/hello/world/", false},
{"http://www.good.com:80/hello/world", false},
{"http://www.good.com:80/hello/?bob=bob", false}
};
}
//precisely two levels after port and before question mark
}
//how to use special (single-level) matchers when also using a question mark:
public Object[][] testEighteen() {
return new Object[][] {
{"http://www.good.com", false},
{"http://www.good.com:80", false},
{"http://www.good.com:80/hello/bob/?bob=bob", true},
{"http://www.good.com:80/hello/bob?bob=bob", true},
{"http://www.good.com:80/hello?bob=bob", false},
{"http://www.good.com:80/hello/world/", false},
{"http://www.good.com:80/hello/world", false},
{"http://www.good.com:80/hello/?bob=bob", false}
};
}
//optional path-element before question mark, exactly two levels before that
}
public Object[][] testNineteen() {
return new Object[][] {
{"http://www.good.com", false},
{"http://www.good.com:80", false},
{"http://www.good.com:80/hello/bob/hello/again/and/again?bob=bob", true}, //seems odd - see testEighteen
{"http://www.good.com:80/hello/bob/?bob=bob", true},
{"http://www.good.com:80/hello/bob?bob=bob", false},
{"http://www.good.com:80/hello?bob=bob", false},
{"http://www.good.com:80/hello/world/", false},
{"http://www.good.com:80/hello/world", false},
{"http://www.good.com:80/hello/?bob=bob", false}
};
}
//optional path-element before question mark, two (or more) levels before that (but not fewer)
}
}