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 2015/04/11 02:03:38 UTC

[3/3] knox git commit: KNOX-509 KnoxSSO with WebSSO support and picketlink provider for SAML WebSSO

KNOX-509 KnoxSSO with WebSSO support and picketlink provider for SAML WebSSO


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

Branch: refs/heads/master
Commit: 905135b66b4e431a90ad625b88837ea9af986d64
Parents: 4f2b2dd 95136c5
Author: Larry McCay <lm...@hortonworks.com>
Authored: Fri Apr 10 20:03:10 2015 -0400
Committer: Larry McCay <lm...@hortonworks.com>
Committed: Fri Apr 10 20:03:10 2015 -0400

----------------------------------------------------------------------
 ...entityAsserterHttpServletRequestWrapper.java |  11 +-
 .../provider/federation/JWTTokenTest.java       |  19 +-
 gateway-provider-security-picketlink/pom.xml    |  82 +++++++
 .../gateway/picketlink/PicketlinkMessages.java  |  33 +++
 .../picketlink/deploy/PicketlinkConf.java       | 194 +++++++++++++++++
 ...PicketlinkFederationProviderContributor.java | 122 +++++++++++
 .../filter/CaptureOriginalURLFilter.java        |  74 +++++++
 .../filter/PicketlinkIdentityAdapter.java       |  92 ++++++++
 ...gateway.deploy.ProviderDeploymentContributor |  19 ++
 .../gateway/picketlink/PicketlinkTest.java      |  31 +++
 gateway-release/pom.xml                         |   8 +
 .../services/DefaultGatewayServices.java        |   4 +-
 .../gateway/services/HssoGatewayServices.java   |   3 +-
 .../security/impl/DefaultCryptoService.java     |   3 +-
 .../impl/DefaultTokenAuthorityService.java      |  67 ++++--
 .../services/security/CryptoServiceTest.java    |   3 +-
 gateway-service-knoxsso/pom.xml                 |  54 +++++
 .../service/knoxsso/KnoxSSOMessages.java        |  46 ++++
 .../gateway/service/knoxsso/WebSSOResource.java | 167 +++++++++++++++
 .../KnoxSSOServiceDeploymentContributor.java    |  60 ++++++
 ....gateway.deploy.ServiceDeploymentContributor |  19 ++
 gateway-spi/pom.xml                             |  11 +
 .../services/security/token/impl/JWT.java       |  58 +++++
 .../services/security/token/impl/JWTToken.java  | 214 ++++++++++++++-----
 pom.xml                                         |  35 ++-
 25 files changed, 1334 insertions(+), 95 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/knox/blob/905135b6/gateway-provider-identity-assertion-common/src/main/java/org/apache/hadoop/gateway/identityasserter/common/filter/IdentityAsserterHttpServletRequestWrapper.java
