Repository: knox Updated Branches: refs/heads/master 53e84a25a -> c5061b843
KNOX-1550 - TLS/SSL client certificate authentication provider Signed-off-by: Kevin Risden <[email protected]> Project: http://git-wip-us.apache.org/repos/asf/knox/repo Commit: http://git-wip-us.apache.org/repos/asf/knox/commit/c5061b84 Tree: http://git-wip-us.apache.org/repos/asf/knox/tree/c5061b84 Diff: http://git-wip-us.apache.org/repos/asf/knox/diff/c5061b84 Branch: refs/heads/master Commit: c5061b843d29bfab5704a2b17915f657d2361292 Parents: 53e84a2 Author: Kevin Risden <[email protected]> Authored: Thu Nov 1 17:53:24 2018 -0400 Committer: Kevin Risden <[email protected]> Committed: Tue Nov 13 11:07:45 2018 -0500 ---------------------------------------------------------------------- gateway-provider-security-clientcert/pom.xml | 69 +++++++++++ .../deploy/ClientCertDeploymentContributor.java | 64 +++++++++++ .../clientcert/filter/ClientCertFilter.java | 115 +++++++++++++++++++ ...gateway.deploy.ProviderDeploymentContributor | 19 +++ .../ClientCertDeploymentContributorTest.java | 81 +++++++++++++ gateway-release/pom.xml | 4 + pom.xml | 6 + 7 files changed, 358 insertions(+) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/knox/blob/c5061b84/gateway-provider-security-clientcert/pom.xml ---------------------------------------------------------------------- diff --git a/gateway-provider-security-clientcert/pom.xml b/gateway-provider-security-clientcert/pom.xml new file mode 100755 index 0000000..d55e23b --- /dev/null +++ b/gateway-provider-security-clientcert/pom.xml @@ -0,0 +1,69 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + 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.knox</groupId> + <artifactId>gateway</artifactId> + <version>1.3.0-SNAPSHOT</version> + </parent> + + <artifactId>gateway-provider-security-clientcert</artifactId> + <name>gateway-provider-security-clientcert</name> + <description>An extension of the gateway for handling client certificate authentication</description> + + <dependencies> + <dependency> + <groupId>org.apache.knox</groupId> + <artifactId>gateway-spi</artifactId> + </dependency> + <dependency> + <groupId>org.apache.knox</groupId> + <artifactId>gateway-util-common</artifactId> + </dependency> + + <dependency> + <groupId>javax.servlet</groupId> + <artifactId>javax.servlet-api</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.hamcrest</groupId> + <artifactId>hamcrest-core</artifactId> + <scope>test</scope> + </dependency> + + <dependency> + <groupId>org.jboss.shrinkwrap</groupId> + <artifactId>shrinkwrap-api</artifactId> + <scope>test</scope> + </dependency> + </dependencies> +</project> http://git-wip-us.apache.org/repos/asf/knox/blob/c5061b84/gateway-provider-security-clientcert/src/main/java/org/apache/knox/gateway/clientcert/deploy/ClientCertDeploymentContributor.java ---------------------------------------------------------------------- diff --git a/gateway-provider-security-clientcert/src/main/java/org/apache/knox/gateway/clientcert/deploy/ClientCertDeploymentContributor.java b/gateway-provider-security-clientcert/src/main/java/org/apache/knox/gateway/clientcert/deploy/ClientCertDeploymentContributor.java new file mode 100755 index 0000000..c37fe86 --- /dev/null +++ b/gateway-provider-security-clientcert/src/main/java/org/apache/knox/gateway/clientcert/deploy/ClientCertDeploymentContributor.java @@ -0,0 +1,64 @@ +/* + * 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.knox.gateway.clientcert.deploy; + +import org.apache.knox.gateway.deploy.DeploymentContext; +import org.apache.knox.gateway.deploy.ProviderDeploymentContributorBase; +import org.apache.knox.gateway.descriptor.FilterParamDescriptor; +import org.apache.knox.gateway.descriptor.ResourceDescriptor; +import org.apache.knox.gateway.clientcert.filter.ClientCertFilter; +import org.apache.knox.gateway.topology.Provider; +import org.apache.knox.gateway.topology.Service; + +import java.util.ArrayList; +import java.util.List; +import java.util.Locale; +import java.util.Map; +import java.util.Map.Entry; + +public class ClientCertDeploymentContributor extends ProviderDeploymentContributorBase { + private static final String CLIENTAUTH_FILTER_CLASSNAME = ClientCertFilter.class.getCanonicalName(); + + public static final String ROLE = "authentication"; + public static final String NAME = "ClientCert"; + + @Override + public String getRole() { + return ROLE; + } + + @Override + public String getName() { + return NAME; + } + + @Override + public void contributeFilter(DeploymentContext context, Provider provider, Service service, + ResourceDescriptor resource, List<FilterParamDescriptor> params) { + // blindly add all the provider params as filter init params + if (params == null) { + params = new ArrayList<>(); + } + Map<String, String> providerParams = provider.getParams(); + for(Entry<String, String> entry : providerParams.entrySet()) { + params.add( resource.createFilterParam().name( entry.getKey().toLowerCase(Locale.ROOT) ).value( entry.getValue() ) ); + } + + resource.addFilter().name( getName() ).role( getRole() ).impl(CLIENTAUTH_FILTER_CLASSNAME).params( params ); + } +} http://git-wip-us.apache.org/repos/asf/knox/blob/c5061b84/gateway-provider-security-clientcert/src/main/java/org/apache/knox/gateway/clientcert/filter/ClientCertFilter.java ---------------------------------------------------------------------- diff --git a/gateway-provider-security-clientcert/src/main/java/org/apache/knox/gateway/clientcert/filter/ClientCertFilter.java b/gateway-provider-security-clientcert/src/main/java/org/apache/knox/gateway/clientcert/filter/ClientCertFilter.java new file mode 100755 index 0000000..a7f967a --- /dev/null +++ b/gateway-provider-security-clientcert/src/main/java/org/apache/knox/gateway/clientcert/filter/ClientCertFilter.java @@ -0,0 +1,115 @@ +/* + * 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.knox.gateway.clientcert.filter; + +import org.apache.knox.gateway.audit.api.Action; +import org.apache.knox.gateway.audit.api.ActionOutcome; +import org.apache.knox.gateway.audit.api.AuditService; +import org.apache.knox.gateway.audit.api.AuditServiceFactory; +import org.apache.knox.gateway.audit.api.Auditor; +import org.apache.knox.gateway.audit.api.ResourceType; +import org.apache.knox.gateway.audit.log4j.audit.AuditConstants; +import org.apache.knox.gateway.filter.AbstractGatewayFilter; +import org.apache.knox.gateway.security.PrimaryPrincipal; + +import java.io.IOException; +import java.security.PrivilegedActionException; +import java.security.PrivilegedExceptionAction; +import java.security.cert.X509Certificate; + +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; + +public class ClientCertFilter implements Filter { + private static AuditService auditService = AuditServiceFactory.getAuditService(); + private static Auditor auditor = auditService.getAuditor( + AuditConstants.DEFAULT_AUDITOR_NAME, AuditConstants.KNOX_SERVICE_NAME, + AuditConstants.KNOX_COMPONENT_NAME ); + + @Override + public void init(FilterConfig filterConfig) { + + } + + @Override + public void doFilter(ServletRequest request, ServletResponse response, FilterChain filterChain) throws IOException, ServletException { + HttpServletRequest httpRequest = (HttpServletRequest)request; + X509Certificate cert = extractCertificate(httpRequest); + if (cert != null) { + String principal = cert.getSubjectDN().getName(); + + Subject subject = new Subject(); + subject.getPrincipals().add(new PrimaryPrincipal(principal)); + auditService.getContext().setUsername(principal); + String sourceUri = (String) request.getAttribute(AbstractGatewayFilter.SOURCE_REQUEST_CONTEXT_URL_ATTRIBUTE_NAME); + auditor.audit(Action.AUTHENTICATION, sourceUri, ResourceType.URI, ActionOutcome.SUCCESS); + continueWithEstablishedSecurityContext(subject, httpRequest, (HttpServletResponse) response, filterChain); + } else { + ((HttpServletResponse)response).sendError(HttpServletResponse.SC_FORBIDDEN, "User not authenticated"); + } + } + + private X509Certificate extractCertificate(HttpServletRequest req) { + X509Certificate[] certs = (X509Certificate[]) req.getAttribute("javax.servlet.request.X509Certificate"); + if (null != certs && certs.length > 0) { + return certs[0]; + } + return null; + } + + 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); + } + } + } + + @Override + public void destroy() { + + } +} http://git-wip-us.apache.org/repos/asf/knox/blob/c5061b84/gateway-provider-security-clientcert/src/main/resources/META-INF/services/org.apache.knox.gateway.deploy.ProviderDeploymentContributor ---------------------------------------------------------------------- diff --git a/gateway-provider-security-clientcert/src/main/resources/META-INF/services/org.apache.knox.gateway.deploy.ProviderDeploymentContributor b/gateway-provider-security-clientcert/src/main/resources/META-INF/services/org.apache.knox.gateway.deploy.ProviderDeploymentContributor new file mode 100755 index 0000000..547b345 --- /dev/null +++ b/gateway-provider-security-clientcert/src/main/resources/META-INF/services/org.apache.knox.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.knox.gateway.clientcert.deploy.ClientCertDeploymentContributor http://git-wip-us.apache.org/repos/asf/knox/blob/c5061b84/gateway-provider-security-clientcert/src/test/java/org/apache/knox/gateway/clientcert/ClientCertDeploymentContributorTest.java ---------------------------------------------------------------------- diff --git a/gateway-provider-security-clientcert/src/test/java/org/apache/knox/gateway/clientcert/ClientCertDeploymentContributorTest.java b/gateway-provider-security-clientcert/src/test/java/org/apache/knox/gateway/clientcert/ClientCertDeploymentContributorTest.java new file mode 100644 index 0000000..bdae540 --- /dev/null +++ b/gateway-provider-security-clientcert/src/test/java/org/apache/knox/gateway/clientcert/ClientCertDeploymentContributorTest.java @@ -0,0 +1,81 @@ +/* + * 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.knox.gateway.clientcert; + +import org.apache.knox.gateway.deploy.DeploymentContext; +import org.apache.knox.gateway.deploy.ProviderDeploymentContributor; +import org.apache.knox.gateway.clientcert.deploy.ClientCertDeploymentContributor; +import org.apache.knox.gateway.topology.Provider; +import org.apache.knox.gateway.topology.Topology; +import org.easymock.EasyMock; +import org.jboss.shrinkwrap.api.ShrinkWrap; +import org.jboss.shrinkwrap.api.spec.WebArchive; +import org.junit.Test; + +import java.util.Iterator; +import java.util.ServiceLoader; + +import static org.hamcrest.CoreMatchers.is; +import static org.hamcrest.MatcherAssert.assertThat; +import static org.junit.Assert.fail; + +public class ClientCertDeploymentContributorTest { + + @SuppressWarnings("rawtypes") + @Test + public void testServiceLoader() { + ServiceLoader loader = ServiceLoader.load( ProviderDeploymentContributor.class ); + Iterator iterator = loader.iterator(); + assertThat( "Service iterator empty.", iterator.hasNext() ); + while( iterator.hasNext() ) { + Object object = iterator.next(); + if( object instanceof ClientCertDeploymentContributor) { + return; + } + } + fail( "Failed to find " + ClientCertDeploymentContributor.class.getName() + " via service loader." ); + } + + @Test + public void testDeployment() { + WebArchive webArchive = ShrinkWrap.create( WebArchive.class, "test-archive" ); + + Provider provider = new Provider(); + provider.setEnabled( true ); + provider.setName( ClientCertDeploymentContributor.NAME ); + + Topology topology = new Topology(); + topology.setName( "Sample" ); + + DeploymentContext context = EasyMock.createNiceMock( DeploymentContext.class ); + EasyMock.expect( context.getWebArchive() ).andReturn( webArchive ).anyTimes(); + EasyMock.expect( context.getTopology() ).andReturn( topology ).anyTimes(); + EasyMock.replay( context ); + + ClientCertDeploymentContributor contributor = new ClientCertDeploymentContributor(); + + assertThat( contributor.getRole(), is( ClientCertDeploymentContributor.ROLE ) ); + assertThat( contributor.getName(), is( ClientCertDeploymentContributor.NAME ) ); + + // Just make sure it doesn't blow up. + contributor.initializeContribution( context ); + + // Just make sure it doesn't blow up. + contributor.finalizeContribution( context ); + } +} http://git-wip-us.apache.org/repos/asf/knox/blob/c5061b84/gateway-release/pom.xml ---------------------------------------------------------------------- diff --git a/gateway-release/pom.xml b/gateway-release/pom.xml index 691f058..ebbfcd4 100644 --- a/gateway-release/pom.xml +++ b/gateway-release/pom.xml @@ -251,6 +251,10 @@ </dependency> <dependency> <groupId>org.apache.knox</groupId> + <artifactId>gateway-provider-security-clientcert</artifactId> + </dependency> + <dependency> + <groupId>org.apache.knox</groupId> <artifactId>gateway-provider-security-preauth</artifactId> </dependency> <dependency> http://git-wip-us.apache.org/repos/asf/knox/blob/c5061b84/pom.xml ---------------------------------------------------------------------- diff --git a/pom.xml b/pom.xml index 2ac1f3d..d900d85 100644 --- a/pom.xml +++ b/pom.xml @@ -84,6 +84,7 @@ <module>gateway-provider-security-webappsec</module> <module>gateway-provider-security-preauth</module> <module>gateway-provider-security-hadoopauth</module> + <module>gateway-provider-security-clientcert</module> <module>gateway-provider-security-shiro</module> <module>gateway-provider-security-pac4j</module> <module>gateway-provider-security-authz-acls</module> @@ -652,6 +653,11 @@ </dependency> <dependency> <groupId>org.apache.knox</groupId> + <artifactId>gateway-provider-security-clientcert</artifactId> + <version>${project.version}</version> + </dependency> + <dependency> + <groupId>org.apache.knox</groupId> <artifactId>gateway-provider-security-preauth</artifactId> <version>${project.version}</version> </dependency>
