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>