You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@knox.apache.org by lm...@apache.org on 2017/05/13 16:47:25 UTC

knox git commit: KNOX-938 - JWTProvider to accept Query Param as well as Bearer Token

Repository: knox
Updated Branches:
  refs/heads/master fb2e31348 -> efc361ddc


KNOX-938 - JWTProvider to accept Query Param as well as Bearer Token

Project: http://git-wip-us.apache.org/repos/asf/knox/repo
Commit: http://git-wip-us.apache.org/repos/asf/knox/commit/efc361dd
Tree: http://git-wip-us.apache.org/repos/asf/knox/tree/efc361dd
Diff: http://git-wip-us.apache.org/repos/asf/knox/diff/efc361dd

Branch: refs/heads/master
Commit: efc361ddc97209a2d87f69018701dbcc5a3450fc
Parents: fb2e313
Author: Larry McCay <lm...@hortonworks.com>
Authored: Sat May 13 12:47:03 2017 -0400
Committer: Larry McCay <lm...@hortonworks.com>
Committed: Sat May 13 12:47:03 2017 -0400

----------------------------------------------------------------------
 .../jwt/filter/JWTFederationFilter.java         | 91 +++++++++++++-------
 1 file changed, 61 insertions(+), 30 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/knox/blob/efc361dd/gateway-provider-security-jwt/src/main/java/org/apache/hadoop/gateway/provider/federation/jwt/filter/JWTFederationFilter.java
----------------------------------------------------------------------
diff --git a/gateway-provider-security-jwt/src/main/java/org/apache/hadoop/gateway/provider/federation/jwt/filter/JWTFederationFilter.java b/gateway-provider-security-jwt/src/main/java/org/apache/hadoop/gateway/provider/federation/jwt/filter/JWTFederationFilter.java
index 33af374..9facd30 100644
--- a/gateway-provider-security-jwt/src/main/java/org/apache/hadoop/gateway/provider/federation/jwt/filter/JWTFederationFilter.java
+++ b/gateway-provider-security-jwt/src/main/java/org/apache/hadoop/gateway/provider/federation/jwt/filter/JWTFederationFilter.java
@@ -46,9 +46,11 @@ import java.util.Set;
 public class JWTFederationFilter extends AbstractJWTFilter {
 
   public static final String KNOX_TOKEN_AUDIENCES = "knox.token.audiences";
+  private static final String KNOX_TOKEN_QUERY_PARAM_NAME = "knox.token.query.param.name";
   private static final String BEARER = "Bearer ";
   private static JWTMessages log = MessagesFactory.get( JWTMessages.class );
   private JWTokenAuthority authority = null;
+  private String paramName = "knoxtoken";
 
   @Override
   public void init( FilterConfig filterConfig ) throws ServletException {
@@ -60,6 +62,13 @@ public class JWTFederationFilter extends AbstractJWTFilter {
     if (expectedAudiences != null) {
       audiences = parseExpectedAudiences(expectedAudiences);
     }
+
+    // query param name for finding the provided knoxtoken
+    String queryParamName = filterConfig.getInitParameter(KNOX_TOKEN_QUERY_PARAM_NAME);
+    if (queryParamName != null) {
+      paramName = queryParamName;
+    }
+
   }
 
   public void destroy() {
@@ -71,51 +80,73 @@ public class JWTFederationFilter extends AbstractJWTFilter {
     if (header != null && header.startsWith(BEARER)) {
       // what follows the bearer designator should be the JWT token being used to request or as an access token
       String wireToken = header.substring(BEARER.length());
-      JWTToken token;
-      token = new JWTToken(wireToken);
-      boolean verified = false;
-      try {
-        verified = authority.verifyToken(token);
-      } catch (TokenServiceException e) {
-        log.unableToVerifyToken(e);
+      JWTToken token = new JWTToken(wireToken);
+      if (validateToken(request, response, chain, token)) {
+        Subject subject = createSubjectFromToken(token);
+        continueWithEstablishedSecurityContext(subject, (HttpServletRequest)request, (HttpServletResponse)response, chain);
       }
-      if (verified) {
-        // confirm that issue matches intended target - which for this filter must be KNOXSSO
-        if (token.getIssuer().equals("KNOXSSO")) {
-          // if there is no expiration data then the lifecycle is tied entirely to
-          // the cookie validity - otherwise ensure that the current time is before
-          // the designated expiration time
-          if (tokenIsStillValid(token)) {
-            boolean audValid = validateAudiences(token);
-            if (audValid) {
-              Subject subject = createSubjectFromToken(token);
-              continueWithEstablishedSecurityContext(subject, (HttpServletRequest)request, (HttpServletResponse)response, chain);
-            }
-            else {
-              log.failedToValidateAudience();
-              ((HttpServletResponse) response).sendError(400, "Bad request: missing required token audience");
-            }
+      else {
+        return; // break the filter chain
+      }
+    }
+    else {
+      // check for query param
+      String wireToken = ((HttpServletRequest) request).getParameter(paramName);
+      if (wireToken != null) {
+        JWTToken token = new JWTToken(wireToken);
+        if (validateToken(request, response, chain, token)) {
+          Subject subject = createSubjectFromToken(token);
+          continueWithEstablishedSecurityContext(subject, (HttpServletRequest)request, (HttpServletResponse)response, chain);
+        }
+      }
+      else {
+        // no token provided in header
+        ((HttpServletResponse) response).sendError(HttpServletResponse.SC_UNAUTHORIZED);
+        return; //break filter chain
+      }
+    }
+  }
+
+  private boolean validateToken(ServletRequest request, ServletResponse response,
+      FilterChain chain, JWTToken token)
+      throws IOException, ServletException {
+    boolean rc = false;
+    boolean verified = false;
+    try {
+      verified = authority.verifyToken(token);
+    } catch (TokenServiceException e) {
+      log.unableToVerifyToken(e);
+    }
+    if (verified) {
+      // confirm that issue matches intended target - which for this filter must be KNOXSSO
+      if (token.getIssuer().equals("KNOXSSO")) {
+        // if there is no expiration data then the lifecycle is tied entirely to
+        // the cookie validity - otherwise ensure that the current time is before
+        // the designated expiration time
+        if (tokenIsStillValid(token)) {
+          boolean audValid = validateAudiences(token);
+          if (audValid) {
+            rc = true;
           }
           else {
-            log.tokenHasExpired();
-            ((HttpServletResponse) response).sendError(400, "Bad request: token has expired");
+            log.failedToValidateAudience();
+            ((HttpServletResponse) response).sendError(400, "Bad request: missing required token audience");
           }
         }
         else {
-          ((HttpServletResponse) response).sendError(HttpServletResponse.SC_UNAUTHORIZED);
-          return; //break filter chain
+          log.tokenHasExpired();
+          ((HttpServletResponse) response).sendError(400, "Bad request: token has expired");
         }
       }
       else {
         ((HttpServletResponse) response).sendError(HttpServletResponse.SC_UNAUTHORIZED);
-        return; //break filter chain
       }
     }
     else {
-      // no token provided in header
       ((HttpServletResponse) response).sendError(HttpServletResponse.SC_UNAUTHORIZED);
-      return; //break filter chain
     }
+
+    return rc;
   }
   
   private void continueWithEstablishedSecurityContext(Subject subject, final HttpServletRequest request, final HttpServletResponse response, final FilterChain chain) throws IOException, ServletException {