----------------------------------------------------------------------
diff --cc gateway-provider-identity-assertion-common/src/main/java/org/apache/hadoop/gateway/identityasserter/common/filter/IdentityAsserterHttpServletRequestWrapper.java
index 63a1e4d,0000000..50e9e60
mode 100644,000000..100644
--- a/gateway-provider-identity-assertion-common/src/main/java/org/apache/hadoop/gateway/identityasserter/common/filter/IdentityAsserterHttpServletRequestWrapper.java
+++ b/gateway-provider-identity-assertion-common/src/main/java/org/apache/hadoop/gateway/identityasserter/common/filter/IdentityAsserterHttpServletRequestWrapper.java
@@@ -1,227 -1,0 +1,236 @@@
 +/**
 + * 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.identityasserter.common.filter;
 +
 +import org.apache.commons.io.IOUtils;
 +import org.apache.hadoop.gateway.SpiGatewayMessages;
 +import org.apache.hadoop.gateway.config.GatewayConfig;
 +import org.apache.hadoop.gateway.i18n.messages.MessagesFactory;
 +
 +import javax.servlet.ServletInputStream;
 +import javax.servlet.http.HttpServletRequest;
 +import javax.servlet.http.HttpServletRequestWrapper;
 +import java.io.ByteArrayInputStream;
 +import java.io.IOException;
 +import java.io.InputStream;
 +import java.io.UnsupportedEncodingException;
 +import java.net.URLEncoder;
 +import java.nio.charset.Charset;
 +import java.util.ArrayList;
 +import java.util.Collection;
 +import java.util.Collections;
 +import java.util.Enumeration;
 +import java.util.HashMap;
 +import java.util.Map;
 +
 +public class IdentityAsserterHttpServletRequestWrapper extends HttpServletRequestWrapper {
 +
 +  private static SpiGatewayMessages log = MessagesFactory.get( SpiGatewayMessages.class );
 +
 +  private static final String PRINCIPAL_PARAM = "user.name";
 +  private static final String DOAS_PRINCIPAL_PARAM = "doAs";
 +  
 +  String username = null;
 +
 +  public IdentityAsserterHttpServletRequestWrapper( HttpServletRequest request, String principal ) {
 +    super(request);
 +    username = principal;
 +  }
 +
 +  @Override
 +  public String getParameter(String name) {
 +    if (name.equals(PRINCIPAL_PARAM)) {
 +      return username;
 +    }
 +    return super.getParameter(name);
 +  }
 +  
 +  @SuppressWarnings("rawtypes")
 +  @Override
 +  public Map getParameterMap() {
 +    return getParams();
 +  }
 +
 +  @SuppressWarnings({ "unchecked", "rawtypes" })
 +  @Override
 +  public Enumeration getParameterNames() {
 +    Map<String, String[]> params = getParams();
-     Enumeration<String> e = Collections.enumeration((Collection<String>) params);
++    if (params == null) {
++      params = new HashMap<String, String[]>();
++    }
++    Enumeration<String> e = Collections.enumeration((Collection<String>) params.keySet());
 +
 +    return e;
 +  }
 +
 +  @Override
 +  public String[] getParameterValues(String name) {
 +    Map<String, String[]> params = getParams();
++    if (params == null) {
++      params = new HashMap<String, String[]>();
++    }
 +
 +    return params.get(name);
 +  }
 +
 +  private Map<String, String[]> getParams( String qString ) {
 +    Map<String, String[]> params = null;
 +    if (getMethod().equals("GET")) {
 +      if (qString != null && qString.length() > 0) {
 +        params = parseQueryString(qString);
 +      }
 +      else {
 +        params = new HashMap<String, String[]>();
 +      }
 +    }
 +    else {
 +      if (qString == null || qString.length() == 0) {
 +        return null;
 +      }
 +      else {
 +        params = parseQueryString(qString);
 +      }
 +    }  
 +    return params;
 +  }
 +
 +  private Map<String, String[]> getParams() {
 +    return getParams( super.getQueryString() );
 +  }
 +  
 +  @Override
 +  public String getQueryString() {
 +    String q = null;
 +    Map<String, String[]> params = getParams();
 +
 +    if (params == null) {
 +      params = new HashMap<String, String[]>();
 +    }
 +    
 +    ArrayList<String> al = new ArrayList<String>();
 +    al.add(username);
 +    String[] a = { "" };
 +
 +    if ("true".equals(System.getProperty(GatewayConfig.HADOOP_KERBEROS_SECURED))) {
 +      params.put(DOAS_PRINCIPAL_PARAM, al.toArray(a));
 +      params.remove(PRINCIPAL_PARAM);
 +    } else {
 +      params.put(PRINCIPAL_PARAM, al.toArray(a));
 +    }
 +    
 +    String encoding = getCharacterEncoding();
 +    if (encoding == null) {
 +      encoding = Charset.defaultCharset().name();
 +    }
 +    q = urlEncode(params, encoding);
 +    return q;
 +  }
 +
 +  @Override
 +  public int getContentLength() {
 +    int len;
 +    String contentType = getContentType();
 +    // If the content type is a form we might rewrite the body so default it to -1.
 +    if( contentType != null && contentType.startsWith( "application/x-www-form-urlencoded" ) ) {
 +      len = -1;
 +    } else {
 +      len = super.getContentLength();
 +    }
 +    return len;
 +  }
 +
 +  @Override
 +  public ServletInputStream getInputStream() throws java.io.IOException {
 +    String contentType = getContentType();
 +    if( contentType != null && contentType.startsWith( "application/x-www-form-urlencoded" ) ) {
 +      String encoding = getCharacterEncoding();
 +      if( encoding == null ) {
 +        encoding = Charset.defaultCharset().name();
 +      }
 +      String body = IOUtils.toString( super.getInputStream(), encoding );
 +      Map<String, String[]> params = getParams( body );
++      if (params == null) {
++        params = new HashMap<String, String[]>();
++      }
 +      body = urlEncode( params, encoding );
 +      // ASCII is OK here because the urlEncode about should have already escaped
 +      return new ServletInputStreamWrapper( new ByteArrayInputStream( body.getBytes( "US-ASCII" ) ) );
 +    } else {
 +      return super.getInputStream();
 +    }
 +  }
 +
 +  static String urlEncode( String string, String encoding ) {
 +    try {
 +      return URLEncoder.encode( string, encoding );
 +    } catch (UnsupportedEncodingException e) {
 +      throw new UnsupportedOperationException(e);
 +    }
 +  }
 +
 +  public static String urlEncode( Map<String, String[]> map, String encoding ) {
 +    StringBuilder sb = new StringBuilder();
 +    for( Map.Entry<String,String[]> entry : map.entrySet() ) {
 +      String name = entry.getKey();
 +      if( name != null && name.length() > 0 ) {
 +        String[] values = entry.getValue();
 +        if( values == null || values.length == 0 ) {
 +          sb.append( entry.getKey() );
 +        } else {
 +          for( int i = 0; i < values.length; i++ ) {
 +            String value = values[ i ];
 +            if( value != null ) {
 +              if( sb.length() > 0 ) {
 +                sb.append( "&" );
 +              }
 +              try {
 +                sb.append( urlEncode( name, encoding ) );
 +                sb.append( "=" );
 +                sb.append( urlEncode( value, encoding ) );
 +              } catch( IllegalArgumentException e ) {
 +                log.skippingUnencodableParameter( name, value, encoding, e );
 +              }
 +            }
 +          }
 +        }
 +      }
 +    }
 +    return sb.toString();
 +  }
 +
 +  @SuppressWarnings({ "deprecation", "unchecked" })
 +  private static Map<String,String[]> parseQueryString( String queryString ) {
 +    return javax.servlet.http.HttpUtils.parseQueryString( queryString );
 +  }
 +  
 +  private class ServletInputStreamWrapper extends ServletInputStream {
 +
 +    private InputStream stream;
 +
 +    private ServletInputStreamWrapper( InputStream stream ) {
 +      this.stream = stream;
 +    }
 +
 +    @Override
 +    public int read() throws IOException {
 +      return stream.read();
 +    }
 +
 +  }
 +
 +}

http://git-wip-us.apache.org/repos/asf/knox/blob/905135b6/gateway-provider-security-picketlink/src/main/java/org/apache/hadoop/gateway/picketlink/PicketlinkMessages.java
----------------------------------------------------------------------
diff --cc gateway-provider-security-picketlink/src/main/java/org/apache/hadoop/gateway/picketlink/PicketlinkMessages.java
index 0000000,0000000..0272ba6
new file mode 100644
--- /dev/null
+++ b/gateway-provider-security-picketlink/src/main/java/org/apache/hadoop/gateway/picketlink/PicketlinkMessages.java
@@@ -1,0 -1,0 +1,33 @@@
++/**
++ * 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.picketlink;
++
++import org.apache.hadoop.gateway.i18n.messages.Message;
++import org.apache.hadoop.gateway.i18n.messages.MessageLevel;
++import org.apache.hadoop.gateway.i18n.messages.Messages;
++
++@Messages(logger="org.apache.hadoop.gateway.picketlink")
++public interface PicketlinkMessages {
++
++  @Message( level = MessageLevel.DEBUG, text = "Found Original URL in reequest: {0}")
++  public void foundOriginalURLInRequest(String url);
++
++  @Message( level = MessageLevel.DEBUG, text = "setting cookie for original-url")
++  public void settingCookieForOriginalURL();
++
++}

http://git-wip-us.apache.org/repos/asf/knox/blob/905135b6/gateway-provider-security-picketlink/src/main/java/org/apache/hadoop/gateway/picketlink/filter/CaptureOriginalURLFilter.java
----------------------------------------------------------------------
diff --cc gateway-provider-security-picketlink/src/main/java/org/apache/hadoop/gateway/picketlink/filter/CaptureOriginalURLFilter.java
index 0000000,247b520..89d1ade
mode 000000,100644..100644
--- a/gateway-provider-security-picketlink/src/main/java/org/apache/hadoop/gateway/picketlink/filter/CaptureOriginalURLFilter.java
+++ b/gateway-provider-security-picketlink/src/main/java/org/apache/hadoop/gateway/picketlink/filter/CaptureOriginalURLFilter.java
@@@ -1,0 -1,65 +1,74 @@@
+ /**
+  * 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.picketlink.filter;
+ 
+ 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.Cookie;
+ import javax.servlet.http.HttpServletRequest;
+ import javax.servlet.http.HttpServletResponse;
++
++import org.apache.hadoop.gateway.i18n.messages.MessagesFactory;
++import org.apache.hadoop.gateway.picketlink.PicketlinkMessages;
++
+ import java.io.IOException;
+ 
+ public class CaptureOriginalURLFilter implements Filter {
 -    
++  private static PicketlinkMessages log = MessagesFactory.get( PicketlinkMessages.class );
++  private static final String COOKIE_PATH = "cookie.path"; 
++  private String cookiePath = null;
++
+   @Override
+   public void init( FilterConfig filterConfig ) throws ServletException {
 -    // TODO: get the cookie path from filterConfig
++    cookiePath = filterConfig.getInitParameter(COOKIE_PATH);
++    if (cookiePath == null) {
++      cookiePath = "/gateway/idp/knoxsso/websso";
++    }
+   }
+ 
+   @Override
+   public void doFilter( ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain ) throws IOException, ServletException {
+     String original = null;
+     HttpServletRequest request = (HttpServletRequest)servletRequest;
 -    System.out.println( "CaptureOriginalURLFilter" );
 -    if (request.getParameter("originalUrl") != null) {
 -      System.out.println( "original url found in request" );
++    String url = request.getParameter("originalUrl");
++    if (url != null) {
++      log.foundOriginalURLInRequest(url);
+       original = request.getParameter("originalUrl");
 -      System.out.println( "setting cookie for original-url" );
++      log.settingCookieForOriginalURL();
+       addCookie(servletResponse, original);
+     }
+     filterChain.doFilter(request, servletResponse);
+   }
+ 
+   @Override
+   public void destroy() {
+ 
+   }
+   
+   private void addCookie(ServletResponse servletResponse, String original) {
+     Cookie c = new Cookie("original-url", original);
 -    // TODO: get the cookie path from filterConfig
 -    c.setPath("/gateway/idp/knoxsso/websso");
++    c.setPath(cookiePath);
+     c.setMaxAge(60);
+     ((HttpServletResponse)servletResponse).addCookie(c);
+   }
+ 
+ }

http://git-wip-us.apache.org/repos/asf/knox/blob/905135b6/gateway-provider-security-picketlink/src/test/java/org/apache/hadoop/gateway/picketlink/PicketlinkTest.java
----------------------------------------------------------------------
diff --cc gateway-provider-security-picketlink/src/test/java/org/apache/hadoop/gateway/picketlink/PicketlinkTest.java
index 0000000,0000000..4ef3088
new file mode 100644
--- /dev/null
+++ b/gateway-provider-security-picketlink/src/test/java/org/apache/hadoop/gateway/picketlink/PicketlinkTest.java
@@@ -1,0 -1,0 +1,31 @@@
++
++/**
++ * 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.picketlink;
++
++import junit.framework.TestCase;
++
++import org.apache.hadoop.gateway.services.security.token.impl.JWTToken;
++import org.junit.Test;
++
++public class PicketlinkTest extends TestCase {
++  @Test
++  public void testPicketlink() throws Exception {
++    assertTrue(true);
++  }
++}

http://git-wip-us.apache.org/repos/asf/knox/blob/905135b6/gateway-release/pom.xml
----------------------------------------------------------------------
diff --cc gateway-release/pom.xml
index 7f84ca7,9294f23..60e808c
--- a/gateway-release/pom.xml
+++ b/gateway-release/pom.xml
@@@ -176,6 -147,14 +176,10 @@@
          </dependency>
          <dependency>
              <groupId>${gateway-group}</groupId>
+             <artifactId>gateway-service-knoxsso</artifactId>
+         </dependency>
+         <dependency>
+             <groupId>${gateway-group}</groupId>
 -            <artifactId>gateway-service-yarn-rm</artifactId>
 -        </dependency>
 -        <dependency>
 -            <groupId>${gateway-group}</groupId>
              <artifactId>gateway-provider-rewrite</artifactId>
          </dependency>
          <dependency>

http://git-wip-us.apache.org/repos/asf/knox/blob/905135b6/gateway-service-knoxsso/src/main/java/org/apache/hadoop/gateway/service/knoxsso/KnoxSSOMessages.java
----------------------------------------------------------------------
diff --cc gateway-service-knoxsso/src/main/java/org/apache/hadoop/gateway/service/knoxsso/KnoxSSOMessages.java
index 0000000,cb8b137..f277ac2
mode 000000,100644..100644
--- a/gateway-service-knoxsso/src/main/java/org/apache/hadoop/gateway/service/knoxsso/KnoxSSOMessages.java
+++ b/gateway-service-knoxsso/src/main/java/org/apache/hadoop/gateway/service/knoxsso/KnoxSSOMessages.java
@@@ -1,0 -1,37 +1,46 @@@
+ /**
+  * 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.service.knoxsso;
+ 
+ import org.apache.hadoop.gateway.i18n.messages.Message;
+ import org.apache.hadoop.gateway.i18n.messages.MessageLevel;
+ import org.apache.hadoop.gateway.i18n.messages.Messages;
+ 
+ @Messages(logger="org.apache.hadoop.gateway.service.knoxsso")
+ public interface KnoxSSOMessages {
+   @Message( level = MessageLevel.INFO, text = "About to redirect to original URL: {0}")
+   void aboutToRedirectToOriginal(String original);
+ 
+   @Message( level = MessageLevel.DEBUG, text = "Adding the following JWT token as a cookie: {0}")
+   void addingJWTCookie(String token);
+ 
+   @Message( level = MessageLevel.INFO, text = "Unable to find cookie with name: {0}")
+   void cookieNotFound(String name);
+ 
+   @Message( level = MessageLevel.ERROR, text = "Unable to properly send needed HTTP status code: {0}, {1}")
+   void unableToCloseOutputStream(String message, String string);
++
++  @Message( level = MessageLevel.ERROR, text = "Unable to add cookie to response. {0}: {1}")
++  void unableAddCookieToResponse(String message, String stackTrace);
++
++  @Message( level = MessageLevel.ERROR, text = "Original URL not found in request.")
++  void originalURLNotFound();
++
++  @Message( level = MessageLevel.INFO, text = "JWT cookie successfully added.")
++  void addedJWTCookie();
+ }

http://git-wip-us.apache.org/repos/asf/knox/blob/905135b6/gateway-service-knoxsso/src/main/java/org/apache/hadoop/gateway/service/knoxsso/WebSSOResource.java
----------------------------------------------------------------------
diff --cc gateway-service-knoxsso/src/main/java/org/apache/hadoop/gateway/service/knoxsso/WebSSOResource.java
index 0000000,84b74e7..bce09a0
mode 000000,100644..100644
--- a/gateway-service-knoxsso/src/main/java/org/apache/hadoop/gateway/service/knoxsso/WebSSOResource.java
+++ b/gateway-service-knoxsso/src/main/java/org/apache/hadoop/gateway/service/knoxsso/WebSSOResource.java
@@@ -1,0 -1,144 +1,167 @@@
+ /**
+  * 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.service.knoxsso;
+ 
+ import java.io.IOException;
+ import java.net.URI;
+ import java.net.URISyntaxException;
+ import java.security.Principal;
+ import java.util.Date;
+ 
+ import javax.servlet.http.Cookie;
+ import javax.servlet.http.HttpServletRequest;
+ import javax.servlet.http.HttpServletResponse;
+ import javax.ws.rs.GET;
+ import javax.ws.rs.POST;
+ import javax.ws.rs.Path;
+ import javax.ws.rs.Produces;
+ import javax.ws.rs.core.Context;
+ import javax.ws.rs.core.Response;
+ import javax.ws.rs.WebApplicationException;
+ 
+ import org.apache.hadoop.gateway.i18n.messages.MessagesFactory;
+ import org.apache.hadoop.gateway.services.GatewayServices;
+ import org.apache.hadoop.gateway.services.security.token.JWTokenAuthority;
+ import org.apache.hadoop.gateway.services.security.token.impl.JWT;
+ 
+ import static javax.ws.rs.core.MediaType.APPLICATION_JSON;
+ import static javax.ws.rs.core.MediaType.APPLICATION_XML;
+ 
 -@Path( "/knoxsso/websso" )
++@Path( WebSSOResource.RESOURCE_PATH )
+ public class WebSSOResource {
++  /**
++   * 
++   */
++  private static final String ORIGINAL_URL_REQUEST_PARAM = "originalUrl";
++  /**
++   * 
++   */
++  private static final String ORIGINAL_URL_COOKIE_NAME = "original-url";
++  /**
++   * 
++   */
++  private static final String JWT_COOKIE_NAME = "hadoop-jwt";
++  static final String RESOURCE_PATH = "/knoxsso/websso";
+   private static KnoxSSOMessages log = MessagesFactory.get( KnoxSSOMessages.class );
+ 
+   @Context 
+   private HttpServletRequest request;
+ 
+   @Context 
+   private HttpServletResponse response;
+ 
+   @GET
+   @Produces({APPLICATION_JSON, APPLICATION_XML})
+   public Response doGet() {
+     return getAuthenticationToken(HttpServletResponse.SC_TEMPORARY_REDIRECT);
+   }
+ 
+   @POST
+   @Produces({APPLICATION_JSON, APPLICATION_XML})
+   public Response doPost() {
+     return getAuthenticationToken(HttpServletResponse.SC_SEE_OTHER);
+   }
+ 
+   private Response getAuthenticationToken(int statusCode) {
+     GatewayServices services = (GatewayServices) request.getServletContext()
+         .getAttribute(GatewayServices.GATEWAY_SERVICES_ATTRIBUTE);
+     boolean removeOriginalUrlCookie = true;
 -    String original = getCookieValue((HttpServletRequest) request, "original-url");
++    String original = getCookieValue((HttpServletRequest) request, ORIGINAL_URL_COOKIE_NAME);
+     if (original == null) {
+       // in the case where there is no SAML redirects done before here
+       // we need to get it from the request parameters
+       removeOriginalUrlCookie = false;
 -      original = request.getParameter("originalUrl");
++      original = request.getParameter(ORIGINAL_URL_REQUEST_PARAM);
++      if (original == null) {
++        log.originalURLNotFound();
++        throw new WebApplicationException("Original URL not found in the request.", Response.Status.BAD_REQUEST);
++      }
+     }
+     
+     JWTokenAuthority ts = services.getService(GatewayServices.TOKEN_SERVICE);
+     Principal p = ((HttpServletRequest)request).getUserPrincipal();
+ 
+     JWT token = ts.issueToken(p, "RS256");
+     
+     addJWTHadoopCookie(original, token);
+     
+     if (removeOriginalUrlCookie) {
+       removeOriginalUrlCookie(response);
+     }
+     
+     log.aboutToRedirectToOriginal(original);
+     response.setStatus(statusCode);
+     response.setHeader("Location", original);
+     try {
+       response.getOutputStream().close();
+     } catch (IOException e) {
+       log.unableToCloseOutputStream(e.getMessage(), e.getStackTrace().toString());
+     }
+     return null;
+   }
+ 
+   public void addJWTHadoopCookie(String original, JWT token) {
+     log.addingJWTCookie(token.toString());
 -    Cookie c = new Cookie("hadoop-jwt",  token.toString());
++    Cookie c = new Cookie(JWT_COOKIE_NAME,  token.toString());
+     c.setPath("/");
+     try {
+       String domain = getDomainName(original);
+       c.setDomain(domain);
+       c.setHttpOnly(true);
+       c.setSecure(true);
+       c.setMaxAge(120);
+       response.addCookie(c);
++      log.addedJWTCookie();
+     }
+     catch(Exception e) {
++      log.unableAddCookieToResponse(e.getMessage(), e.getStackTrace().toString());
+       throw new WebApplicationException("Unable to add JWT cookie to response.");
+     }
+   }
+ 
+   private void removeOriginalUrlCookie(HttpServletResponse response) {
 -    Cookie c = new Cookie("original-url", null);
++    Cookie c = new Cookie(ORIGINAL_URL_COOKIE_NAME, null);
+     c.setMaxAge(0);
 -    c.setPath("/knoxsso/websso");
++    c.setPath(RESOURCE_PATH);
+     response.addCookie(c);
+   }
+ 
+   public String getDomainName(String url) throws URISyntaxException {
 -      URI uri = new URI(url);
 -      String domain = uri.getHost();
 -      return domain.startsWith("www.") ? domain.substring(4) : domain.substring(domain.indexOf('.'));
++    URI uri = new URI(url);
++    String domain = uri.getHost();
++    int idx = domain.indexOf('.');
++    if (idx == -1) {
++      idx = 0;
++    }
++    return domain.startsWith("www.") ? domain.substring(4) : domain.substring(idx);
+   }
+ 
+   private String getCookieValue(HttpServletRequest request, String name) {
+     Cookie[] cookies = request.getCookies();
+     String value = null;
+     for(Cookie cookie : cookies){
+       if(name.equals(cookie.getName())){
+           value = cookie.getValue();
+       }
+     }
+     if (value == null) {
+       log.cookieNotFound(name);
+     }
+     return value;
+   }
+ }

