Repository: knox Updated Branches: refs/heads/master 39aa06ee8 -> ddaf373fc
KNOX-635 - Provide Whitelisting for Redirect Destinations for KnoxSSO Project: http://git-wip-us.apache.org/repos/asf/knox/repo Commit: http://git-wip-us.apache.org/repos/asf/knox/commit/ddaf373f Tree: http://git-wip-us.apache.org/repos/asf/knox/tree/ddaf373f Diff: http://git-wip-us.apache.org/repos/asf/knox/diff/ddaf373f Branch: refs/heads/master Commit: ddaf373fc14e0ae10d6ead8660673681774d8320 Parents: 39aa06e Author: Larry McCay <[email protected]> Authored: Thu Nov 26 14:08:11 2015 -0500 Committer: Larry McCay <[email protected]> Committed: Thu Nov 26 14:08:11 2015 -0500 ---------------------------------------------------------------------- gateway-service-knoxsso/pom.xml | 4 ++ .../service/knoxsso/KnoxSSOMessages.java | 4 ++ .../gateway/service/knoxsso/WebSSOResource.java | 15 +++++++ .../service/knoxsso/WebSSOResourceTest.java | 33 +++++++++++++++ .../apache/hadoop/gateway/util/RegExUtils.java | 43 ++++++++++++++++++++ 5 files changed, 99 insertions(+) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/knox/blob/ddaf373f/gateway-service-knoxsso/pom.xml ---------------------------------------------------------------------- diff --git a/gateway-service-knoxsso/pom.xml b/gateway-service-knoxsso/pom.xml index b3c2d92..d608853 100644 --- a/gateway-service-knoxsso/pom.xml +++ b/gateway-service-knoxsso/pom.xml @@ -35,6 +35,10 @@ <dependencies> <dependency> <groupId>${gateway-group}</groupId> + <artifactId>gateway-util-common</artifactId> + </dependency> + <dependency> + <groupId>${gateway-group}</groupId> <artifactId>gateway-spi</artifactId> </dependency> <dependency> http://git-wip-us.apache.org/repos/asf/knox/blob/ddaf373f/gateway-service-knoxsso/src/main/java/org/apache/hadoop/gateway/service/knoxsso/KnoxSSOMessages.java ---------------------------------------------------------------------- diff --git a/gateway-service-knoxsso/src/main/java/org/apache/hadoop/gateway/service/knoxsso/KnoxSSOMessages.java b/gateway-service-knoxsso/src/main/java/org/apache/hadoop/gateway/service/knoxsso/KnoxSSOMessages.java index 598fb99..0c7ec87 100644 --- a/gateway-service-knoxsso/src/main/java/org/apache/hadoop/gateway/service/knoxsso/KnoxSSOMessages.java +++ b/gateway-service-knoxsso/src/main/java/org/apache/hadoop/gateway/service/knoxsso/KnoxSSOMessages.java @@ -59,4 +59,8 @@ public interface KnoxSSOMessages { @Message( level = MessageLevel.INFO, text = "The cookie max age is being set to: {0}.") void setMaxAge(String age); + + @Message( level = MessageLevel.ERROR, text = "The original URL: {0} for redirecting back after authentication is " + + "not valid according to the configured whitelist: {1}. See documentation for KnoxSSO Whitelisting.") + void whiteListMatchFail(String original, String whitelist); } \ No newline at end of file http://git-wip-us.apache.org/repos/asf/knox/blob/ddaf373f/gateway-service-knoxsso/src/main/java/org/apache/hadoop/gateway/service/knoxsso/WebSSOResource.java ---------------------------------------------------------------------- diff --git a/gateway-service-knoxsso/src/main/java/org/apache/hadoop/gateway/service/knoxsso/WebSSOResource.java b/gateway-service-knoxsso/src/main/java/org/apache/hadoop/gateway/service/knoxsso/WebSSOResource.java index 4bab18c..f23bbbe 100644 --- a/gateway-service-knoxsso/src/main/java/org/apache/hadoop/gateway/service/knoxsso/WebSSOResource.java +++ b/gateway-service-knoxsso/src/main/java/org/apache/hadoop/gateway/service/knoxsso/WebSSOResource.java @@ -40,6 +40,7 @@ import org.apache.hadoop.gateway.services.GatewayServices; import org.apache.hadoop.gateway.services.security.token.JWTokenAuthority; import org.apache.hadoop.gateway.services.security.token.TokenServiceException; import org.apache.hadoop.gateway.services.security.token.impl.JWT; +import org.apache.hadoop.gateway.util.RegExUtils; import org.apache.hadoop.gateway.util.Urls; import static javax.ws.rs.core.MediaType.APPLICATION_JSON; @@ -50,6 +51,7 @@ public class WebSSOResource { private static final String SSO_COOKIE_SECURE_ONLY_INIT_PARAM = "knoxsso.cookie.secure.only"; private static final String SSO_COOKIE_MAX_AGE_INIT_PARAM = "knoxsso.cookie.max.age"; private static final String SSO_COOKIE_TOKEN_TTL_PARAM = "knoxsso.token.ttl"; + private static final String SSO_COOKIE_TOKEN_WHITELIST_PARAM = "knoxsso.redirect.whitelist.regex"; private static final String ORIGINAL_URL_REQUEST_PARAM = "originalUrl"; private static final String ORIGINAL_URL_COOKIE_NAME = "original-url"; private static final String JWT_COOKIE_NAME = "hadoop-jwt"; @@ -58,6 +60,7 @@ public class WebSSOResource { private boolean secureOnly = true; private int maxAge = -1; private long tokenTTL = 30000l; + private String whitelist = null; @Context private HttpServletRequest request; @@ -89,6 +92,12 @@ public class WebSSOResource { } } + whitelist = context.getInitParameter(SSO_COOKIE_TOKEN_WHITELIST_PARAM); + if (whitelist == null) { + // default to local/relative targets + whitelist = "^/.*$"; + } + String ttl = context.getInitParameter(SSO_COOKIE_TOKEN_TTL_PARAM); if (ttl != null) { try { @@ -126,6 +135,12 @@ public class WebSSOResource { log.originalURLNotFound(); throw new WebApplicationException("Original URL not found in the request.", Response.Status.BAD_REQUEST); } + boolean validRedirect = RegExUtils.checkWhitelist(whitelist, original); + if (!validRedirect) { + log.whiteListMatchFail(original, whitelist); + throw new WebApplicationException("Original URL not valid according to the configured whitelist.", + Response.Status.BAD_REQUEST); + } } JWTokenAuthority ts = services.getService(GatewayServices.TOKEN_SERVICE); http://git-wip-us.apache.org/repos/asf/knox/blob/ddaf373f/gateway-service-knoxsso/src/test/java/org/apache/hadoop/gateway/service/knoxsso/WebSSOResourceTest.java ---------------------------------------------------------------------- diff --git a/gateway-service-knoxsso/src/test/java/org/apache/hadoop/gateway/service/knoxsso/WebSSOResourceTest.java b/gateway-service-knoxsso/src/test/java/org/apache/hadoop/gateway/service/knoxsso/WebSSOResourceTest.java index 769e497..4d97f0b 100644 --- a/gateway-service-knoxsso/src/test/java/org/apache/hadoop/gateway/service/knoxsso/WebSSOResourceTest.java +++ b/gateway-service-knoxsso/src/test/java/org/apache/hadoop/gateway/service/knoxsso/WebSSOResourceTest.java @@ -17,6 +17,7 @@ */ package org.apache.hadoop.gateway.service.knoxsso; +import org.apache.hadoop.gateway.util.RegExUtils; import org.junit.Assert; import org.junit.Test; @@ -37,4 +38,36 @@ public class WebSSOResourceTest { // ip addresses can not be wildcarded - may be a completely different domain Assert.assertTrue(resource.getDomainName("http://127.0.0.1").equals("127.0.0.1")); } + + @Test + public void testWhitelistMatching() throws Exception { + String whitelist = "^https?://.*example.com:8080/.*$;" + + "^https?://.*example.com/.*$;" + + "^https?://.*example2.com:\\d{0,9}/.*$"; + + // match on explicit hostname/domain and port + Assert.assertTrue("Failed to match whitelist", RegExUtils.checkWhitelist(whitelist, + "http://host.example.com:8080/")); + // match on non-required port + Assert.assertTrue("Failed to match whitelist", RegExUtils.checkWhitelist(whitelist, + "http://host.example.com/")); + // match on required but any port + Assert.assertTrue("Failed to match whitelist", RegExUtils.checkWhitelist(whitelist, + "http://host.example2.com:1234/")); + // fail on missing port + Assert.assertFalse("Matched whitelist inappropriately", RegExUtils.checkWhitelist(whitelist, + "http://host.example2.com/")); + // fail on invalid port + Assert.assertFalse("Matched whitelist inappropriately", RegExUtils.checkWhitelist(whitelist, + "http://host.example.com:8081/")); + // fail on alphanumeric port + Assert.assertFalse("Matched whitelist inappropriately", RegExUtils.checkWhitelist(whitelist, + "http://host.example.com:A080/")); + // fail on invalid hostname/domain + Assert.assertFalse("Matched whitelist inappropriately", RegExUtils.checkWhitelist(whitelist, + "http://host.example.net:8080/")); + // fail on required port + Assert.assertFalse("Matched whitelist inappropriately", RegExUtils.checkWhitelist(whitelist, + "http://host.example2.com/")); + } } http://git-wip-us.apache.org/repos/asf/knox/blob/ddaf373f/gateway-util-common/src/main/java/org/apache/hadoop/gateway/util/RegExUtils.java ---------------------------------------------------------------------- diff --git a/gateway-util-common/src/main/java/org/apache/hadoop/gateway/util/RegExUtils.java b/gateway-util-common/src/main/java/org/apache/hadoop/gateway/util/RegExUtils.java new file mode 100644 index 0000000..0171a3e --- /dev/null +++ b/gateway-util-common/src/main/java/org/apache/hadoop/gateway/util/RegExUtils.java @@ -0,0 +1,43 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF 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 org.apache.hadoop.gateway.util; + +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +public class RegExUtils { + /** + * Checks for a match of a given string against + * a whitelist of semi-colon separated regex patterns. + * @param whitelist - semi-colon separated patterns + * @param tomatch - the string to match against list + * @return true for a match otherwise false + */ + public static boolean checkWhitelist(String whitelist, String tomatch) { + String[] patterns = whitelist.split(";"); + for (String patternString : patterns) { + Pattern pattern = Pattern.compile(patternString); + Matcher matcher = pattern.matcher(tomatch); + if (matcher.matches()) { + return true; + } + } + return false; + } + +}
