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 2013/03/15 16:37:00 UTC

git commit: Added support for JWT token based identity federation

Updated Branches:
  refs/heads/master e09ea97d1 -> ba9dc3e5f


Added support for JWT token based identity federation

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

Branch: refs/heads/master
Commit: ba9dc3e5f55a54753b15108e2a64bc5ab67cd15f
Parents: e09ea97
Author: Larry McCay <lm...@hortonworks.com>
Authored: Fri Mar 15 11:36:06 2013 -0400
Committer: Larry McCay <lm...@hortonworks.com>
Committed: Fri Mar 15 11:36:06 2013 -0400

----------------------------------------------------------------------
 gateway-provider-security-jwt/pom.xml              |   79 ++++++++
 .../authn/jwt/deploy/JWTDeploymentContributor.java |   52 ++++++
 .../provider/authn/jwt/filter/JWTAuthority.java    |   60 +++++++
 .../authn/jwt/filter/JWTFederationFilter.java      |  135 ++++++++++++++
 .../provider/authn/jwt/filter/JWTToken.java        |  136 ++++++++++++++
 .../jwt/deploy/JWTDeploymentContributor.java       |   52 ++++++
 .../federation/jwt/filter/JWTAuthority.java        |   60 +++++++
 .../federation/jwt/filter/JWTFederationFilter.java |  135 ++++++++++++++
 .../federation/jwt/filter/JWTProviderMessages.java |   24 +++
 .../provider/federation/jwt/filter/JWTToken.java   |  138 +++++++++++++++
 ...op.gateway.deploy.ProviderDeploymentContributor |   19 ++
 .../gateway/provider/federation/JWTTokenTest.java  |   40 ++++
 gateway-release/pom.xml                            |    4 +
 .../gateway/services/DefaultGatewayServices.java   |    1 +
 .../security/impl/DefaultAliasService.java         |   13 ++
 .../security/impl/DefaultCryptoService.java        |   68 +++++++
 .../security/impl/DefaultKeystoreService.java      |   22 +++
 .../services/security/CryptoServiceTest.java       |   12 ++
 .../gateway/hdfs/HdfsDeploymentContributor.java    |    7 +-
 .../gateway/oozie/OozieDeploymentContributor.java  |    7 +-
 .../templeton/TempletonDeploymentContributor.java  |    7 +-
 .../deploy/ServiceDeploymentContributorBase.java   |   14 ++
 .../gateway/services/security/AliasService.java    |    6 +
 .../gateway/services/security/CryptoService.java   |    4 +
 .../gateway/services/security/KeystoreService.java |    3 +
 pom.xml                                            |    7 +-
 26 files changed, 1101 insertions(+), 4 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-knox/blob/ba9dc3e5/gateway-provider-security-jwt/pom.xml