http://git-wip-us.apache.org/repos/asf/knox/blob/905135b6/gateway-spi/pom.xml
----------------------------------------------------------------------
diff --cc gateway-spi/pom.xml
index 11ddda7,0fb2b28..5edb2f7
--- a/gateway-spi/pom.xml
+++ b/gateway-spi/pom.xml
@@@ -79,7 -75,12 +79,18 @@@
              <groupId>org.jboss.shrinkwrap.descriptors</groupId>
              <artifactId>shrinkwrap-descriptors-impl-javaee</artifactId>
          </dependency>
 -	      <dependency>
 -	          <groupId>com.nimbusds</groupId>
 -	          <artifactId>nimbus-jose-jwt</artifactId>
 -	          <version>3.9</version>
 -	      </dependency>
 +        <dependency>
++          <groupId>com.nimbusds</groupId>
++          <artifactId>nimbus-jose-jwt</artifactId>
++          <scope>compile</scope>
++          <exclusions>
++            <exclusion>
++              <groupId>org.bouncycastle</groupId>
++              <artifactId>bcprov-jdk15on</artifactId>
++            </exclusion>
++          </exclusions>
++        </dependency>
+         <dependency>
              <groupId>commons-net</groupId>
              <artifactId>commons-net</artifactId>
          </dependency>

