knox-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From kris...@apache.org
Subject [knox] branch master updated: KNOX-2070 - SSOCookieFederationFilter NPE (#170)
Date Tue, 29 Oct 2019 16:33:47 GMT
This is an automated email from the ASF dual-hosted git repository.

krisden pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/knox.git


The following commit(s) were added to refs/heads/master by this push:
     new b3923f2  KNOX-2070 - SSOCookieFederationFilter NPE (#170)
b3923f2 is described below

commit b3923f29ddfee3b10ed99097480aefacb3878f04
Author: Kevin Risden <risdenk@users.noreply.github.com>
AuthorDate: Tue Oct 29 12:33:39 2019 -0400

    KNOX-2070 - SSOCookieFederationFilter NPE (#170)
    
    Signed-off-by: Kevin Risden <krisden@apache.org>
---
 gateway-provider-security-jwt/pom.xml              |   5 +
 .../jwt/filter/SSOCookieFederationFilter.java      |  28 +-
 .../provider/federation/AbstractJWTFilterTest.java | 292 +++++++++++++++++++--
 .../provider/federation/SSOCookieProviderTest.java |  12 +
 4 files changed, 305 insertions(+), 32 deletions(-)

diff --git a/gateway-provider-security-jwt/pom.xml b/gateway-provider-security-jwt/pom.xml
index c9ba969..7fa0ba5 100644
--- a/gateway-provider-security-jwt/pom.xml
+++ b/gateway-provider-security-jwt/pom.xml
@@ -76,5 +76,10 @@
             <artifactId>gateway-test-utils</artifactId>
             <scope>test</scope>
         </dependency>
+        <dependency>
+            <groupId>org.slf4j</groupId>
+            <artifactId>slf4j-api</artifactId>
+            <scope>test</scope>
+        </dependency>
     </dependencies>
 </project>
diff --git a/gateway-provider-security-jwt/src/main/java/org/apache/knox/gateway/provider/federation/jwt/filter/SSOCookieFederationFilter.java
b/gateway-provider-security-jwt/src/main/java/org/apache/knox/gateway/provider/federation/jwt/filter/SSOCookieFederationFilter.java
index d5235aa..cbdbbd1 100644
--- a/gateway-provider-security-jwt/src/main/java/org/apache/knox/gateway/provider/federation/jwt/filter/SSOCookieFederationFilter.java
+++ b/gateway-provider-security-jwt/src/main/java/org/apache/knox/gateway/provider/federation/jwt/filter/SSOCookieFederationFilter.java
@@ -39,8 +39,11 @@ import java.nio.charset.StandardCharsets;
 import java.text.ParseException;
 
 public class SSOCookieFederationFilter extends AbstractJWTFilter {
+  public static final String XHR_HEADER = "X-Requested-With";
+  public static final String XHR_VALUE = "XMLHttpRequest";
+
   private static final String GATEWAY_PATH = "gateway.path";
-public static final String SSO_COOKIE_NAME = "sso.cookie.name";
+  public static final String SSO_COOKIE_NAME = "sso.cookie.name";
   public static final String SSO_EXPECTED_AUDIENCES = "sso.expected.audiences";
   public static final String SSO_AUTHENTICATION_PROVIDER_URL = "sso.authentication.provider.url";
   public static final String SSO_VERIFICATION_PEM = "sso.token.verification.pem";
@@ -50,13 +53,11 @@ public static final String SSO_COOKIE_NAME = "sso.cookie.name";
 
   private static final String ORIGINAL_URL_QUERY_PARAM = "originalUrl=";
   private static final String DEFAULT_SSO_COOKIE_NAME = "hadoop-jwt";
-  private static final String XHR_HEADER = "X-Requested-With";
-  private static final String XHR_VALUE = "XMLHttpRequest";
   private static JWTMessages log = MessagesFactory.get( JWTMessages.class );
 
   private String cookieName;
   private String authenticationProviderUrl;
-private String gatewayPath;
+  private String gatewayPath;
 
   @Override
   public void init( FilterConfig filterConfig ) throws ServletException {
@@ -130,19 +131,20 @@ private String gatewayPath;
   }
 
   @Override
-  protected void handleValidationError(HttpServletRequest request, HttpServletResponse response,
int status,
-                                       String error) throws IOException {
-    String loginURL = constructLoginURL(request);
-
+  protected void handleValidationError(HttpServletRequest request, HttpServletResponse response,
+                                       int status, String error) throws IOException {
     /* We don't need redirect if this is a XHR request */
-    if (request.getHeader(XHR_HEADER) != null && request.getHeader(XHR_HEADER)
-        .equalsIgnoreCase(XHR_VALUE)) {
-      final byte[] data = error.getBytes(StandardCharsets.UTF_8);
+    if (request.getHeader(XHR_HEADER) != null &&
+            request.getHeader(XHR_HEADER).equalsIgnoreCase(XHR_VALUE)) {
       response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
       response.setContentType(MimeTypes.Type.TEXT_PLAIN.toString());
-      response.setContentLength(data.length);
-      response.getOutputStream().write(data);
+      if(error != null && !error.isEmpty()) {
+        final byte[] data = error.getBytes(StandardCharsets.UTF_8);
+        response.setContentLength(data.length);
+        response.getOutputStream().write(data);
+      }
     } else {
+      String loginURL = constructLoginURL(request);
       response.sendRedirect(loginURL);
     }
 
diff --git a/gateway-provider-security-jwt/src/test/java/org/apache/knox/gateway/provider/federation/AbstractJWTFilterTest.java
b/gateway-provider-security-jwt/src/test/java/org/apache/knox/gateway/provider/federation/AbstractJWTFilterTest.java
index 562671e..e46d2b9 100644
--- a/gateway-provider-security-jwt/src/test/java/org/apache/knox/gateway/provider/federation/AbstractJWTFilterTest.java
+++ b/gateway-provider-security-jwt/src/test/java/org/apache/knox/gateway/provider/federation/AbstractJWTFilterTest.java
@@ -43,8 +43,10 @@ import javax.servlet.FilterChain;
 import javax.servlet.FilterConfig;
 import javax.servlet.ServletContext;
 import javax.servlet.ServletException;
+import javax.servlet.ServletOutputStream;
 import javax.servlet.ServletRequest;
 import javax.servlet.ServletResponse;
+import javax.servlet.WriteListener;
 import javax.servlet.http.HttpServletRequest;
 import javax.servlet.http.HttpServletResponse;
 import java.net.InetAddress;
@@ -127,7 +129,21 @@ public abstract class AbstractJWTFilterTest  {
       HttpServletResponse response = EasyMock.createNiceMock(HttpServletResponse.class);
       EasyMock.expect(response.encodeRedirectURL(SERVICE_URL)).andReturn(
           SERVICE_URL);
-      EasyMock.replay(request);
+      EasyMock.expect(response.getOutputStream()).andAnswer(() -> new ServletOutputStream()
{
+        @Override
+        public void write(int b) {
+        }
+
+        @Override
+        public void setWriteListener(WriteListener arg0) {
+        }
+
+        @Override
+        public boolean isReady() {
+          return false;
+        }
+      }).anyTimes();
+      EasyMock.replay(request, response);
 
       TestFilterChain chain = new TestFilterChain();
       handler.doFilter(request, response, chain);
@@ -159,7 +175,21 @@ public abstract class AbstractJWTFilterTest  {
       HttpServletResponse response = EasyMock.createNiceMock(HttpServletResponse.class);
       EasyMock.expect(response.encodeRedirectURL(SERVICE_URL)).andReturn(
           SERVICE_URL);
-      EasyMock.replay(request);
+      EasyMock.expect(response.getOutputStream()).andAnswer(() -> new ServletOutputStream()
{
+        @Override
+        public void write(int b) {
+        }
+
+        @Override
+        public void setWriteListener(WriteListener arg0) {
+        }
+
+        @Override
+        public boolean isReady() {
+          return false;
+        }
+      }).anyTimes();
+      EasyMock.replay(request, response);
 
       TestFilterChain chain = new TestFilterChain();
       handler.doFilter(request, response, chain);
@@ -193,7 +223,21 @@ public abstract class AbstractJWTFilterTest  {
       HttpServletResponse response = EasyMock.createNiceMock(HttpServletResponse.class);
       EasyMock.expect(response.encodeRedirectURL(SERVICE_URL)).andReturn(
           SERVICE_URL);
-      EasyMock.replay(request);
+      EasyMock.expect(response.getOutputStream()).andAnswer(() -> new ServletOutputStream()
{
+        @Override
+        public void write(int b) {
+        }
+
+        @Override
+        public void setWriteListener(WriteListener arg0) {
+        }
+
+        @Override
+        public boolean isReady() {
+          return false;
+        }
+      }).anyTimes();
+      EasyMock.replay(request, response);
 
       TestFilterChain chain = new TestFilterChain();
       handler.doFilter(request, response, chain);
@@ -223,7 +267,21 @@ public abstract class AbstractJWTFilterTest  {
       HttpServletResponse response = EasyMock.createNiceMock(HttpServletResponse.class);
       EasyMock.expect(response.encodeRedirectURL(SERVICE_URL)).andReturn(
           SERVICE_URL);
-      EasyMock.replay(request);
+      EasyMock.expect(response.getOutputStream()).andAnswer(() -> new ServletOutputStream()
{
+        @Override
+        public void write(int b) {
+        }
+
+        @Override
+        public void setWriteListener(WriteListener arg0) {
+        }
+
+        @Override
+        public boolean isReady() {
+          return false;
+        }
+      }).anyTimes();
+      EasyMock.replay(request, response);
 
       TestFilterChain chain = new TestFilterChain();
       handler.doFilter(request, response, chain);
@@ -255,7 +313,21 @@ public abstract class AbstractJWTFilterTest  {
       HttpServletResponse response = EasyMock.createNiceMock(HttpServletResponse.class);
       EasyMock.expect(response.encodeRedirectURL(SERVICE_URL)).andReturn(
           SERVICE_URL);
-      EasyMock.replay(request);
+      EasyMock.expect(response.getOutputStream()).andAnswer(() -> new ServletOutputStream()
{
+        @Override
+        public void write(int b) {
+        }
+
+        @Override
+        public void setWriteListener(WriteListener arg0) {
+        }
+
+        @Override
+        public boolean isReady() {
+          return false;
+        }
+      }).anyTimes();
+      EasyMock.replay(request, response);
 
       TestFilterChain chain = new TestFilterChain();
       handler.doFilter(request, response, chain);
@@ -284,7 +356,21 @@ public abstract class AbstractJWTFilterTest  {
       HttpServletResponse response = EasyMock.createNiceMock(HttpServletResponse.class);
       EasyMock.expect(response.encodeRedirectURL(SERVICE_URL)).andReturn(
           SERVICE_URL);
-      EasyMock.replay(request);
+      EasyMock.expect(response.getOutputStream()).andAnswer(() -> new ServletOutputStream()
{
+        @Override
+        public void write(int b) {
+        }
+
+        @Override
+        public void setWriteListener(WriteListener arg0) {
+        }
+
+        @Override
+        public boolean isReady() {
+          return false;
+        }
+      }).anyTimes();
+      EasyMock.replay(request, response);
 
       TestFilterChain chain = new TestFilterChain();
       handler.doFilter(request, response, chain);
@@ -316,7 +402,21 @@ public abstract class AbstractJWTFilterTest  {
       HttpServletResponse response = EasyMock.createNiceMock(HttpServletResponse.class);
       EasyMock.expect(response.encodeRedirectURL(SERVICE_URL)).andReturn(
           SERVICE_URL);
-      EasyMock.replay(request);
+      EasyMock.expect(response.getOutputStream()).andAnswer(() -> new ServletOutputStream()
{
+        @Override
+        public void write(int b) {
+        }
+
+        @Override
+        public void setWriteListener(WriteListener arg0) {
+        }
+
+        @Override
+        public boolean isReady() {
+          return false;
+        }
+      }).anyTimes();
+      EasyMock.replay(request, response);
 
       TestFilterChain chain = new TestFilterChain();
       handler.doFilter(request, response, chain);
@@ -351,7 +451,21 @@ public abstract class AbstractJWTFilterTest  {
       HttpServletResponse response = EasyMock.createNiceMock(HttpServletResponse.class);
       EasyMock.expect(response.encodeRedirectURL(SERVICE_URL)).andReturn(
           SERVICE_URL);
-      EasyMock.replay(request);
+      EasyMock.expect(response.getOutputStream()).andAnswer(() -> new ServletOutputStream()
{
+        @Override
+        public void write(int b) {
+        }
+
+        @Override
+        public void setWriteListener(WriteListener arg0) {
+        }
+
+        @Override
+        public boolean isReady() {
+          return false;
+        }
+      }).anyTimes();
+      EasyMock.replay(request, response);
 
       TestFilterChain chain = new TestFilterChain();
       handler.doFilter(request, response, chain);
@@ -371,7 +485,7 @@ public abstract class AbstractJWTFilterTest  {
       handler.init(new TestFilterConfig(props));
 
       SignedJWT jwt = getJWT(AbstractJWTFilter.JWT_DEFAULT_ISSUER, "alice",
-                             new Date(new Date().getTime() - 1000), privateKey);
+          new Date(new Date().getTime() - 1000), privateKey);
 
       HttpServletRequest request = EasyMock.createNiceMock(HttpServletRequest.class);
       setTokenOnRequest(request, jwt);
@@ -382,7 +496,21 @@ public abstract class AbstractJWTFilterTest  {
       HttpServletResponse response = EasyMock.createNiceMock(HttpServletResponse.class);
       EasyMock.expect(response.encodeRedirectURL(SERVICE_URL)).andReturn(
           SERVICE_URL);
-      EasyMock.replay(request);
+      EasyMock.expect(response.getOutputStream()).andAnswer(() -> new ServletOutputStream()
{
+        @Override
+        public void write(int b) {
+        }
+
+        @Override
+        public void setWriteListener(WriteListener arg0) {
+        }
+
+        @Override
+        public boolean isReady() {
+          return false;
+        }
+      }).anyTimes();
+      EasyMock.replay(request, response);
 
       TestFilterChain chain = new TestFilterChain();
       handler.doFilter(request, response, chain);
@@ -410,7 +538,21 @@ public abstract class AbstractJWTFilterTest  {
       HttpServletResponse response = EasyMock.createNiceMock(HttpServletResponse.class);
       EasyMock.expect(response.encodeRedirectURL(SERVICE_URL)).andReturn(
           SERVICE_URL).anyTimes();
-      EasyMock.replay(request);
+      EasyMock.expect(response.getOutputStream()).andAnswer(() -> new ServletOutputStream()
{
+        @Override
+        public void write(int b) {
+        }
+
+        @Override
+        public void setWriteListener(WriteListener arg0) {
+        }
+
+        @Override
+        public boolean isReady() {
+          return false;
+        }
+      }).anyTimes();
+      EasyMock.replay(request, response);
 
       TestFilterChain chain = new TestFilterChain();
       handler.doFilter(request, response, chain);
@@ -441,7 +583,21 @@ public abstract class AbstractJWTFilterTest  {
       HttpServletResponse response = EasyMock.createNiceMock(HttpServletResponse.class);
       EasyMock.expect(response.encodeRedirectURL(SERVICE_URL)).andReturn(
           SERVICE_URL).anyTimes();
-      EasyMock.replay(request);
+      EasyMock.expect(response.getOutputStream()).andAnswer(() -> new ServletOutputStream()
{
+        @Override
+        public void write(int b) {
+        }
+
+        @Override
+        public void setWriteListener(WriteListener arg0) {
+        }
+
+        @Override
+        public boolean isReady() {
+          return false;
+        }
+      }).anyTimes();
+      EasyMock.replay(request, response);
 
       TestFilterChain chain = new TestFilterChain();
       handler.doFilter(request, response, chain);
@@ -476,7 +632,21 @@ public abstract class AbstractJWTFilterTest  {
       HttpServletResponse response = EasyMock.createNiceMock(HttpServletResponse.class);
       EasyMock.expect(response.encodeRedirectURL(SERVICE_URL)).andReturn(
           SERVICE_URL).anyTimes();
-      EasyMock.replay(request);
+      EasyMock.expect(response.getOutputStream()).andAnswer(() -> new ServletOutputStream()
{
+        @Override
+        public void write(int b) {
+        }
+
+        @Override
+        public void setWriteListener(WriteListener arg0) {
+        }
+
+        @Override
+        public boolean isReady() {
+          return false;
+        }
+      }).anyTimes();
+      EasyMock.replay(request, response);
 
       TestFilterChain chain = new TestFilterChain();
       handler.doFilter(request, response, chain);
@@ -517,7 +687,21 @@ public abstract class AbstractJWTFilterTest  {
       EasyMock.expect(request.getQueryString()).andReturn(null);
       HttpServletResponse response = EasyMock.createNiceMock(HttpServletResponse.class);
       EasyMock.expect(response.encodeRedirectURL(SERVICE_URL)).andReturn(SERVICE_URL);
-      EasyMock.replay(request);
+      EasyMock.expect(response.getOutputStream()).andAnswer(() -> new ServletOutputStream()
{
+        @Override
+        public void write(int b) {
+        }
+
+        @Override
+        public void setWriteListener(WriteListener arg0) {
+        }
+
+        @Override
+        public boolean isReady() {
+          return false;
+        }
+      }).anyTimes();
+      EasyMock.replay(request, response);
 
       TestFilterChain chain = new TestFilterChain();
       handler.doFilter(request, response, chain);
@@ -545,7 +729,21 @@ public abstract class AbstractJWTFilterTest  {
       HttpServletResponse response = EasyMock.createNiceMock(HttpServletResponse.class);
       EasyMock.expect(response.encodeRedirectURL(SERVICE_URL)).andReturn(
           SERVICE_URL);
-      EasyMock.replay(request);
+      EasyMock.expect(response.getOutputStream()).andAnswer(() -> new ServletOutputStream()
{
+        @Override
+        public void write(int b) {
+        }
+
+        @Override
+        public void setWriteListener(WriteListener arg0) {
+        }
+
+        @Override
+        public boolean isReady() {
+          return false;
+        }
+      }).anyTimes();
+      EasyMock.replay(request, response);
 
       TestFilterChain chain = new TestFilterChain();
       handler.doFilter(request, response, chain);
@@ -574,7 +772,21 @@ public abstract class AbstractJWTFilterTest  {
       HttpServletResponse response = EasyMock.createNiceMock(HttpServletResponse.class);
       EasyMock.expect(response.encodeRedirectURL(SERVICE_URL)).andReturn(
           SERVICE_URL);
-      EasyMock.replay(request);
+      EasyMock.expect(response.getOutputStream()).andAnswer(() -> new ServletOutputStream()
{
+        @Override
+        public void write(int b) {
+        }
+
+        @Override
+        public void setWriteListener(WriteListener arg0) {
+        }
+
+        @Override
+        public boolean isReady() {
+          return false;
+        }
+      }).anyTimes();
+      EasyMock.replay(request, response);
 
       TestFilterChain chain = new TestFilterChain();
       handler.doFilter(request, response, chain);
@@ -606,7 +818,21 @@ public abstract class AbstractJWTFilterTest  {
       HttpServletResponse response = EasyMock.createNiceMock(HttpServletResponse.class);
       EasyMock.expect(response.encodeRedirectURL(SERVICE_URL)).andReturn(
           SERVICE_URL);
-      EasyMock.replay(request);
+      EasyMock.expect(response.getOutputStream()).andAnswer(() -> new ServletOutputStream()
{
+        @Override
+        public void write(int b) {
+        }
+
+        @Override
+        public void setWriteListener(WriteListener arg0) {
+        }
+
+        @Override
+        public boolean isReady() {
+          return false;
+        }
+      }).anyTimes();
+      EasyMock.replay(request, response);
 
       TestFilterChain chain = new TestFilterChain();
       handler.doFilter(request, response, chain);
@@ -637,7 +863,21 @@ public abstract class AbstractJWTFilterTest  {
       HttpServletResponse response = EasyMock.createNiceMock(HttpServletResponse.class);
       EasyMock.expect(response.encodeRedirectURL(SERVICE_URL)).andReturn(
           SERVICE_URL);
-      EasyMock.replay(request);
+      EasyMock.expect(response.getOutputStream()).andAnswer(() -> new ServletOutputStream()
{
+        @Override
+        public void write(int b) {
+        }
+
+        @Override
+        public void setWriteListener(WriteListener arg0) {
+        }
+
+        @Override
+        public boolean isReady() {
+          return false;
+        }
+      }).anyTimes();
+      EasyMock.replay(request, response);
 
       TestFilterChain chain = new TestFilterChain();
       handler.doFilter(request, response, chain);
@@ -668,7 +908,21 @@ public abstract class AbstractJWTFilterTest  {
       HttpServletResponse response = EasyMock.createNiceMock(HttpServletResponse.class);
       EasyMock.expect(response.encodeRedirectURL(SERVICE_URL)).andReturn(
           SERVICE_URL);
-      EasyMock.replay(request);
+      EasyMock.expect(response.getOutputStream()).andAnswer(() -> new ServletOutputStream()
{
+        @Override
+        public void write(int b) {
+        }
+
+        @Override
+        public void setWriteListener(WriteListener arg0) {
+        }
+
+        @Override
+        public boolean isReady() {
+          return false;
+        }
+      }).anyTimes();
+      EasyMock.replay(request, response);
 
       TestFilterChain chain = new TestFilterChain();
       handler.doFilter(request, response, chain);
diff --git a/gateway-provider-security-jwt/src/test/java/org/apache/knox/gateway/provider/federation/SSOCookieProviderTest.java
b/gateway-provider-security-jwt/src/test/java/org/apache/knox/gateway/provider/federation/SSOCookieProviderTest.java
index 7fc28a6..4555461 100644
--- a/gateway-provider-security-jwt/src/test/java/org/apache/knox/gateway/provider/federation/SSOCookieProviderTest.java
+++ b/gateway-provider-security-jwt/src/test/java/org/apache/knox/gateway/provider/federation/SSOCookieProviderTest.java
@@ -17,12 +17,15 @@
  */
 package org.apache.knox.gateway.provider.federation;
 
+import static org.apache.knox.gateway.provider.federation.jwt.filter.SSOCookieFederationFilter.XHR_HEADER;
+import static org.apache.knox.gateway.provider.federation.jwt.filter.SSOCookieFederationFilter.XHR_VALUE;
 import static org.junit.Assert.fail;
 
 import java.security.Principal;
 import java.util.Properties;
 import java.util.Date;
 import java.util.Set;
+import java.util.concurrent.ThreadLocalRandom;
 
 import javax.servlet.ServletException;
 import javax.servlet.http.Cookie;
@@ -39,8 +42,12 @@ import org.junit.Before;
 import org.junit.Test;
 
 import com.nimbusds.jwt.SignedJWT;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
 
 public class SSOCookieProviderTest extends AbstractJWTFilterTest {
+  private static Logger LOGGER = LoggerFactory.getLogger(SSOCookieProviderTest.class);
+
   private static final String SERVICE_URL = "https://localhost:8888/resource";
 
   @Before
@@ -53,6 +60,11 @@ public class SSOCookieProviderTest extends AbstractJWTFilterTest {
   protected void setTokenOnRequest(HttpServletRequest request, SignedJWT jwt) {
     Cookie cookie = new Cookie("hadoop-jwt", jwt.serialize());
     EasyMock.expect(request.getCookies()).andReturn(new Cookie[] { cookie });
+
+    if(ThreadLocalRandom.current().nextBoolean()) {
+      LOGGER.info("Using XHR header for request");
+      EasyMock.expect(request.getHeader(XHR_HEADER)).andReturn(XHR_VALUE).anyTimes();
+    }
   }
 
   @Override


Mime
View raw message