----------------------------------------------------------------------
diff --git a/gateway-provider-security-jwt/pom.xml b/gateway-provider-security-jwt/pom.xml
new file mode 100644
index 0000000..c436be9
--- /dev/null
+++ b/gateway-provider-security-jwt/pom.xml
@@ -0,0 +1,79 @@
+<!--
+   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.
+-->
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+    <modelVersion>4.0.0</modelVersion>
+    <parent>
+        <groupId>org.apache.hadoop</groupId>
+        <artifactId>gateway</artifactId>
+        <version>0.2.0-SNAPSHOT</version>
+    </parent>
+    <artifactId>gateway-provider-security-jwt</artifactId>
+
+    <name>gateway-provider-security-jwt</name>
+    <description>An extension of the gateway introducing JWT as a recognized token for authentication.</description>
+
+    <licenses>
+        <license>
+            <name>The Apache Software License, Version 2.0</name>
+            <url>http://www.apache.org/licenses/LICENSE-2.0.txt</url>
+            <distribution>repo</distribution>
+        </license>
+    </licenses>
+
+    <dependencies>
+        <dependency>
+            <groupId>${gateway-group}</groupId>
+            <artifactId>gateway-spi</artifactId>
+        </dependency>
+
+        <dependency>
+            <groupId>commons-io</groupId>
+            <artifactId>commons-io</artifactId>
+        </dependency>
+
+	  	  <dependency>
+          <groupId>commons-codec</groupId>
+          <artifactId>commons-codec</artifactId>
+        </dependency>
+        
+				<dependency>
+          <groupId>com.jayway.jsonpath</groupId>
+          <artifactId>json-path</artifactId>
+        </dependency>
+        
+        <dependency>
+            <groupId>junit</groupId>
+            <artifactId>junit</artifactId>
+            <scope>test</scope>
+        </dependency>
+
+        <dependency>
+            <groupId>org.easymock</groupId>
+            <artifactId>easymock</artifactId>
+            <scope>test</scope>
+        </dependency>
+
+        <dependency>
+            <groupId>org.apache.hadoop</groupId>
+            <artifactId>gateway-test-utils</artifactId>
+            <scope>test</scope>
+        </dependency>
+
+    </dependencies>
+
+</project>
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-knox/blob/ba9dc3e5/gateway-provider-security-jwt/src/main/java/org/apache/hadoop/gateway/provider/authn/jwt/deploy/JWTDeploymentContributor.java
----------------------------------------------------------------------
diff --git a/gateway-provider-security-jwt/src/main/java/org/apache/hadoop/gateway/provider/authn/jwt/deploy/JWTDeploymentContributor.java b/gateway-provider-security-jwt/src/main/java/org/apache/hadoop/gateway/provider/authn/jwt/deploy/JWTDeploymentContributor.java
new file mode 100644
index 0000000..f842c36
--- /dev/null
+++ b/gateway-provider-security-jwt/src/main/java/org/apache/hadoop/gateway/provider/authn/jwt/deploy/JWTDeploymentContributor.java
@@ -0,0 +1,52 @@
+/**
+ * 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.provider.authn.jwt.deploy;
+
+import org.apache.hadoop.gateway.deploy.DeploymentContext;
+import org.apache.hadoop.gateway.deploy.ProviderDeploymentContributorBase;
+import org.apache.hadoop.gateway.descriptor.FilterParamDescriptor;
+import org.apache.hadoop.gateway.descriptor.ResourceDescriptor;
+import org.apache.hadoop.gateway.topology.Provider;
+import org.apache.hadoop.gateway.topology.Service;
+import org.jboss.shrinkwrap.api.asset.StringAsset;
+
+import java.util.List;
+
+public class JWTDeploymentContributor extends ProviderDeploymentContributorBase {
+
+  private static final String FILTER_CLASSNAME = "org.apache.hadoop.gateway.provider.authn.jwt.filter.JWTFederationFilter";
+
+  @Override
+  public String getRole() {
+    return "federation";
+  }
+
+  @Override
+  public String getName() {
+    return "JWTProvider";
+  }
+
+  @Override
+  public void contributeProvider( DeploymentContext context, Provider provider ) {
+  }
+
+  @Override
+  public void contributeFilter( DeploymentContext context, Provider provider, Service service, ResourceDescriptor resource, List<FilterParamDescriptor> params ) {
+    resource.addFilter().name( getName() ).role( getRole() ).impl( FILTER_CLASSNAME ).params( params );
+  }
+}

http://git-wip-us.apache.org/repos/asf/incubator-knox/blob/ba9dc3e5/gateway-provider-security-jwt/src/main/java/org/apache/hadoop/gateway/provider/authn/jwt/filter/JWTAuthority.java
----------------------------------------------------------------------
diff --git a/gateway-provider-security-jwt/src/main/java/org/apache/hadoop/gateway/provider/authn/jwt/filter/JWTAuthority.java b/gateway-provider-security-jwt/src/main/java/org/apache/hadoop/gateway/provider/authn/jwt/filter/JWTAuthority.java
new file mode 100644
index 0000000..9e47350
--- /dev/null
+++ b/gateway-provider-security-jwt/src/main/java/org/apache/hadoop/gateway/provider/authn/jwt/filter/JWTAuthority.java
@@ -0,0 +1,60 @@
+  /**
+   * 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.provider.authn.jwt.filter;
+
+import java.security.Principal;
+
+import javax.security.auth.Subject;
+
+import org.apache.hadoop.gateway.services.security.CryptoService;
+
+public class JWTAuthority {
+  private CryptoService crypto = null;
+  
+  public JWTAuthority(CryptoService crypto) {
+    this.crypto = crypto;
+  }
+  
+  public JWTToken issueToken(Subject subject) {
+    Principal p = (Principal) subject.getPrincipals().toArray()[0];
+    String[] claimArray = new String[4];
+    claimArray[0] = "gateway";
+    claimArray[1] = p.getName();
+    // TODO: what do we need here and how do we determine what it should be?
+    claimArray[2] = "https://login.hadoop.example.org";
+    // TODO: make the validity period configurable
+    claimArray[3] = Long.toString( ( System.currentTimeMillis()/1000 ) + 300);
+
+    JWTToken token = new JWTToken("RS256", claimArray);
+    signToken(token);
+    
+    return token;
+  }
+  
+  private void signToken(JWTToken token) {
+    byte[] signature = null;
+    signature = crypto.sign("SHA256withRSA","gateway-identity",token.getPayloadToSign());
+    token.setSignaturePayload(signature);
+  }
+  
+  public boolean verifyToken(JWTToken token) {
+    boolean rc = false;
+    rc = crypto.verify("SHA256withRSA", "gateway-identity", token.getPayloadToSign(), token.getSignaturePayload());
+    return rc;
+  }
+}

http://git-wip-us.apache.org/repos/asf/incubator-knox/blob/ba9dc3e5/gateway-provider-security-jwt/src/main/java/org/apache/hadoop/gateway/provider/authn/jwt/filter/JWTFederationFilter.java
----------------------------------------------------------------------
diff --git a/gateway-provider-security-jwt/src/main/java/org/apache/hadoop/gateway/provider/authn/jwt/filter/JWTFederationFilter.java b/gateway-provider-security-jwt/src/main/java/org/apache/hadoop/gateway/provider/authn/jwt/filter/JWTFederationFilter.java
new file mode 100644
index 0000000..af76e09
--- /dev/null
+++ b/gateway-provider-security-jwt/src/main/java/org/apache/hadoop/gateway/provider/authn/jwt/filter/JWTFederationFilter.java
@@ -0,0 +1,135 @@
+  /**
+   * 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.provider.authn.jwt.filter;
+
+import javax.security.auth.Subject;
+import javax.servlet.Filter;
+import javax.servlet.FilterChain;
+import javax.servlet.FilterConfig;
+import javax.servlet.ServletException;
+import javax.servlet.ServletRequest;
+import javax.servlet.ServletResponse;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+import org.apache.hadoop.gateway.services.GatewayServices;
+import org.apache.hadoop.gateway.services.security.CryptoService;
+
+import java.io.IOException;
+import java.security.Principal;
+import java.security.PrivilegedActionException;
+import java.security.PrivilegedExceptionAction;
+import java.util.HashSet;
+import java.util.Set;
+
+
+public class JWTFederationFilter implements Filter {
+
+  private static final String BEARER = "Bearer ";
+  private static final String GATEWAY_SERVICES_ATTRIBUTE = "org.apache.hadoop.gateway.gateway.services";
+  
+  private JWTAuthority authority = null;
+
+  @Override
+  public void init( FilterConfig filterConfig ) throws ServletException {
+    GatewayServices services = (GatewayServices) filterConfig.getServletContext().getAttribute(GATEWAY_SERVICES_ATTRIBUTE);
+    CryptoService crypto = (CryptoService) services.getService("CryptoService");
+    authority = new JWTAuthority(crypto);
+  }
+
+  public void destroy() {
+  }
+
+  public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) 
+      throws IOException, ServletException {
+    String header = ((HttpServletRequest) request).getHeader("Authorization");
+    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 = JWTToken.parseToken(wireToken);
+      boolean verified = authority.verifyToken(token);
+      if (verified) {
+        // TODO: validate expiration
+        // TODO: confirm that audience matches intended target
+        Subject subject = createSubjectFromToken(token);
+        continueWithEstablishedSecurityContext(subject, (HttpServletRequest)request, (HttpServletResponse)response, chain);
+      }
+      else {
+        ((HttpServletResponse) response).sendError(HttpServletResponse.SC_UNAUTHORIZED);
+        return; //break filter chain
+      }
+    }
+    else {
+      // no token provided in header
+      // TODO: may have to check cookie and url as well before sending error
+      ((HttpServletResponse) response).sendError(HttpServletResponse.SC_UNAUTHORIZED);
+      return; //break filter chain
+    }
+  }
+  
+  private void continueWithEstablishedSecurityContext(Subject subject, final HttpServletRequest request, final HttpServletResponse response, final FilterChain chain) throws IOException, ServletException {
+    try {
+      Subject.doAs(
+        subject,
+        new PrivilegedExceptionAction<Object>() {
+          @Override
+          public Object run() throws Exception {
+            chain.doFilter(request, response);
+            return null;
+          }
+        }
+        );
+    }
+    catch (PrivilegedActionException e) {
+      Throwable t = e.getCause();
+      if (t instanceof IOException) {
+        throw (IOException) t;
+      }
+      else if (t instanceof ServletException) {
+        throw (ServletException) t;
+      }
+      else {
+        throw new ServletException(t);
+      }
+    }
+  }
+  
+  private Subject createSubjectFromToken(JWTToken token) {
+    final String principal = token.getPrincipal();
+
+    HashSet emptySet = new HashSet();
+    Set<Principal> principals = new HashSet<Principal>();
+    Principal p = new Principal() {
+      @Override
+      public String getName() {
+        return principal;
+      }
+    };
+    principals.add(p);
+    
+//        The newly constructed Sets check whether this Subject has been set read-only 
+//        before permitting subsequent modifications. The newly created Sets also prevent 
+//        illegal modifications by ensuring that callers have sufficient permissions.
+ //
+//        To modify the Principals Set, the caller must have AuthPermission("modifyPrincipals"). 
+//        To modify the public credential Set, the caller must have AuthPermission("modifyPublicCredentials"). 
+//        To modify the private credential Set, the caller must have AuthPermission("modifyPrivateCredentials").
+    javax.security.auth.Subject subject = new javax.security.auth.Subject(true, principals, emptySet, emptySet);
+    return subject;
+  }
+}

http://git-wip-us.apache.org/repos/asf/incubator-knox/blob/ba9dc3e5/gateway-provider-security-jwt/src/main/java/org/apache/hadoop/gateway/provider/authn/jwt/filter/JWTToken.java
----------------------------------------------------------------------
diff --git a/gateway-provider-security-jwt/src/main/java/org/apache/hadoop/gateway/provider/authn/jwt/filter/JWTToken.java b/gateway-provider-security-jwt/src/main/java/org/apache/hadoop/gateway/provider/authn/jwt/filter/JWTToken.java
new file mode 100644
index 0000000..d8544a3
--- /dev/null
+++ b/gateway-provider-security-jwt/src/main/java/org/apache/hadoop/gateway/provider/authn/jwt/filter/JWTToken.java
@@ -0,0 +1,136 @@
+  /**
+   * 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.provider.authn.jwt.filter;
+
+import java.io.UnsupportedEncodingException;
+import java.text.MessageFormat;
+
+import org.apache.commons.codec.binary.Base64;
+
+import com.jayway.jsonpath.JsonPath;
+
+public class JWTToken {
+  private static final String headerTemplate = "'{'\"alg\": \"{0}\"'}'";
+  private static final String claimTemplate = "'{'\"iss\": \"{0}\", \"prn\": \"{1}\", \"aud\": \"{2}\", \"exp\": \"{3}\"'}'";
+  public static final String PRINCIPAL = "prn";
+  public static final String ISSUER = "iss";
+  public static final String AUDIENCE = "aud";
+  public static final String EXPIRES = "exp";
+
+  public String header = null;
+  public String claims = null;
+  
+  byte[] payload = null;
+  
+  public JWTToken(byte[] header, byte[] claims, byte[] signature) {
+    try {
+      this.header = new String(header, "UTF-8");
+      this.claims = new String(claims, "UTF-8");
+      this.payload = signature;
+    } catch (UnsupportedEncodingException e) {
+      // TODO Auto-generated catch block
+      e.printStackTrace();
+    }
+  }
+
+  public JWTToken(String alg, String[] claimsArray) {
+    MessageFormat headerFormatter = new MessageFormat(headerTemplate);
+    String[] algArray = new String[1];
+    algArray[0] = alg;
+    header = headerFormatter.format(algArray);
+
+    MessageFormat claimsFormatter = new MessageFormat(claimTemplate);
+    claims = claimsFormatter.format(claimsArray);
+  }
+  
+  public String getPayloadToSign() {
+    StringBuffer sb = new StringBuffer();
+    try {
+      sb.append(Base64.encodeBase64URLSafeString(header.getBytes("UTF-8")));
+      sb.append(".");
+      sb.append(Base64.encodeBase64URLSafeString(claims.getBytes("UTF-8")));
+    } catch (UnsupportedEncodingException e) {
+      // TODO Auto-generated catch block
+      e.printStackTrace();
+    }
+    
+    return sb.toString();
+  }
+
+  public String toString() {
+    System.out.println("Rendering JWT token for the wire");
+    StringBuffer sb = new StringBuffer();
+    try {
+      sb.append(Base64.encodeBase64URLSafeString(header.getBytes("UTF-8")));
+      sb.append(".");
+      sb.append(Base64.encodeBase64URLSafeString(claims.getBytes("UTF-8")));
+      sb.append(".");
+      sb.append(Base64.encodeBase64URLSafeString(payload));
+    } catch (UnsupportedEncodingException e) {
+      // TODO Auto-generated catch block
+      e.printStackTrace();
+    }
+    
+    System.out.println("Returning JWT token for the wire: " + sb.toString());
+    return sb.toString();
+  }
+  
+  public void setSignaturePayload(byte[] payload) {
+    this.payload = payload;
+  }
+  
+  public byte[] getSignaturePayload() {
+    return this.payload;
+  }
+
+  public static JWTToken parseToken(String wireToken) {
+    JWTToken token = null;
+    System.out.println("token off the wire: " + wireToken);
+    String[] parts = wireToken.split("\\.");
+    token = new JWTToken(Base64.decodeBase64(parts[0]), Base64.decodeBase64(parts[1]), Base64.decodeBase64(parts[2]));
+    System.out.println("header: " + token.header);
+    System.out.println("claims: " + token.claims);
+    System.out.println("payload: " + new String(token.payload));
+    
+    return token;
+  }
+  
+  public String getClaim(String claimName) {
+    String claim = null;
+    
+    claim = JsonPath.read(claims, "$." + claimName);
+    
+    return claim;
+  }
+
+  public String getPrincipal() {
+    return getClaim(JWTToken.PRINCIPAL);
+  }
+
+  public String getIssuer() {
+    return getClaim(JWTToken.ISSUER);
+  }
+
+  public String getAudience() {
+    return getClaim(JWTToken.AUDIENCE);
+  }
+
+  public String getExpires() {
+    return getClaim(JWTToken.EXPIRES);
+  }
+}

http://git-wip-us.apache.org/repos/asf/incubator-knox/blob/ba9dc3e5/gateway-provider-security-jwt/src/main/java/org/apache/hadoop/gateway/provider/federation/jwt/deploy/JWTDeploymentContributor.java
----------------------------------------------------------------------
diff --git a/gateway-provider-security-jwt/src/main/java/org/apache/hadoop/gateway/provider/federation/jwt/deploy/JWTDeploymentContributor.java b/gateway-provider-security-jwt/src/main/java/org/apache/hadoop/gateway/provider/federation/jwt/deploy/JWTDeploymentContributor.java
new file mode 100644
index 0000000..32ac572
--- /dev/null
+++ b/gateway-provider-security-jwt/src/main/java/org/apache/hadoop/gateway/provider/federation/jwt/deploy/JWTDeploymentContributor.java
@@ -0,0 +1,52 @@
+/**
+ * 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.provider.federation.jwt.deploy;
+
+import org.apache.hadoop.gateway.deploy.DeploymentContext;
+import org.apache.hadoop.gateway.deploy.ProviderDeploymentContributorBase;
+import org.apache.hadoop.gateway.descriptor.FilterParamDescriptor;
+import org.apache.hadoop.gateway.descriptor.ResourceDescriptor;
+import org.apache.hadoop.gateway.topology.Provider;
+import org.apache.hadoop.gateway.topology.Service;
+import org.jboss.shrinkwrap.api.asset.StringAsset;
+
+import java.util.List;
+
+public class JWTDeploymentContributor extends ProviderDeploymentContributorBase {
+
+  private static final String FILTER_CLASSNAME = "org.apache.hadoop.gateway.provider.authn.jwt.filter.JWTFederationFilter";
+
+  @Override
+  public String getRole() {
+    return "federation";
+  }
+
+  @Override
+  public String getName() {
+    return "JWTProvider";
+  }
+
+  @Override
+  public void contributeProvider( DeploymentContext context, Provider provider ) {
+  }
+
+  @Override
+  public void contributeFilter( DeploymentContext context, Provider provider, Service service, ResourceDescriptor resource, List<FilterParamDescriptor> params ) {
+    resource.addFilter().name( getName() ).role( getRole() ).impl( FILTER_CLASSNAME ).params( params );
+  }
+}

http://git-wip-us.apache.org/repos/asf/incubator-knox/blob/ba9dc3e5/gateway-provider-security-jwt/src/main/java/org/apache/hadoop/gateway/provider/federation/jwt/filter/JWTAuthority.java
----------------------------------------------------------------------
diff --git a/gateway-provider-security-jwt/src/main/java/org/apache/hadoop/gateway/provider/federation/jwt/filter/JWTAuthority.java b/gateway-provider-security-jwt/src/main/java/org/apache/hadoop/gateway/provider/federation/jwt/filter/JWTAuthority.java
new file mode 100644
index 0000000..8471ee0
--- /dev/null
+++ b/gateway-provider-security-jwt/src/main/java/org/apache/hadoop/gateway/provider/federation/jwt/filter/JWTAuthority.java
@@ -0,0 +1,60 @@
+  /**
+   * 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.provider.federation.jwt.filter;
+
+import java.security.Principal;
+
+import javax.security.auth.Subject;
+
+import org.apache.hadoop.gateway.services.security.CryptoService;
+
+public class JWTAuthority {
+  private CryptoService crypto = null;
+  
+  public JWTAuthority(CryptoService crypto) {
+    this.crypto = crypto;
+  }
+  
+  public JWTToken issueToken(Subject subject) {
+    Principal p = (Principal) subject.getPrincipals().toArray()[0];
+    String[] claimArray = new String[4];
+    claimArray[0] = "gateway";
+    claimArray[1] = p.getName();
+    // TODO: what do we need here and how do we determine what it should be?
+    claimArray[2] = "https://login.hadoop.example.org";
+    // TODO: make the validity period configurable
+    claimArray[3] = Long.toString( ( System.currentTimeMillis()/1000 ) + 300);
+
+    JWTToken token = new JWTToken("RS256", claimArray);
+    signToken(token);
+    
+    return token;
+  }
+  
+  private void signToken(JWTToken token) {
+    byte[] signature = null;
+    signature = crypto.sign("SHA256withRSA","gateway-identity",token.getPayloadToSign());
+    token.setSignaturePayload(signature);
+  }
+  
+  public boolean verifyToken(JWTToken token) {
+    boolean rc = false;
+    rc = crypto.verify("SHA256withRSA", "gateway-identity", token.getPayloadToSign(), token.getSignaturePayload());
+    return rc;
+  }
+}

http://git-wip-us.apache.org/repos/asf/incubator-knox/blob/ba9dc3e5/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
new file mode 100644
index 0000000..be92b40
--- /dev/null
+++ b/gateway-provider-security-jwt/src/main/java/org/apache/hadoop/gateway/provider/federation/jwt/filter/JWTFederationFilter.java
@@ -0,0 +1,135 @@
+  /**
+   * 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.provider.federation.jwt.filter;
+
+import javax.security.auth.Subject;
+import javax.servlet.Filter;
+import javax.servlet.FilterChain;
+import javax.servlet.FilterConfig;
+import javax.servlet.ServletException;
+import javax.servlet.ServletRequest;
+import javax.servlet.ServletResponse;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+import org.apache.hadoop.gateway.services.GatewayServices;
+import org.apache.hadoop.gateway.services.security.CryptoService;
+
+import java.io.IOException;
+import java.security.Principal;
+import java.security.PrivilegedActionException;
+import java.security.PrivilegedExceptionAction;
+import java.util.HashSet;
+import java.util.Set;
+
+
+public class JWTFederationFilter implements Filter {
+
+  private static final String BEARER = "Bearer ";
+  private static final String GATEWAY_SERVICES_ATTRIBUTE = "org.apache.hadoop.gateway.gateway.services";
+  
+  private JWTAuthority authority = null;
+
+  @Override
+  public void init( FilterConfig filterConfig ) throws ServletException {
+    GatewayServices services = (GatewayServices) filterConfig.getServletContext().getAttribute(GATEWAY_SERVICES_ATTRIBUTE);
+    CryptoService crypto = (CryptoService) services.getService("CryptoService");
+    authority = new JWTAuthority(crypto);
+  }
+
+  public void destroy() {
+  }
+
+  public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) 
+      throws IOException, ServletException {
+    String header = ((HttpServletRequest) request).getHeader("Authorization");
+    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 = JWTToken.parseToken(wireToken);
+      boolean verified = authority.verifyToken(token);
+      if (verified) {
+        // TODO: validate expiration
+        // TODO: confirm that audience matches intended target
+        Subject subject = createSubjectFromToken(token);
+        continueWithEstablishedSecurityContext(subject, (HttpServletRequest)request, (HttpServletResponse)response, chain);
+      }
+      else {
+        ((HttpServletResponse) response).sendError(HttpServletResponse.SC_UNAUTHORIZED);
+        return; //break filter chain
+      }
+    }
+    else {
+      // no token provided in header
+      // TODO: may have to check cookie and url as well before sending error
+      ((HttpServletResponse) response).sendError(HttpServletResponse.SC_UNAUTHORIZED);
+      return; //break filter chain
+    }
+  }
+  
+  private void continueWithEstablishedSecurityContext(Subject subject, final HttpServletRequest request, final HttpServletResponse response, final FilterChain chain) throws IOException, ServletException {
+    try {
+      Subject.doAs(
+        subject,
+        new PrivilegedExceptionAction<Object>() {
+          @Override
+          public Object run() throws Exception {
+            chain.doFilter(request, response);
+            return null;
+          }
+        }
+        );
+    }
+    catch (PrivilegedActionException e) {
+      Throwable t = e.getCause();
+      if (t instanceof IOException) {
+        throw (IOException) t;
+      }
+      else if (t instanceof ServletException) {
+        throw (ServletException) t;
+      }
+      else {
+        throw new ServletException(t);
+      }
+    }
+  }
+  
+  private Subject createSubjectFromToken(JWTToken token) {
+    final String principal = token.getPrincipal();
+
+    HashSet emptySet = new HashSet();
+    Set<Principal> principals = new HashSet<Principal>();
+    Principal p = new Principal() {
+      @Override
+      public String getName() {
+        return principal;
+      }
+    };
+    principals.add(p);
+    
+//        The newly constructed Sets check whether this Subject has been set read-only 
+//        before permitting subsequent modifications. The newly created Sets also prevent 
+//        illegal modifications by ensuring that callers have sufficient permissions.
+ //
+//        To modify the Principals Set, the caller must have AuthPermission("modifyPrincipals"). 
+//        To modify the public credential Set, the caller must have AuthPermission("modifyPublicCredentials"). 
+//        To modify the private credential Set, the caller must have AuthPermission("modifyPrivateCredentials").
+    javax.security.auth.Subject subject = new javax.security.auth.Subject(true, principals, emptySet, emptySet);
+    return subject;
+  }
+}

http://git-wip-us.apache.org/repos/asf/incubator-knox/blob/ba9dc3e5/gateway-provider-security-jwt/src/main/java/org/apache/hadoop/gateway/provider/federation/jwt/filter/JWTProviderMessages.java
----------------------------------------------------------------------
diff --git a/gateway-provider-security-jwt/src/main/java/org/apache/hadoop/gateway/provider/federation/jwt/filter/JWTProviderMessages.java b/gateway-provider-security-jwt/src/main/java/org/apache/hadoop/gateway/provider/federation/jwt/filter/JWTProviderMessages.java
new file mode 100644
index 0000000..af2eabe
--- /dev/null
+++ b/gateway-provider-security-jwt/src/main/java/org/apache/hadoop/gateway/provider/federation/jwt/filter/JWTProviderMessages.java
@@ -0,0 +1,24 @@
+package org.apache.hadoop.gateway.provider.federation.jwt.filter;
+
+import org.apache.commons.cli.ParseException;
+import org.apache.hadoop.gateway.i18n.messages.Message;
+import org.apache.hadoop.gateway.i18n.messages.MessageLevel;
+import org.apache.hadoop.gateway.i18n.messages.Messages;
+import org.apache.hadoop.gateway.i18n.messages.StackTrace;
+
+import java.io.File;
+import java.net.URI;
+
+/**
+ *
+ */
+@Messages(logger="org.apache.hadoop.gateway")
+public interface JWTProviderMessages {
+
+  @Message( level = MessageLevel.DEBUG, text = "Rendering JWT Token for the wire: {0}" )
+  void renderingJWTTokenForTheWire(String string);
+
+  @Message( level = MessageLevel.DEBUG, text = "Parsing JWT Token from the wire: {0}" )
+  void parsingToken(String wireToken);
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-knox/blob/ba9dc3e5/gateway-provider-security-jwt/src/main/java/org/apache/hadoop/gateway/provider/federation/jwt/filter/JWTToken.java
----------------------------------------------------------------------
diff --git a/gateway-provider-security-jwt/src/main/java/org/apache/hadoop/gateway/provider/federation/jwt/filter/JWTToken.java b/gateway-provider-security-jwt/src/main/java/org/apache/hadoop/gateway/provider/federation/jwt/filter/JWTToken.java
new file mode 100644
index 0000000..4da185d
--- /dev/null
+++ b/gateway-provider-security-jwt/src/main/java/org/apache/hadoop/gateway/provider/federation/jwt/filter/JWTToken.java
@@ -0,0 +1,138 @@
+  /**
+   * 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.provider.federation.jwt.filter;
+
+import java.io.UnsupportedEncodingException;
+import java.text.MessageFormat;
+
+import org.apache.commons.codec.binary.Base64;
+import org.apache.hadoop.gateway.i18n.messages.MessagesFactory;
+
+import com.jayway.jsonpath.JsonPath;
+
+public class JWTToken {
+  private static final String headerTemplate = "'{'\"alg\": \"{0}\"'}'";
+  private static final String claimTemplate = "'{'\"iss\": \"{0}\", \"prn\": \"{1}\", \"aud\": \"{2}\", \"exp\": \"{3}\"'}'";
+  public static final String PRINCIPAL = "prn";
+  public static final String ISSUER = "iss";
+  public static final String AUDIENCE = "aud";
+  public static final String EXPIRES = "exp";
+  private static JWTProviderMessages log = MessagesFactory.get( JWTProviderMessages.class );
+
+  public String header = null;
+  public String claims = null;
+  
+  byte[] payload = null;
+  
+  public JWTToken(byte[] header, byte[] claims, byte[] signature) {
+    try {
+      this.header = new String(header, "UTF-8");
+      this.claims = new String(claims, "UTF-8");
+      this.payload = signature;
+    } catch (UnsupportedEncodingException e) {
+      // TODO Auto-generated catch block
+      e.printStackTrace();
+    }
+  }
+
+  public JWTToken(String alg, String[] claimsArray) {
+    MessageFormat headerFormatter = new MessageFormat(headerTemplate);
+    String[] algArray = new String[1];
+    algArray[0] = alg;
+    header = headerFormatter.format(algArray);
+
+    MessageFormat claimsFormatter = new MessageFormat(claimTemplate);
+    claims = claimsFormatter.format(claimsArray);
+  }
+  
+  public String getPayloadToSign() {
+    StringBuffer sb = new StringBuffer();
+    try {
+      sb.append(Base64.encodeBase64URLSafeString(header.getBytes("UTF-8")));
+      sb.append(".");
+      sb.append(Base64.encodeBase64URLSafeString(claims.getBytes("UTF-8")));
+    } catch (UnsupportedEncodingException e) {
+      // TODO Auto-generated catch block
+      e.printStackTrace();
+    }
+    
+    return sb.toString();
+  }
+
+  public String toString() {
+    StringBuffer sb = new StringBuffer();
+    try {
+      sb.append(Base64.encodeBase64URLSafeString(header.getBytes("UTF-8")));
+      sb.append(".");
+      sb.append(Base64.encodeBase64URLSafeString(claims.getBytes("UTF-8")));
+      sb.append(".");
+      sb.append(Base64.encodeBase64URLSafeString(payload));
+    } catch (UnsupportedEncodingException e) {
+      // TODO Auto-generated catch block
+      e.printStackTrace();
+    }
+    
+    log.renderingJWTTokenForTheWire(sb.toString());
+
+    return sb.toString();
+  }
+  
+  public void setSignaturePayload(byte[] payload) {
+    this.payload = payload;
+  }
+  
+  public byte[] getSignaturePayload() {
+    return this.payload;
+  }
+
+  public static JWTToken parseToken(String wireToken) {
+    JWTToken token = null;
+    log.parsingToken(wireToken);
+    String[] parts = wireToken.split("\\.");
+    token = new JWTToken(Base64.decodeBase64(parts[0]), Base64.decodeBase64(parts[1]), Base64.decodeBase64(parts[2]));
+    System.out.println("header: " + token.header);
+    System.out.println("claims: " + token.claims);
+    System.out.println("payload: " + new String(token.payload));
+    
+    return token;
+  }
+  
+  public String getClaim(String claimName) {
+    String claim = null;
+    
+    claim = JsonPath.read(claims, "$." + claimName);
+    
+    return claim;
+  }
+
+  public String getPrincipal() {
+    return getClaim(JWTToken.PRINCIPAL);
+  }
+
+  public String getIssuer() {
+    return getClaim(JWTToken.ISSUER);
+  }
+
+  public String getAudience() {
+    return getClaim(JWTToken.AUDIENCE);
+  }
+
+  public String getExpires() {
+    return getClaim(JWTToken.EXPIRES);
+  }
+}

http://git-wip-us.apache.org/repos/asf/incubator-knox/blob/ba9dc3e5/gateway-provider-security-jwt/src/main/resources/META-INF/services/org.apache.hadoop.gateway.deploy.ProviderDeploymentContributor
----------------------------------------------------------------------
diff --git a/gateway-provider-security-jwt/src/main/resources/META-INF/services/org.apache.hadoop.gateway.deploy.ProviderDeploymentContributor b/gateway-provider-security-jwt/src/main/resources/META-INF/services/org.apache.hadoop.gateway.deploy.ProviderDeploymentContributor
new file mode 100644
index 0000000..58c6bf7
--- /dev/null
+++ b/gateway-provider-security-jwt/src/main/resources/META-INF/services/org.apache.hadoop.gateway.deploy.ProviderDeploymentContributor
@@ -0,0 +1,19 @@
+##########################################################################
+# 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.
+##########################################################################
+
+org.apache.hadoop.gateway.provider.federation.jwt.deploy.JWTDeploymentContributor
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-knox/blob/ba9dc3e5/gateway-provider-security-jwt/src/test/java/org/apache/hadoop/gateway/provider/federation/JWTTokenTest.java
----------------------------------------------------------------------
diff --git a/gateway-provider-security-jwt/src/test/java/org/apache/hadoop/gateway/provider/federation/JWTTokenTest.java b/gateway-provider-security-jwt/src/test/java/org/apache/hadoop/gateway/provider/federation/JWTTokenTest.java
new file mode 100644
index 0000000..bdc34a0
--- /dev/null
+++ b/gateway-provider-security-jwt/src/test/java/org/apache/hadoop/gateway/provider/federation/JWTTokenTest.java
@@ -0,0 +1,40 @@
+package org.apache.hadoop.gateway.provider.federation;
+
+import org.apache.hadoop.gateway.provider.federation.jwt.filter.JWTToken;
+import org.junit.Test;
+
+import junit.framework.TestCase;
+
+public class JWTTokenTest extends TestCase {
+
+  private static final String JWT_TOKEN = "eyJhbGciOiJSUzI1NiJ9.eyJpc3MiOiAiZ2F0ZXdheSIsICJwcm4iOiAiam9obi5kb2VAZXhhbXBsZS5jb20iLCAiYXVkIjogImh0dHBzOi8vbG9naW4uZXhhbXBsZS5jb20iLCAiZXhwIjogIjEzNjMzNjA5MTMifQ.AUecCHfxT84-zllHs6_XvQuIx8186Y9s5waNOILVBoV11b4RINvknVDhIyR-j35LUn2ayQ9J2e1psey3-slWCs9B40_W-VeG5mPdtT6Job9c6ZX_eIgwSh-d88MlYoSXNt2oWcabMi6HmKeOxc6MfX__R4AMKdgXx5Jido5RRiw";
+  private static final String HEADER = "{\"alg\":\"RS256\"}";
+  private static final String CLAIMS = "{\"iss\": \"gateway\", \"prn\": \"john.doe@example.com\", \"aud\": \"https://login.example.com\", \"exp\": \"1363360913\"}";
+  
+  @Test
+  public void testTokenParsing() throws Exception {
+    JWTToken token = JWTToken.parseToken(JWT_TOKEN);
+    
+    assertEquals(token.header, HEADER);
+    assertEquals(token.claims, CLAIMS);
+    
+    assertEquals(token.getIssuer(), "gateway");
+    assertEquals(token.getPrincipal(), "john.doe@example.com");
+    assertEquals(token.getAudience(), "https://login.example.com");
+    assertEquals(token.getExpires(), "1363360913");
+  }
+  
+  @Test 
+  public void testTokenCreation() throws Exception {
+    String[] claims = new String[4];
+    claims[0] = "3MVG99OxTyEMCQ3gNp2PjkqeZKxnmAiG1xV4oHh9AKL_rSK.BoSVPGZHQukXnVjzRgSuQqGn75NL7yfkQcyy7";
+    claims[1] = "john.doe@example.com";
+    claims[2] = "https://login.example.com";
+    claims[3] = Long.toString( ( System.currentTimeMillis()/1000 ) + 300);
+    JWTToken token = new JWTToken("RS256", claims);
+
+    assertEquals(token.getIssuer(), "3MVG99OxTyEMCQ3gNp2PjkqeZKxnmAiG1xV4oHh9AKL_rSK.BoSVPGZHQukXnVjzRgSuQqGn75NL7yfkQcyy7");
+    assertEquals(token.getPrincipal(), "john.doe@example.com");
+    assertEquals(token.getAudience(), "https://login.example.com");
+  }
+}

http://git-wip-us.apache.org/repos/asf/incubator-knox/blob/ba9dc3e5/gateway-release/pom.xml
----------------------------------------------------------------------
diff --git a/gateway-release/pom.xml b/gateway-release/pom.xml
index 0ec0a3e..a872983 100644
--- a/gateway-release/pom.xml
+++ b/gateway-release/pom.xml
@@ -117,6 +117,10 @@
         </dependency>
         <dependency>
             <groupId>${gateway-group}</groupId>
+            <artifactId>gateway-provider-security-jwt</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>${gateway-group}</groupId>
             <artifactId>gateway-provider-identity-assertion-pseudo</artifactId>
         </dependency>
 

http://git-wip-us.apache.org/repos/asf/incubator-knox/blob/ba9dc3e5/gateway-server/src/main/java/org/apache/hadoop/gateway/services/DefaultGatewayServices.java
----------------------------------------------------------------------
diff --git a/gateway-server/src/main/java/org/apache/hadoop/gateway/services/DefaultGatewayServices.java b/gateway-server/src/main/java/org/apache/hadoop/gateway/services/DefaultGatewayServices.java
index fdd23d4..fcd3f66 100644
--- a/gateway-server/src/main/java/org/apache/hadoop/gateway/services/DefaultGatewayServices.java
+++ b/gateway-server/src/main/java/org/apache/hadoop/gateway/services/DefaultGatewayServices.java
@@ -70,6 +70,7 @@ public class DefaultGatewayServices implements Service, ProviderDeploymentContri
     services.put(ALIAS_SERVICE, alias);
 
     DefaultCryptoService crypto = new DefaultCryptoService();
+    crypto.setKeystoreService(ks);
     crypto.setAliasService(alias);
     crypto.init(config, options);
     services.put(CRYPTO_SERVICE, crypto);

http://git-wip-us.apache.org/repos/asf/incubator-knox/blob/ba9dc3e5/gateway-server/src/main/java/org/apache/hadoop/gateway/services/security/impl/DefaultAliasService.java
----------------------------------------------------------------------
diff --git a/gateway-server/src/main/java/org/apache/hadoop/gateway/services/security/impl/DefaultAliasService.java b/gateway-server/src/main/java/org/apache/hadoop/gateway/services/security/impl/DefaultAliasService.java
index 57ef251..f16c07a 100644
--- a/gateway-server/src/main/java/org/apache/hadoop/gateway/services/security/impl/DefaultAliasService.java
+++ b/gateway-server/src/main/java/org/apache/hadoop/gateway/services/security/impl/DefaultAliasService.java
@@ -17,6 +17,8 @@
  */
 package org.apache.hadoop.gateway.services.security.impl;
 
+import java.security.Key;
+import java.security.KeyStore;
 import java.util.Map;
 import java.util.Random;
 
@@ -24,6 +26,7 @@ import org.apache.hadoop.gateway.config.GatewayConfig;
 import org.apache.hadoop.gateway.services.ServiceLifecycleException;
 import org.apache.hadoop.gateway.services.security.AliasService;
 import org.apache.hadoop.gateway.services.security.KeystoreService;
+import org.apache.hadoop.gateway.services.security.KeystoreServiceException;
 
 public class DefaultAliasService implements AliasService {
 
@@ -102,4 +105,14 @@ public class DefaultAliasService implements AliasService {
     keystoreService.addCredentialForCluster(clusterName, alias, value);
   }
 
+  @Override
+  public char[] getPasswordFromAliasForGateway(String alias) {
+    return getPasswordFromAliasForCluster("__gateway", alias);
+  }
+
+  @Override
+  public void generateAliasForGateway(String alias) {
+    generateAliasForCluster("__gateway", alias);
+  }
+
 }

http://git-wip-us.apache.org/repos/asf/incubator-knox/blob/ba9dc3e5/gateway-server/src/main/java/org/apache/hadoop/gateway/services/security/impl/DefaultCryptoService.java
----------------------------------------------------------------------
diff --git a/gateway-server/src/main/java/org/apache/hadoop/gateway/services/security/impl/DefaultCryptoService.java b/gateway-server/src/main/java/org/apache/hadoop/gateway/services/security/impl/DefaultCryptoService.java
index 647cdc5..c942271 100644
--- a/gateway-server/src/main/java/org/apache/hadoop/gateway/services/security/impl/DefaultCryptoService.java
+++ b/gateway-server/src/main/java/org/apache/hadoop/gateway/services/security/impl/DefaultCryptoService.java
@@ -19,18 +19,31 @@ package org.apache.hadoop.gateway.services.security.impl;
 
 import java.io.UnsupportedEncodingException;
 import java.security.InvalidKeyException;
+import java.security.Key;
+import java.security.KeyStoreException;
 import java.security.NoSuchAlgorithmException;
+import java.security.PrivateKey;
+import java.security.Signature;
+import java.security.SignatureException;
 import java.util.Map;
 
+import org.apache.commons.codec.binary.Base64;
 import org.apache.hadoop.gateway.config.GatewayConfig;
 import org.apache.hadoop.gateway.services.security.AliasService;
 import org.apache.hadoop.gateway.services.security.CryptoService;
 import org.apache.hadoop.gateway.services.security.EncryptionResult;
+import org.apache.hadoop.gateway.services.security.KeystoreService;
+import org.apache.hadoop.gateway.services.security.KeystoreServiceException;
 import org.apache.hadoop.gateway.services.ServiceLifecycleException;
 
 public class DefaultCryptoService implements CryptoService {
   
   private AliasService as = null;
+  private KeystoreService ks = null;
+
+  public void setKeystoreService(KeystoreService ks) {
+    this.ks = ks;
+  }
 
   public CryptoService setAliasService(AliasService as) {
     this.as = as;
@@ -109,4 +122,59 @@ public class DefaultCryptoService implements CryptoService {
     }
     return null;
   }
+
+  @Override
+  public boolean verify(String algorithm, String alias, String signed, byte[] signature) {
+    boolean verified = false;
+    try {
+      Signature sig=Signature.getInstance(algorithm);
+      sig.initVerify(ks.getKeystoreForGateway().getCertificate(alias).getPublicKey());
+      sig.update(signed.getBytes("UTF-8"));
+      verified = sig.verify(signature);
+    } catch (SignatureException e) {
+      // TODO Auto-generated catch block
+      e.printStackTrace();
+    } catch (NoSuchAlgorithmException e) {
+      // TODO Auto-generated catch block
+      e.printStackTrace();
+    } catch (InvalidKeyException e) {
+      // TODO Auto-generated catch block
+      e.printStackTrace();
+    } catch (KeyStoreException e) {
+      // TODO Auto-generated catch block
+      e.printStackTrace();
+    } catch (UnsupportedEncodingException e) {
+      // TODO Auto-generated catch block
+      e.printStackTrace();
+    }
+    System.out.println("Signature verified: " + verified);  
+    return verified;
+  }
+
+  @Override
+  public byte[] sign(String algorithm, String alias, String payloadToSign) {
+    try {
+      PrivateKey privateKey = (PrivateKey) ks.getKeyForGateway(alias);
+      Signature signature = Signature.getInstance(algorithm);
+      signature.initSign(privateKey);
+      signature.update(payloadToSign.getBytes("UTF-8"));
+      return signature.sign();
+    } catch (NoSuchAlgorithmException e) {
+      // TODO Auto-generated catch block
+      e.printStackTrace();
+    } catch (InvalidKeyException e) {
+      // TODO Auto-generated catch block
+      e.printStackTrace();
+    } catch (SignatureException e) {
+      // TODO Auto-generated catch block
+      e.printStackTrace();
+    } catch (UnsupportedEncodingException e) {
+      // TODO Auto-generated catch block
+      e.printStackTrace();
+    } catch (KeystoreServiceException e) {
+      // TODO Auto-generated catch block
+      e.printStackTrace();
+    }
+    return null;
+  }
 }

http://git-wip-us.apache.org/repos/asf/incubator-knox/blob/ba9dc3e5/gateway-server/src/main/java/org/apache/hadoop/gateway/services/security/impl/DefaultKeystoreService.java
----------------------------------------------------------------------
diff --git a/gateway-server/src/main/java/org/apache/hadoop/gateway/services/security/impl/DefaultKeystoreService.java b/gateway-server/src/main/java/org/apache/hadoop/gateway/services/security/impl/DefaultKeystoreService.java
index c9545b2..88458ba 100644
--- a/gateway-server/src/main/java/org/apache/hadoop/gateway/services/security/impl/DefaultKeystoreService.java
+++ b/gateway-server/src/main/java/org/apache/hadoop/gateway/services/security/impl/DefaultKeystoreService.java
@@ -258,6 +258,27 @@ public class DefaultKeystoreService implements KeystoreService {
     return false;
   }
 
+  @Override
+  public Key getKeyForGateway(String alias) throws KeystoreServiceException {
+    Key key = null;
+    KeyStore ks = getKeystoreForGateway();
+    if (ks != null) {
+      try {
+        key = ks.getKey(alias, masterService.getMasterSecret());
+      } catch (UnrecoverableKeyException e) {
+        // TODO Auto-generated catch block
+        e.printStackTrace();
+      } catch (KeyStoreException e) {
+        // TODO Auto-generated catch block
+        e.printStackTrace();
+      } catch (NoSuchAlgorithmException e) {
+        // TODO Auto-generated catch block
+        e.printStackTrace();
+      }
+    }
+    return key;
+  }  
+  
   public KeyStore getCredentialStoreForCluster(String clusterName) {
     final File  keyStoreFile = new File( keyStoreDir + clusterName + CREDENTIALS_SUFFIX  );
     return getKeystore(keyStoreFile, "JCEKS");
@@ -308,6 +329,7 @@ public class DefaultKeystoreService implements KeystoreService {
 
   public void writeKeystoreToFile(final KeyStore keyStore, final File file)
          throws KeyStoreException, IOException, NoSuchAlgorithmException, CertificateException {
+    // TODO: does this really need to be part of the interface?
     // TODO: backup the keystore on disk before attempting a write and restore on failure
       final FileOutputStream  out = new FileOutputStream(file);
       try

http://git-wip-us.apache.org/repos/asf/incubator-knox/blob/ba9dc3e5/gateway-server/src/test/java/org/apache/hadoop/gateway/services/security/CryptoServiceTest.java
----------------------------------------------------------------------
diff --git a/gateway-server/src/test/java/org/apache/hadoop/gateway/services/security/CryptoServiceTest.java b/gateway-server/src/test/java/org/apache/hadoop/gateway/services/security/CryptoServiceTest.java
index f42a291..d014242 100644
--- a/gateway-server/src/test/java/org/apache/hadoop/gateway/services/security/CryptoServiceTest.java
+++ b/gateway-server/src/test/java/org/apache/hadoop/gateway/services/security/CryptoServiceTest.java
@@ -73,6 +73,18 @@ public class CryptoServiceTest {
       @Override
       public void generateAliasForCluster(String clusterName, String alias) {
       }
+
+      @Override
+      public char[] getPasswordFromAliasForGateway(String alias) {
+        // TODO Auto-generated method stub
+        return null;
+      }
+
+      @Override
+      public void generateAliasForGateway(String alias) {
+        // TODO Auto-generated method stub
+        
+      }
     };
     cs = new DefaultCryptoService().setAliasService(as);
   }

http://git-wip-us.apache.org/repos/asf/incubator-knox/blob/ba9dc3e5/gateway-service-hdfs/src/main/java/org/apache/hadoop/gateway/hdfs/HdfsDeploymentContributor.java
----------------------------------------------------------------------
diff --git a/gateway-service-hdfs/src/main/java/org/apache/hadoop/gateway/hdfs/HdfsDeploymentContributor.java b/gateway-service-hdfs/src/main/java/org/apache/hadoop/gateway/hdfs/HdfsDeploymentContributor.java
index 407a79b..721d8f0 100644
--- a/gateway-service-hdfs/src/main/java/org/apache/hadoop/gateway/hdfs/HdfsDeploymentContributor.java
+++ b/gateway-service-hdfs/src/main/java/org/apache/hadoop/gateway/hdfs/HdfsDeploymentContributor.java
@@ -119,7 +119,12 @@ public class HdfsDeploymentContributor extends ServiceDeploymentContributorBase
   }
 
   private void addAuthenticationFilter( DeploymentContext context, Service service, ResourceDescriptor resource ) {
-    context.contributeFilter( service, resource, "authentication", null, null );
+    if (topologyContainsProviderType(context, "authentication")) {
+      context.contributeFilter( service, resource, "authentication", null, null );
+    }
+    if (topologyContainsProviderType(context, "federation")) {
+      context.contributeFilter( service, resource, "federation", null, null );
+    }
   }
 
   private void addIdentityAssertionFilter(DeploymentContext context, Service service, ResourceDescriptor resource) {

http://git-wip-us.apache.org/repos/asf/incubator-knox/blob/ba9dc3e5/gateway-service-oozie/src/main/java/org/apache/hadoop/gateway/oozie/OozieDeploymentContributor.java
----------------------------------------------------------------------
diff --git a/gateway-service-oozie/src/main/java/org/apache/hadoop/gateway/oozie/OozieDeploymentContributor.java b/gateway-service-oozie/src/main/java/org/apache/hadoop/gateway/oozie/OozieDeploymentContributor.java
index 1b8f100..8ac1f31 100644
--- a/gateway-service-oozie/src/main/java/org/apache/hadoop/gateway/oozie/OozieDeploymentContributor.java
+++ b/gateway-service-oozie/src/main/java/org/apache/hadoop/gateway/oozie/OozieDeploymentContributor.java
@@ -84,7 +84,12 @@ public class OozieDeploymentContributor extends ServiceDeploymentContributorBase
   }
 
   private void addAuthenticationFilter( DeploymentContext context, Service service, ResourceDescriptor resource ) {
-    context.contributeFilter( service, resource, "authentication", null, null );
+    if (topologyContainsProviderType(context, "authentication")) {
+      context.contributeFilter( service, resource, "authentication", null, null );
+    }
+    if (topologyContainsProviderType(context, "federation")) {
+      context.contributeFilter( service, resource, "federation", null, null );
+    }
   }
 
   private void addRewriteFilter(

http://git-wip-us.apache.org/repos/asf/incubator-knox/blob/ba9dc3e5/gateway-service-templeton/src/main/java/org/apache/hadoop/gateway/templeton/TempletonDeploymentContributor.java
----------------------------------------------------------------------
diff --git a/gateway-service-templeton/src/main/java/org/apache/hadoop/gateway/templeton/TempletonDeploymentContributor.java b/gateway-service-templeton/src/main/java/org/apache/hadoop/gateway/templeton/TempletonDeploymentContributor.java
index 7600268..fcaf5cc 100644
--- a/gateway-service-templeton/src/main/java/org/apache/hadoop/gateway/templeton/TempletonDeploymentContributor.java
+++ b/gateway-service-templeton/src/main/java/org/apache/hadoop/gateway/templeton/TempletonDeploymentContributor.java
@@ -56,7 +56,12 @@ public class TempletonDeploymentContributor extends ServiceDeploymentContributor
     ResourceDescriptor resource = context.getGatewayDescriptor().addResource();
     resource.role( service.getRole() );
     resource.pattern( TEMPLETON_EXTERNAL_PATH + "/**?**" );
-    context.contributeFilter( service, resource, "authentication", null, null );
+    if (topologyContainsProviderType(context, "authentication")) {
+      context.contributeFilter( service, resource, "authentication", null, null );
+    }
+    if (topologyContainsProviderType(context, "federation")) {
+      context.contributeFilter( service, resource, "federation", null, null );
+    }
     context.contributeFilter( service, resource, "rewrite", null, null );
     context.contributeFilter( service, resource, "identity-assertion", null, null );
     context.contributeFilter( service, resource, "dispatch", null, null );

http://git-wip-us.apache.org/repos/asf/incubator-knox/blob/ba9dc3e5/gateway-spi/src/main/java/org/apache/hadoop/gateway/deploy/ServiceDeploymentContributorBase.java
----------------------------------------------------------------------
diff --git a/gateway-spi/src/main/java/org/apache/hadoop/gateway/deploy/ServiceDeploymentContributorBase.java b/gateway-spi/src/main/java/org/apache/hadoop/gateway/deploy/ServiceDeploymentContributorBase.java
index 7acca27..28d6db7 100644
--- a/gateway-spi/src/main/java/org/apache/hadoop/gateway/deploy/ServiceDeploymentContributorBase.java
+++ b/gateway-spi/src/main/java/org/apache/hadoop/gateway/deploy/ServiceDeploymentContributorBase.java
@@ -17,6 +17,10 @@
  */
 package org.apache.hadoop.gateway.deploy;
 
+import java.util.Collection;
+
+import org.apache.hadoop.gateway.topology.Provider;
+
 public abstract class ServiceDeploymentContributorBase extends DeploymentContributorBase implements ServiceDeploymentContributor {
 
   public void initializeContribution( DeploymentContext context ) {
@@ -27,4 +31,14 @@ public abstract class ServiceDeploymentContributorBase extends DeploymentContrib
     // Noop.
   }
 
+  protected boolean topologyContainsProviderType(DeploymentContext context, String role) {
+    Collection<Provider> providers = context.getTopology().getProviders();
+    for (Provider provider : providers) {
+      if (role.equals(provider.getRole())) {
+        return true;
+      }
+    }
+    return false;
+  }
+
 }

http://git-wip-us.apache.org/repos/asf/incubator-knox/blob/ba9dc3e5/gateway-spi/src/main/java/org/apache/hadoop/gateway/services/security/AliasService.java
----------------------------------------------------------------------
diff --git a/gateway-spi/src/main/java/org/apache/hadoop/gateway/services/security/AliasService.java b/gateway-spi/src/main/java/org/apache/hadoop/gateway/services/security/AliasService.java
index a2799bd..b32bbb1 100644
--- a/gateway-spi/src/main/java/org/apache/hadoop/gateway/services/security/AliasService.java
+++ b/gateway-spi/src/main/java/org/apache/hadoop/gateway/services/security/AliasService.java
@@ -17,6 +17,8 @@
  */
 package org.apache.hadoop.gateway.services.security;
 
+import java.security.Key;
+
 import org.apache.hadoop.gateway.services.Service;
 
 public interface AliasService extends Service {
@@ -28,4 +30,8 @@ public interface AliasService extends Service {
   public abstract char[] getPasswordFromAliasForCluster(String clusterName, String alias, boolean generate);
 
   void generateAliasForCluster(String clusterName, String alias);
+
+  public abstract char[] getPasswordFromAliasForGateway(String alias);
+
+  void generateAliasForGateway(String alias);
 }
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-knox/blob/ba9dc3e5/gateway-spi/src/main/java/org/apache/hadoop/gateway/services/security/CryptoService.java
----------------------------------------------------------------------
diff --git a/gateway-spi/src/main/java/org/apache/hadoop/gateway/services/security/CryptoService.java b/gateway-spi/src/main/java/org/apache/hadoop/gateway/services/security/CryptoService.java
index 9b8527f..7d09f38 100644
--- a/gateway-spi/src/main/java/org/apache/hadoop/gateway/services/security/CryptoService.java
+++ b/gateway-spi/src/main/java/org/apache/hadoop/gateway/services/security/CryptoService.java
@@ -28,4 +28,8 @@ public interface CryptoService extends Service {
   public byte[] decryptForCluster(String clusterName, String alias, String cipherText);
 
   public byte[] decryptForCluster(String clusterName, String alias, byte[] cipherText, byte[] iv, byte[] salt);
+
+  public boolean verify(String algorithm, String alias, String payloadToSign, byte[] signaturePayload);
+
+  public byte[] sign(String algorithm, String alias, String payloadToSign);
 }

http://git-wip-us.apache.org/repos/asf/incubator-knox/blob/ba9dc3e5/gateway-spi/src/main/java/org/apache/hadoop/gateway/services/security/KeystoreService.java
----------------------------------------------------------------------
diff --git a/gateway-spi/src/main/java/org/apache/hadoop/gateway/services/security/KeystoreService.java b/gateway-spi/src/main/java/org/apache/hadoop/gateway/services/security/KeystoreService.java
index 3451207..65c8a2a 100644
--- a/gateway-spi/src/main/java/org/apache/hadoop/gateway/services/security/KeystoreService.java
+++ b/gateway-spi/src/main/java/org/apache/hadoop/gateway/services/security/KeystoreService.java
@@ -19,6 +19,7 @@ package org.apache.hadoop.gateway.services.security;
 
 import java.io.File;
 import java.io.IOException;
+import java.security.Key;
 import java.security.KeyStore;
 import java.security.KeyStoreException;
 import java.security.NoSuchAlgorithmException;
@@ -34,6 +35,8 @@ public interface KeystoreService extends Service {
   
   public KeyStore getKeystoreForGateway();
   
+  public Key getKeyForGateway(String alias) throws KeystoreServiceException;
+
   public void createCredentialStoreForCluster(String clusterName);
   
   public boolean isCredentialStoreForClusterAvailable(String clusterName) throws KeystoreServiceException;

http://git-wip-us.apache.org/repos/asf/incubator-knox/blob/ba9dc3e5/pom.xml
----------------------------------------------------------------------
diff --git a/pom.xml b/pom.xml
index 0ddf45d..93fa7c5 100644
--- a/pom.xml
+++ b/pom.xml
@@ -52,6 +52,7 @@
         <module>gateway-provider-rewrite</module>
         <module>gateway-provider-hostmap-static</module>
         <module>gateway-provider-secure-query</module>
+        <module>gateway-provider-security-jwt</module>
         <module>gateway-provider-security-shiro</module>
         <module>gateway-provider-identity-assertion-pseudo</module>
         <module>gateway-service-hdfs</module>
@@ -272,6 +273,11 @@
             </dependency>
             <dependency>
                 <groupId>${gateway-group}</groupId>
+                <artifactId>gateway-provider-security-jwt</artifactId>
+                <version>${gateway-version}</version>
+            </dependency>
+            <dependency>
+                <groupId>${gateway-group}</groupId>
                 <artifactId>gateway-provider-security-shiro</artifactId>
                 <version>${gateway-version}</version>
             </dependency>
@@ -617,7 +623,6 @@
                 <groupId>com.jayway.jsonpath</groupId>
                 <artifactId>json-path</artifactId>
                 <version>0.8.1</version>
-                <scope>test</scope>
             </dependency>
             <dependency>
                 <groupId>com.jayway.jsonpath</groupId>