http://git-wip-us.apache.org/repos/asf/knox/blob/905135b6/pom.xml
----------------------------------------------------------------------
diff --cc pom.xml
index 9c283b0,e23f699..e412a81
--- a/pom.xml
+++ b/pom.xml
@@@ -58,8 -57,7 +58,9 @@@
          <module>gateway-provider-security-hadoopauth</module>
          <module>gateway-provider-security-shiro</module>
          <module>gateway-provider-security-authz-acls</module>
 +        <module>gateway-provider-identity-assertion-common</module>
 +        <module>gateway-provider-identity-assertion-concat</module>
+         <module>gateway-provider-security-picketlink</module>
          <module>gateway-provider-identity-assertion-pseudo</module>
          <module>gateway-provider-jersey</module>
          <module>gateway-provider-ha</module>
@@@ -67,10 -65,12 +68,11 @@@
          <module>gateway-service-as</module>
          <module>gateway-service-hbase</module>
          <module>gateway-service-hive</module>
+         <module>gateway-service-knoxsso</module>
          <module>gateway-service-webhdfs</module>
 -        <module>gateway-service-oozie</module>
 -        <module>gateway-service-webhcat</module>
          <module>gateway-service-tgs</module>
 -        <module>gateway-service-yarn-rm</module>
 +        <module>gateway-service-storm</module>
 +        <module>gateway-service-definitions</module>
          <module>gateway-shell</module>
          <module>gateway-shell-launcher</module>
          <module>knox-cli-launcher</module>
