Repository: knox Updated Branches: refs/heads/master 90f1df7f5 -> 5de920bd0
KNOX-1069 - KnoxSSO token audience config should trim values Project: http://git-wip-us.apache.org/repos/asf/knox/repo Commit: http://git-wip-us.apache.org/repos/asf/knox/commit/5de920bd Tree: http://git-wip-us.apache.org/repos/asf/knox/tree/5de920bd Diff: http://git-wip-us.apache.org/repos/asf/knox/diff/5de920bd Branch: refs/heads/master Commit: 5de920bd092d2822a32aa546d01bb8e64de3a5a9 Parents: 90f1df7 Author: Colm O hEigeartaigh <cohei...@apache.org> Authored: Wed Oct 4 11:00:40 2017 +0100 Committer: Colm O hEigeartaigh <cohei...@apache.org> Committed: Wed Oct 4 11:00:40 2017 +0100 ---------------------------------------------------------------------- .../jwt/filter/AbstractJWTFilter.java | 2 +- .../federation/AbstractJWTFilterTest.java | 31 +++++++++++ .../gateway/service/knoxsso/WebSSOResource.java | 2 +- .../service/knoxsso/WebSSOResourceTest.java | 58 ++++++++++++++++++++ .../service/knoxtoken/TokenResource.java | 2 +- .../knoxtoken/TokenServiceResourceTest.java | 58 ++++++++++++++++++++ 6 files changed, 150 insertions(+), 3 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/knox/blob/5de920bd/gateway-provider-security-jwt/src/main/java/org/apache/hadoop/gateway/provider/federation/jwt/filter/AbstractJWTFilter.java ---------------------------------------------------------------------- diff --git a/gateway-provider-security-jwt/src/main/java/org/apache/hadoop/gateway/provider/federation/jwt/filter/AbstractJWTFilter.java b/gateway-provider-security-jwt/src/main/java/org/apache/hadoop/gateway/provider/federation/jwt/filter/AbstractJWTFilter.java index d4c6717..7f8e733 100644 --- a/gateway-provider-security-jwt/src/main/java/org/apache/hadoop/gateway/provider/federation/jwt/filter/AbstractJWTFilter.java +++ b/gateway-provider-security-jwt/src/main/java/org/apache/hadoop/gateway/provider/federation/jwt/filter/AbstractJWTFilter.java @@ -118,7 +118,7 @@ public abstract class AbstractJWTFilter implements Filter { String[] audArray = expectedAudiences.split(","); audList = new ArrayList<String>(); for (String a : audArray) { - audList.add(a); + audList.add(a.trim()); } } return audList; http://git-wip-us.apache.org/repos/asf/knox/blob/5de920bd/gateway-provider-security-jwt/src/test/java/org/apache/hadoop/gateway/provider/federation/AbstractJWTFilterTest.java ---------------------------------------------------------------------- diff --git a/gateway-provider-security-jwt/src/test/java/org/apache/hadoop/gateway/provider/federation/AbstractJWTFilterTest.java b/gateway-provider-security-jwt/src/test/java/org/apache/hadoop/gateway/provider/federation/AbstractJWTFilterTest.java index bdde3e6..bd34c04 100644 --- a/gateway-provider-security-jwt/src/test/java/org/apache/hadoop/gateway/provider/federation/AbstractJWTFilterTest.java +++ b/gateway-provider-security-jwt/src/test/java/org/apache/hadoop/gateway/provider/federation/AbstractJWTFilterTest.java @@ -203,6 +203,37 @@ public abstract class AbstractJWTFilterTest { } @Test + public void testValidAudienceJWTWhitespace() throws Exception { + try { + Properties props = getProperties(); + props.put(getAudienceProperty(), " foo, bar "); + handler.init(new TestFilterConfig(props)); + + SignedJWT jwt = getJWT("alice", new Date(new Date().getTime() + 5000), privateKey, props); + + HttpServletRequest request = EasyMock.createNiceMock(HttpServletRequest.class); + setTokenOnRequest(request, jwt); + + EasyMock.expect(request.getRequestURL()).andReturn( + new StringBuffer(SERVICE_URL)).anyTimes(); + EasyMock.expect(request.getQueryString()).andReturn(null); + HttpServletResponse response = EasyMock.createNiceMock(HttpServletResponse.class); + EasyMock.expect(response.encodeRedirectURL(SERVICE_URL)).andReturn( + SERVICE_URL); + EasyMock.replay(request); + + TestFilterChain chain = new TestFilterChain(); + handler.doFilter(request, response, chain); + Assert.assertTrue("doFilterCalled should not be false.", chain.doFilterCalled ); + Set<PrimaryPrincipal> principals = chain.subject.getPrincipals(PrimaryPrincipal.class); + Assert.assertTrue("No PrimaryPrincipal", !principals.isEmpty()); + Assert.assertEquals("Not the expected principal", "alice", ((Principal)principals.toArray()[0]).getName()); + } catch (ServletException se) { + fail("Should NOT have thrown a ServletException."); + } + } + + @Test public void testValidVerificationPEM() throws Exception { try { Properties props = getProperties(); http://git-wip-us.apache.org/repos/asf/knox/blob/5de920bd/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 0d9e6dd..70228d3 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 @@ -127,7 +127,7 @@ public class WebSSOResource { if (audiences != null) { String[] auds = audiences.split(","); for (int i = 0; i < auds.length; i++) { - targetAudiences.add(auds[i]); + targetAudiences.add(auds[i].trim()); } } http://git-wip-us.apache.org/repos/asf/knox/blob/5de920bd/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 4e9e76b..568f0fe 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 @@ -229,6 +229,64 @@ public class WebSSOResourceTest { assertTrue(audiences.contains("recipient2")); } + @Test + public void testAudiencesWhitespace() throws Exception { + + ServletContext context = EasyMock.createNiceMock(ServletContext.class); + EasyMock.expect(context.getInitParameter("knoxsso.cookie.name")).andReturn(null); + EasyMock.expect(context.getInitParameter("knoxsso.cookie.secure.only")).andReturn(null); + EasyMock.expect(context.getInitParameter("knoxsso.cookie.max.age")).andReturn(null); + EasyMock.expect(context.getInitParameter("knoxsso.cookie.domain.suffix")).andReturn(null); + EasyMock.expect(context.getInitParameter("knoxsso.redirect.whitelist.regex")).andReturn(null); + EasyMock.expect(context.getInitParameter("knoxsso.token.audiences")).andReturn(" recipient1, recipient2 "); + EasyMock.expect(context.getInitParameter("knoxsso.token.ttl")).andReturn(null); + EasyMock.expect(context.getInitParameter("knoxsso.enable.session")).andReturn(null); + + HttpServletRequest request = EasyMock.createNiceMock(HttpServletRequest.class); + EasyMock.expect(request.getParameter("originalUrl")).andReturn("http://localhost:9080/service"); + EasyMock.expect(request.getParameterMap()).andReturn(Collections.<String,String[]>emptyMap()); + EasyMock.expect(request.getServletContext()).andReturn(context).anyTimes(); + + Principal principal = EasyMock.createNiceMock(Principal.class); + EasyMock.expect(principal.getName()).andReturn("alice").anyTimes(); + EasyMock.expect(request.getUserPrincipal()).andReturn(principal).anyTimes(); + + GatewayServices services = EasyMock.createNiceMock(GatewayServices.class); + EasyMock.expect(context.getAttribute(GatewayServices.GATEWAY_SERVICES_ATTRIBUTE)).andReturn(services); + + JWTokenAuthority authority = new TestJWTokenAuthority(publicKey, privateKey); + EasyMock.expect(services.getService(GatewayServices.TOKEN_SERVICE)).andReturn(authority); + + HttpServletResponse response = EasyMock.createNiceMock(HttpServletResponse.class); + ServletOutputStream outputStream = EasyMock.createNiceMock(ServletOutputStream.class); + CookieResponseWrapper responseWrapper = new CookieResponseWrapper(response, outputStream); + + EasyMock.replay(principal, services, context, request); + + WebSSOResource webSSOResponse = new WebSSOResource(); + webSSOResponse.request = request; + webSSOResponse.response = responseWrapper; + webSSOResponse.context = context; + webSSOResponse.init(); + + // Issue a token + webSSOResponse.doGet(); + + // Check the cookie + Cookie cookie = responseWrapper.getCookie("hadoop-jwt"); + assertNotNull(cookie); + + JWTToken parsedToken = new JWTToken(cookie.getValue()); + assertEquals("alice", parsedToken.getSubject()); + assertTrue(authority.verifyToken(parsedToken)); + + // Verify the audiences + List<String> audiences = Arrays.asList(parsedToken.getAudienceClaims()); + assertEquals(2, audiences.size()); + assertTrue(audiences.contains("recipient1")); + assertTrue(audiences.contains("recipient2")); + } + /** * A wrapper for HttpServletResponseWrapper to store the cookies */ http://git-wip-us.apache.org/repos/asf/knox/blob/5de920bd/gateway-service-knoxtoken/src/main/java/org/apache/hadoop/gateway/service/knoxtoken/TokenResource.java ---------------------------------------------------------------------- diff --git a/gateway-service-knoxtoken/src/main/java/org/apache/hadoop/gateway/service/knoxtoken/TokenResource.java b/gateway-service-knoxtoken/src/main/java/org/apache/hadoop/gateway/service/knoxtoken/TokenResource.java index 9d8bae3..8dddf02 100644 --- a/gateway-service-knoxtoken/src/main/java/org/apache/hadoop/gateway/service/knoxtoken/TokenResource.java +++ b/gateway-service-knoxtoken/src/main/java/org/apache/hadoop/gateway/service/knoxtoken/TokenResource.java @@ -82,7 +82,7 @@ public class TokenResource { if (audiences != null) { String[] auds = audiences.split(","); for (int i = 0; i < auds.length; i++) { - targetAudiences.add(auds[i]); + targetAudiences.add(auds[i].trim()); } } http://git-wip-us.apache.org/repos/asf/knox/blob/5de920bd/gateway-service-knoxtoken/src/test/java/org/apache/hadoop/gateway/service/knoxtoken/TokenServiceResourceTest.java ---------------------------------------------------------------------- diff --git a/gateway-service-knoxtoken/src/test/java/org/apache/hadoop/gateway/service/knoxtoken/TokenServiceResourceTest.java b/gateway-service-knoxtoken/src/test/java/org/apache/hadoop/gateway/service/knoxtoken/TokenServiceResourceTest.java index b4e51e6..0046bd9 100644 --- a/gateway-service-knoxtoken/src/test/java/org/apache/hadoop/gateway/service/knoxtoken/TokenServiceResourceTest.java +++ b/gateway-service-knoxtoken/src/test/java/org/apache/hadoop/gateway/service/knoxtoken/TokenServiceResourceTest.java @@ -206,6 +206,64 @@ public class TokenServiceResourceTest { } @Test + public void testAudiencesWhitespace() throws Exception { + + ServletContext context = EasyMock.createNiceMock(ServletContext.class); + EasyMock.expect(context.getInitParameter("knox.token.audiences")).andReturn(" recipient1, recipient2 "); + EasyMock.expect(context.getInitParameter("knox.token.ttl")).andReturn(null); + EasyMock.expect(context.getInitParameter("knox.token.target.url")).andReturn(null); + EasyMock.expect(context.getInitParameter("knox.token.client.data")).andReturn(null); + + HttpServletRequest request = EasyMock.createNiceMock(HttpServletRequest.class); + EasyMock.expect(request.getServletContext()).andReturn(context).anyTimes(); + Principal principal = EasyMock.createNiceMock(Principal.class); + EasyMock.expect(principal.getName()).andReturn("alice").anyTimes(); + EasyMock.expect(request.getUserPrincipal()).andReturn(principal).anyTimes(); + + GatewayServices services = EasyMock.createNiceMock(GatewayServices.class); + EasyMock.expect(context.getAttribute(GatewayServices.GATEWAY_SERVICES_ATTRIBUTE)).andReturn(services); + + JWTokenAuthority authority = new TestJWTokenAuthority(publicKey, privateKey); + EasyMock.expect(services.getService(GatewayServices.TOKEN_SERVICE)).andReturn(authority); + + StringWriter writer = new StringWriter(); + PrintWriter printWriter = new PrintWriter(writer); + HttpServletResponse response = EasyMock.createNiceMock(HttpServletResponse.class); + EasyMock.expect(response.getWriter()).andReturn(printWriter); + + EasyMock.replay(principal, services, context, request, response); + + TokenResource tr = new TokenResource(); + tr.request = request; + tr.response = response; + tr.context = context; + tr.init(); + + // Issue a token + Response retResponse = tr.doGet(); + + assertEquals(200, retResponse.getStatus()); + + // Parse the response + String retString = writer.toString(); + String accessToken = getTagValue(retString, "access_token"); + assertNotNull(accessToken); + String expiry = getTagValue(retString, "expires_in"); + assertNotNull(expiry); + + // Verify the token + JWTToken parsedToken = new JWTToken(accessToken); + assertEquals("alice", parsedToken.getSubject()); + assertTrue(authority.verifyToken(parsedToken)); + + // Verify the audiences + List<String> audiences = Arrays.asList(parsedToken.getAudienceClaims()); + assertEquals(2, audiences.size()); + assertTrue(audiences.contains("recipient1")); + assertTrue(audiences.contains("recipient2")); + } + + @Test public void testValidClientCert() throws Exception { ServletContext context = EasyMock.createNiceMock(ServletContext.class);