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/04/16 20:00:04 UTC
git commit: Another iteration of work toward KNOX-37 - POC work for
demonstrating an access token issuance and acceptance for SSO.
Updated Branches:
refs/heads/master ae2d31c7a -> d205789ab
Another iteration of work toward KNOX-37 - POC work for demonstrating an access token issuance and acceptance for SSO.
Project: http://git-wip-us.apache.org/repos/asf/incubator-knox/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-knox/commit/d205789a
Tree: http://git-wip-us.apache.org/repos/asf/incubator-knox/tree/d205789a
Diff: http://git-wip-us.apache.org/repos/asf/incubator-knox/diff/d205789a
Branch: refs/heads/master
Commit: d205789ab938db23a5c9fe806bd261d2a7dd8acc
Parents: ae2d31c
Author: Larry McCay <lm...@hortonworks.com>
Authored: Tue Apr 16 13:59:18 2013 -0400
Committer: Larry McCay <lm...@hortonworks.com>
Committed: Tue Apr 16 13:59:18 2013 -0400
----------------------------------------------------------------------
.../provider/federation/jwt/JWTAuthority.java | 5 +-
.../deploy/AccessTokenFederationContributor.java | 51 ++++++
.../jwt/filter/AccessTokenFederationFilter.java | 136 +++++++++++++++
.../jwt/filter/JWTAuthCodeAssertionFilter.java | 47 +++++
...op.gateway.deploy.ProviderDeploymentContributor | 4 +-
gateway-release/home/deployments/sample.xml | 6 +
gateway-release/home/templates/topology.xml | 6 +
.../security/impl/DefaultCryptoService.java | 4 +-
.../security/impl/DefaultKeystoreService.java | 4 +-
.../gateway/services/security/KeystoreService.java | 2 +-
10 files changed, 258 insertions(+), 7 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/incubator-knox/blob/d205789a/gateway-provider-security-jwt/src/main/java/org/apache/hadoop/gateway/provider/federation/jwt/JWTAuthority.java
----------------------------------------------------------------------
diff --git a/gateway-provider-security-jwt/src/main/java/org/apache/hadoop/gateway/provider/federation/jwt/JWTAuthority.java b/gateway-provider-security-jwt/src/main/java/org/apache/hadoop/gateway/provider/federation/jwt/JWTAuthority.java
index 9c34773..34c3713 100644
--- a/gateway-provider-security-jwt/src/main/java/org/apache/hadoop/gateway/provider/federation/jwt/JWTAuthority.java
+++ b/gateway-provider-security-jwt/src/main/java/org/apache/hadoop/gateway/provider/federation/jwt/JWTAuthority.java
@@ -21,6 +21,7 @@ import java.security.Principal;
import javax.security.auth.Subject;
+import org.apache.hadoop.gateway.services.security.AliasService;
import org.apache.hadoop.gateway.services.security.CryptoService;
public class JWTAuthority {
@@ -30,7 +31,7 @@ public class JWTAuthority {
this.crypto = crypto;
}
- public JWTToken issueToken(Subject subject, String algorithm, byte[] secret) {
+ public JWTToken issueToken(Subject subject, String algorithm) {
Principal p = (Principal) subject.getPrincipals().toArray()[0];
String[] claimArray = new String[4];
claimArray[0] = "gateway";
@@ -42,7 +43,7 @@ public class JWTAuthority {
JWTToken token = null;
if ("RS256".equals(algorithm)) {
- new JWTToken("RS256", claimArray);
+ token = new JWTToken("RS256", claimArray);
signToken(token);
}
else {
http://git-wip-us.apache.org/repos/asf/incubator-knox/blob/d205789a/gateway-provider-security-jwt/src/main/java/org/apache/hadoop/gateway/provider/federation/jwt/deploy/AccessTokenFederationContributor.java
----------------------------------------------------------------------
diff --git a/gateway-provider-security-jwt/src/main/java/org/apache/hadoop/gateway/provider/federation/jwt/deploy/AccessTokenFederationContributor.java b/gateway-provider-security-jwt/src/main/java/org/apache/hadoop/gateway/provider/federation/jwt/deploy/AccessTokenFederationContributor.java
new file mode 100644
index 0000000..2245336
--- /dev/null
+++ b/gateway-provider-security-jwt/src/main/java/org/apache/hadoop/gateway/provider/federation/jwt/deploy/AccessTokenFederationContributor.java
@@ -0,0 +1,51 @@
+/**
+ * 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 java.util.List;
+
+public class AccessTokenFederationContributor extends ProviderDeploymentContributorBase {
+
+ private static final String FILTER_CLASSNAME = "org.apache.hadoop.gateway.provider.federation.jwt.filter.AccessTokenFederationFilter";
+
+ @Override
+ public String getRole() {
+ return "federation";
+ }
+
+ @Override
+ public String getName() {
+ return "AccessTokenProvider";
+ }
+
+ @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/d205789a/gateway-provider-security-jwt/src/main/java/org/apache/hadoop/gateway/provider/federation/jwt/filter/AccessTokenFederationFilter.java
----------------------------------------------------------------------
diff --git a/gateway-provider-security-jwt/src/main/java/org/apache/hadoop/gateway/provider/federation/jwt/filter/AccessTokenFederationFilter.java b/gateway-provider-security-jwt/src/main/java/org/apache/hadoop/gateway/provider/federation/jwt/filter/AccessTokenFederationFilter.java
new file mode 100644
index 0000000..179d2ee
--- /dev/null
+++ b/gateway-provider-security-jwt/src/main/java/org/apache/hadoop/gateway/provider/federation/jwt/filter/AccessTokenFederationFilter.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.federation.jwt.filter;
+
+import java.io.IOException;
+import java.security.Principal;
+import java.security.PrivilegedActionException;
+import java.security.PrivilegedExceptionAction;
+import java.util.HashSet;
+import java.util.Set;
+
+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.provider.federation.jwt.AccessToken;
+import org.apache.hadoop.gateway.services.GatewayServices;
+import org.apache.hadoop.gateway.services.security.CryptoService;
+
+public class AccessTokenFederationFilter implements Filter {
+ private static final String BEARER = "Bearer ";
+
+ private CryptoService crypto = null;
+
+ @Override
+ public void init( FilterConfig filterConfig ) throws ServletException {
+ GatewayServices services = (GatewayServices) filterConfig.getServletContext().getAttribute(GatewayServices.GATEWAY_SERVICES_ATTRIBUTE);
+ crypto = (CryptoService) services.getService(GatewayServices.CRYPTO_SERVICE);
+ }
+
+ 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());
+ AccessToken token = AccessToken.parseToken(crypto, wireToken);
+// LJM TODO: replace with actual verification - should we do it in the authority? Probably.
+// boolean verified = authority.verifyAccessToken(token);
+ boolean verified = true;
+ if (verified) {
+ // TODO: validate expiration
+ // TODO: confirm that audience matches intended target
+ // TODO: verify that the user requesting access to the service/resource is authorized for it - need scopes?
+ 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(AccessToken token) {
+ final String principal = token.getPrincipalName();
+
+ 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/d205789a/gateway-provider-security-jwt/src/main/java/org/apache/hadoop/gateway/provider/federation/jwt/filter/JWTAuthCodeAssertionFilter.java
----------------------------------------------------------------------
diff --git a/gateway-provider-security-jwt/src/main/java/org/apache/hadoop/gateway/provider/federation/jwt/filter/JWTAuthCodeAssertionFilter.java b/gateway-provider-security-jwt/src/main/java/org/apache/hadoop/gateway/provider/federation/jwt/filter/JWTAuthCodeAssertionFilter.java
index 7dfacb5..072c308 100644
--- a/gateway-provider-security-jwt/src/main/java/org/apache/hadoop/gateway/provider/federation/jwt/filter/JWTAuthCodeAssertionFilter.java
+++ b/gateway-provider-security-jwt/src/main/java/org/apache/hadoop/gateway/provider/federation/jwt/filter/JWTAuthCodeAssertionFilter.java
@@ -18,18 +18,65 @@
package org.apache.hadoop.gateway.provider.federation.jwt.filter;
import java.io.IOException;
+import java.security.AccessController;
+import java.util.HashMap;
+import javax.security.auth.Subject;
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.filter.security.AbstractIdentityAssertionFilter;
+import org.apache.hadoop.gateway.provider.federation.jwt.JWTAuthority;
+import org.apache.hadoop.gateway.provider.federation.jwt.JWTToken;
+import org.apache.hadoop.gateway.services.GatewayServices;
+import org.apache.hadoop.gateway.services.security.CryptoService;
+import org.apache.hadoop.gateway.util.JsonUtils;
public class JWTAuthCodeAssertionFilter extends AbstractIdentityAssertionFilter {
+ private static final String BEARER = "Bearer ";
+
+ private CryptoService crypto = null;
@Override
+ public void init( FilterConfig filterConfig ) throws ServletException {
+ super.init(filterConfig);
+ String validityStr = filterConfig.getInitParameter("validity");
+ if (validityStr == null) {
+ validityStr = "3600"; // 1 hr. in secs
+ }
+// validity = Long.parseLong(validityStr);
+
+ GatewayServices services = (GatewayServices) filterConfig.getServletContext().getAttribute(GatewayServices.GATEWAY_SERVICES_ATTRIBUTE);
+ crypto = (CryptoService) services.getService(GatewayServices.CRYPTO_SERVICE);
+ }
+
+ @Override
public void doFilter(ServletRequest request, ServletResponse response,
FilterChain chain) throws IOException, ServletException {
+
+ Subject subject = Subject.getSubject(AccessController.getContext());
+ String principalName = getPrincipalName(subject);
+ principalName = mapper.mapPrincipal(principalName);
+ JWTAuthority authority = new JWTAuthority(crypto);
+ JWTToken authCode = authority.issueToken(subject, "RS256");
+
+ HashMap<String, Object> map = new HashMap<String, Object>();
+ // TODO: populate map from JWT authorization code
+ map.put("iss", authCode.getIssuer());
+ map.put("sub", authCode.getPrincipal());
+ map.put("aud", authCode.getAudience());
+ map.put("exp", authCode.getExpires());
+ map.put("code", authCode.toString());
+
+ String jsonResponse = JsonUtils.renderAsJsonString(map);
+
+ response.getWriter().write(jsonResponse);
+ response.getWriter().flush();
+ return; // break filter chain
}
}
http://git-wip-us.apache.org/repos/asf/incubator-knox/blob/d205789a/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
index 5915713..2300504 100644
--- 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
@@ -17,4 +17,6 @@
##########################################################################
org.apache.hadoop.gateway.provider.federation.jwt.deploy.JWTFederationContributor
-org.apache.hadoop.gateway.provider.federation.jwt.deploy.JWTAccessTokenAssertionContributor
\ No newline at end of file
+org.apache.hadoop.gateway.provider.federation.jwt.deploy.JWTAccessTokenAssertionContributor
+org.apache.hadoop.gateway.provider.federation.jwt.deploy.JWTAuthCodeAssertionContributor
+org.apache.hadoop.gateway.provider.federation.jwt.deploy.AccessTokenFederationContributor
http://git-wip-us.apache.org/repos/asf/incubator-knox/blob/d205789a/gateway-release/home/deployments/sample.xml
----------------------------------------------------------------------
diff --git a/gateway-release/home/deployments/sample.xml b/gateway-release/home/deployments/sample.xml
index 616c57e..d1d3b2b 100644
--- a/gateway-release/home/deployments/sample.xml
+++ b/gateway-release/home/deployments/sample.xml
@@ -21,6 +21,7 @@
<provider>
<role>authentication</role>
<enabled>true</enabled>
+ <name>ShiroProvider</name>
<param>
<name>main.ldapRealm</name>
<value>org.apache.shiro.realm.ldap.JndiLdapRealm</value>
@@ -42,6 +43,11 @@
<value>authcBasic</value>
</param>
</provider>
+ <provider>
+ <role>identity-assertion</role>
+ <enabled>true</enabled>
+ <name>Pseudo</name>
+ </provider>
</gateway>
<service>
http://git-wip-us.apache.org/repos/asf/incubator-knox/blob/d205789a/gateway-release/home/templates/topology.xml
----------------------------------------------------------------------
diff --git a/gateway-release/home/templates/topology.xml b/gateway-release/home/templates/topology.xml
index 4c2dd69..1ef62a9 100644
--- a/gateway-release/home/templates/topology.xml
+++ b/gateway-release/home/templates/topology.xml
@@ -21,6 +21,7 @@
<provider>
<role>authentication</role>
<enabled>true</enabled>
+ <name>ShiroProvider</name>
<param>
<name>main.ldapRealm</name>
<value>org.apache.shiro.realm.ldap.JndiLdapRealm</value>
@@ -42,6 +43,11 @@
<value>authcBasic</value>
</param>
</provider>
+ <provider>
+ <role>identity-assertion</role>
+ <enabled>true</enabled>
+ <name>Pseudo</name>
+ </provider>
</gateway>
<service>
http://git-wip-us.apache.org/repos/asf/incubator-knox/blob/d205789a/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 c942271..7d1e1f9 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
@@ -37,6 +37,7 @@ import org.apache.hadoop.gateway.services.security.KeystoreServiceException;
import org.apache.hadoop.gateway.services.ServiceLifecycleException;
public class DefaultCryptoService implements CryptoService {
+ private static final String GATEWAY_IDENTITY_PASSPHRASE = "gateway-identity-passphrase";
private AliasService as = null;
private KeystoreService ks = null;
@@ -154,7 +155,8 @@ public class DefaultCryptoService implements CryptoService {
@Override
public byte[] sign(String algorithm, String alias, String payloadToSign) {
try {
- PrivateKey privateKey = (PrivateKey) ks.getKeyForGateway(alias);
+ char[] passphrase = as.getPasswordFromAliasForGateway(GATEWAY_IDENTITY_PASSPHRASE);
+ PrivateKey privateKey = (PrivateKey) ks.getKeyForGateway(alias, passphrase);
Signature signature = Signature.getInstance(algorithm);
signature.initSign(privateKey);
signature.update(payloadToSign.getBytes("UTF-8"));
http://git-wip-us.apache.org/repos/asf/incubator-knox/blob/d205789a/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 88458ba..6670fb5 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
@@ -259,12 +259,12 @@ public class DefaultKeystoreService implements KeystoreService {
}
@Override
- public Key getKeyForGateway(String alias) throws KeystoreServiceException {
+ public Key getKeyForGateway(String alias, char[] passphrase) throws KeystoreServiceException {
Key key = null;
KeyStore ks = getKeystoreForGateway();
if (ks != null) {
try {
- key = ks.getKey(alias, masterService.getMasterSecret());
+ key = ks.getKey(alias, passphrase);
} catch (UnrecoverableKeyException e) {
// TODO Auto-generated catch block
e.printStackTrace();
http://git-wip-us.apache.org/repos/asf/incubator-knox/blob/d205789a/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 65c8a2a..848a522 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
@@ -35,7 +35,7 @@ public interface KeystoreService extends Service {
public KeyStore getKeystoreForGateway();
- public Key getKeyForGateway(String alias) throws KeystoreServiceException;
+ public Key getKeyForGateway(String alias, char[] passphrase) throws KeystoreServiceException;
public void createCredentialStoreForCluster(String clusterName);