@@@ -552,6 -552,17 +564,16 @@@
                  <version>${gateway-version}</version>
              </dependency>
  
+         <dependency>
+             <groupId>org.picketlink</groupId>
+             <artifactId>picketlink-federation</artifactId>
+             <version>2.7.0.CR3</version>
+         </dependency>
+         <dependency>
+             <groupId>org.jboss.logging</groupId>
+             <artifactId>jboss-logging</artifactId>
+             <version>3.2.0.Final</version>
+         </dependency>
 -        
              <dependency>
                  <groupId>org.glassfish.jersey.containers</groupId>
                  <artifactId>jersey-container-servlet</artifactId>
@@@ -562,7 -573,7 +584,18 @@@
                  <artifactId>jersey-server</artifactId>
                  <version>2.6</version>
              </dependency>
--
++            <dependency>
++              <groupId>com.nimbusds</groupId>
++              <artifactId>nimbus-jose-jwt</artifactId>
++              <version>3.9</version>
++              <scope>compile</scope>
++              <exclusions>
++                <exclusion>
++                  <groupId>org.bouncycastle</groupId>
++                  <artifactId>bcprov-jdk15on</artifactId>
++                </exclusion>
++              </exclusions>
++            </dependency>
              <dependency>
                  <groupId>org.eclipse.jetty</groupId>
                  <artifactId>jetty-server</artifactId>