Repository: knox Updated Branches: refs/heads/KNOX-1204 [created] 27d381dcc
KNOX-1204 - KIP-11 - S3 Access through Knox API Project: http://git-wip-us.apache.org/repos/asf/knox/repo Commit: http://git-wip-us.apache.org/repos/asf/knox/commit/43567b0a Tree: http://git-wip-us.apache.org/repos/asf/knox/tree/43567b0a Diff: http://git-wip-us.apache.org/repos/asf/knox/diff/43567b0a Branch: refs/heads/KNOX-1204 Commit: 43567b0a094f149d244f68109d76d90a36f8924a Parents: c7f2855 Author: Larry McCay <[email protected]> Authored: Sat Mar 10 17:39:35 2018 -0500 Committer: Larry McCay <[email protected]> Committed: Fri Mar 30 11:06:09 2018 -0400 ---------------------------------------------------------------------- gateway-release/pom.xml | 4 + gateway-service-knoxs3/pom.xml | 76 +++++++ .../service/knoxs3/KnoxS3ServiceMessages.java | 32 +++ .../service/knoxs3/S3BucketsResource.java | 199 +++++++++++++++++ .../KnoxS3ServiceDeploymentContributor.java | 55 +++++ ....gateway.deploy.ServiceDeploymentContributor | 19 ++ .../service/knoxs3/S3BucketsResourceTest.java | 79 +++++++ .../services/s3client/KnoxS3ClientBuilder.java | 219 +++++++++++++++++++ .../services/s3client/S3PolicyModel.java | 60 +++++ pom.xml | 6 + 10 files changed, 749 insertions(+) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/knox/blob/43567b0a/gateway-release/pom.xml ---------------------------------------------------------------------- diff --git a/gateway-release/pom.xml b/gateway-release/pom.xml index c729535..b65c2ef 100644 --- a/gateway-release/pom.xml +++ b/gateway-release/pom.xml @@ -217,6 +217,10 @@ </dependency> <dependency> <groupId>${gateway-group}</groupId> + <artifactId>gateway-service-knoxs3</artifactId> + </dependency> + <dependency> + <groupId>${gateway-group}</groupId> <artifactId>gateway-service-nifi</artifactId> </dependency> <dependency> http://git-wip-us.apache.org/repos/asf/knox/blob/43567b0a/gateway-service-knoxs3/pom.xml ---------------------------------------------------------------------- diff --git a/gateway-service-knoxs3/pom.xml b/gateway-service-knoxs3/pom.xml new file mode 100644 index 0000000..37fcc52 --- /dev/null +++ b/gateway-service-knoxs3/pom.xml @@ -0,0 +1,76 @@ +<?xml version="1.0"?> +<!-- + 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.0.0</version> + </parent> + <groupId>org.apache.knox</groupId> + <artifactId>gateway-service-knoxs3</artifactId> + <version>1.0.0</version> + <name>gateway-service-health</name> + <url>http://maven.apache.org</url> + <properties> + <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> + </properties> + <dependencies> + <dependency> + <groupId>${gateway-group}</groupId> + <artifactId>gateway-util-common</artifactId> + </dependency> + <dependency> + <groupId>${gateway-group}</groupId> + <artifactId>gateway-spi</artifactId> + </dependency> + <dependency> + <groupId>${gateway-group}</groupId> + <artifactId>gateway-provider-rewrite</artifactId> + </dependency> + <dependency> + <groupId>${gateway-group}</groupId> + <artifactId>gateway-provider-jersey</artifactId> + </dependency> + <dependency> + <groupId>junit</groupId> + <artifactId>junit</artifactId> + <scope>test</scope> + </dependency> + <dependency> + <groupId>org.apache.knox</groupId> + <artifactId>gateway-test-utils</artifactId> + <scope>test</scope> + </dependency> + <dependency> + <groupId>org.easymock</groupId> + <artifactId>easymock</artifactId> + <scope>test</scope> + </dependency> + <dependency> + <groupId>io.dropwizard.metrics</groupId> + <artifactId>metrics-servlets</artifactId> + </dependency> + <dependency> + <groupId>org.apache.knox</groupId> + <artifactId>gateway-server</artifactId> + </dependency> + </dependencies> +</project> http://git-wip-us.apache.org/repos/asf/knox/blob/43567b0a/gateway-service-knoxs3/src/main/java/org/apache/knox/gateway/service/knoxs3/KnoxS3ServiceMessages.java ---------------------------------------------------------------------- diff --git a/gateway-service-knoxs3/src/main/java/org/apache/knox/gateway/service/knoxs3/KnoxS3ServiceMessages.java b/gateway-service-knoxs3/src/main/java/org/apache/knox/gateway/service/knoxs3/KnoxS3ServiceMessages.java new file mode 100644 index 0000000..36e1f21 --- /dev/null +++ b/gateway-service-knoxs3/src/main/java/org/apache/knox/gateway/service/knoxs3/KnoxS3ServiceMessages.java @@ -0,0 +1,32 @@ +/** + * 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.service.knoxs3; + +import org.apache.knox.gateway.i18n.messages.Message; +import org.apache.knox.gateway.i18n.messages.MessageLevel; +import org.apache.knox.gateway.i18n.messages.Messages; +import org.apache.knox.gateway.i18n.messages.StackTrace; + +@Messages(logger = "org.apache.knox.gateway.service.health") +public interface KnoxS3ServiceMessages { + @Message(level = MessageLevel.INFO, text = "{0}") + void basicInfo(String original); + + @Message(level = MessageLevel.ERROR, text = "Unable to get health stats for {0}, due to {1}") + void logException(String name, @StackTrace(level = MessageLevel.DEBUG) Exception e); +} \ No newline at end of file http://git-wip-us.apache.org/repos/asf/knox/blob/43567b0a/gateway-service-knoxs3/src/main/java/org/apache/knox/gateway/service/knoxs3/S3BucketsResource.java ---------------------------------------------------------------------- diff --git a/gateway-service-knoxs3/src/main/java/org/apache/knox/gateway/service/knoxs3/S3BucketsResource.java b/gateway-service-knoxs3/src/main/java/org/apache/knox/gateway/service/knoxs3/S3BucketsResource.java new file mode 100644 index 0000000..d0b25d7 --- /dev/null +++ b/gateway-service-knoxs3/src/main/java/org/apache/knox/gateway/service/knoxs3/S3BucketsResource.java @@ -0,0 +1,199 @@ +/** + * 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.service.knoxs3; + +import org.apache.knox.gateway.i18n.messages.MessagesFactory; +import org.apache.knox.gateway.services.GatewayServices; +import org.apache.knox.gateway.util.JsonUtils; + +import com.amazonaws.services.s3.AmazonS3; +import com.amazonaws.services.s3.model.Bucket; +import javax.annotation.PostConstruct; +import javax.servlet.ServletContext; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import javax.ws.rs.DELETE; +import javax.ws.rs.GET; +import javax.ws.rs.PUT; +import javax.ws.rs.Path; +import javax.ws.rs.PathParam; +import javax.ws.rs.Produces; +import javax.ws.rs.core.Context; +import javax.ws.rs.core.Response; +import java.io.PrintWriter; +import java.util.Enumeration; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Properties; + +import static javax.ws.rs.core.MediaType.APPLICATION_JSON; + + +@Path(S3BucketsResource.RESOURCE_PATH) +public class S3BucketsResource { + private static final String BUCKETS_API_PATH = "buckets"; + private static final String BUCKET_API_PATH = "buckets/{id}"; + private static KnoxS3ServiceMessages log = MessagesFactory.get(KnoxS3ServiceMessages.class); + private static final String VERSION_TAG = "v1"; + static final String RESOURCE_PATH = "/knoxs3/" + VERSION_TAG; + + private static final String CONTENT_TYPE = "application/json"; + private static final String CACHE_CONTROL = "Cache-Control"; + private static final String NO_CACHE = "must-revalidate,no-cache,no-store"; + + private KnoxS3ClientBuilder s3b = new KnoxS3ClientBuilder(); + + @Context + HttpServletRequest request; + + @Context + private HttpServletResponse response; + + @Context + ServletContext context; + + @PostConstruct + public void init() { + s3b.init(getProperties()); + } + + private Properties getProperties() { + Properties props = new Properties(); + String paramName = null; + Enumeration<String> e = context.getInitParameterNames(); + while (e.hasMoreElements()) { + paramName = (String)e.nextElement(); + if (paramName.startsWith("s3.")) { + props.setProperty(paramName, context.getInitParameter(paramName)); + } + } + + return props; + } + + @PUT + @Produces({APPLICATION_JSON}) + @Path(BUCKET_API_PATH) + public Response createBucket(@PathParam("id") String id) { + // use this to get to idbroker service once moved there + GatewayServices services = (GatewayServices) request.getServletContext() + .getAttribute(GatewayServices.GATEWAY_SERVICES_ATTRIBUTE); + return getCreateBucketResponse(id); + } + + private Response getCreateBucketResponse(String id) { + response.setStatus(HttpServletResponse.SC_OK); + response.setHeader(CACHE_CONTROL, NO_CACHE); + response.setContentType(CONTENT_TYPE); + PrintWriter writer = null; + try { + writer = response.getWriter(); + doCreateBucket(id); + } catch (Exception ioe) { + log.logException("create", ioe); + return Response.serverError().entity(String.format("Failed to reply correctly due to : %s ", ioe)).build(); + } finally { + if (writer != null) { + writer.close(); + } + } + return Response.ok().build(); + } + + private void doCreateBucket(String id) { + AmazonS3 s3 = s3b.getS3Client(); + s3.createBucket(id); + } + + @DELETE + @Produces({APPLICATION_JSON}) + @Path(BUCKET_API_PATH) + public Response deleteBucket(@PathParam("id") String id) { + // use this to get to idbroker service once moved there + GatewayServices services = (GatewayServices) request.getServletContext() + .getAttribute(GatewayServices.GATEWAY_SERVICES_ATTRIBUTE); + return getDeleteBucketResponse(id); + + } + + private Response getDeleteBucketResponse(String id) { + response.setStatus(HttpServletResponse.SC_OK); + response.setHeader(CACHE_CONTROL, NO_CACHE); + response.setContentType(CONTENT_TYPE); + PrintWriter writer = null; + try { + writer = response.getWriter(); + doDeleteBucket(id); + } catch (Exception ioe) { + log.logException("delete", ioe); + return Response.serverError().entity(String.format("Failed to reply correctly due to : %s ", ioe)).build(); + } finally { + if (writer != null) { + writer.close(); + } + } + return Response.ok().build(); + } + + private void doDeleteBucket(String id) { + AmazonS3 s3 = s3b.getS3Client(); + s3.deleteBucket(id); + } + + @GET + @Produces({APPLICATION_JSON}) + @Path(BUCKETS_API_PATH) + public Response listBuckets() { + // use this to get to idbroker service once moved there + GatewayServices services = (GatewayServices) request.getServletContext() + .getAttribute(GatewayServices.GATEWAY_SERVICES_ATTRIBUTE); + return getListBucketsResponse(); + } + + private Response getListBucketsResponse() { + response.setStatus(HttpServletResponse.SC_OK); + response.setHeader(CACHE_CONTROL, NO_CACHE); + response.setContentType(CONTENT_TYPE); + PrintWriter writer = null; + try { + writer = response.getWriter(); + writer.println(getBuckets()); + } catch (Exception e) { + log.logException("list", e); + return Response.serverError().entity(String.format("Failed to reply correctly due to : %s ", e)).build(); + } finally { + if (writer != null) { + writer.close(); + } + } + return Response.ok().build(); + } + + private String getBuckets() { + AmazonS3 s3 = s3b.getS3Client(); + Map<String, Object> bucketMap = new HashMap<String, Object>(); + List<Bucket> buckets = s3.listBuckets(); + for (Bucket bucket : buckets) { + System.out.println(bucket.getName()); + bucketMap.put(bucket.getName(), bucket); + } + return JsonUtils.renderAsJsonString(bucketMap); + } + +} http://git-wip-us.apache.org/repos/asf/knox/blob/43567b0a/gateway-service-knoxs3/src/main/java/org/apache/knox/gateway/service/knoxs3/deploy/KnoxS3ServiceDeploymentContributor.java ---------------------------------------------------------------------- diff --git a/gateway-service-knoxs3/src/main/java/org/apache/knox/gateway/service/knoxs3/deploy/KnoxS3ServiceDeploymentContributor.java b/gateway-service-knoxs3/src/main/java/org/apache/knox/gateway/service/knoxs3/deploy/KnoxS3ServiceDeploymentContributor.java new file mode 100644 index 0000000..2a7fdb6 --- /dev/null +++ b/gateway-service-knoxs3/src/main/java/org/apache/knox/gateway/service/knoxs3/deploy/KnoxS3ServiceDeploymentContributor.java @@ -0,0 +1,55 @@ +/** + * 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.service.knoxs3.deploy; + +import org.apache.knox.gateway.jersey.JerseyServiceDeploymentContributorBase; + +public class KnoxS3ServiceDeploymentContributor extends JerseyServiceDeploymentContributorBase { + + /* (non-Javadoc) + * @see ServiceDeploymentContributor#getRole() + */ + @Override + public String getRole() { + return "KNOXS3"; + } + + /* (non-Javadoc) + * @see ServiceDeploymentContributor#getName() + */ + @Override + public String getName() { + return "KnoxS3Service"; + } + + /* (non-Javadoc) + * @see JerseyServiceDeploymentContributorBase#getPackages() + */ + @Override + protected String[] getPackages() { + return new String[]{"org.apache.knox.gateway.service.knoxs3"}; + } + + /* (non-Javadoc) + * @see JerseyServiceDeploymentContributorBase#getPatterns() + */ + @Override + protected String[] getPatterns() { + return new String[]{"*/**?**"}; + } +} http://git-wip-us.apache.org/repos/asf/knox/blob/43567b0a/gateway-service-knoxs3/src/main/resources/META-INF/services/org.apache.knox.gateway.deploy.ServiceDeploymentContributor ---------------------------------------------------------------------- diff --git a/gateway-service-knoxs3/src/main/resources/META-INF/services/org.apache.knox.gateway.deploy.ServiceDeploymentContributor b/gateway-service-knoxs3/src/main/resources/META-INF/services/org.apache.knox.gateway.deploy.ServiceDeploymentContributor new file mode 100644 index 0000000..fcfbdd7 --- /dev/null +++ b/gateway-service-knoxs3/src/main/resources/META-INF/services/org.apache.knox.gateway.deploy.ServiceDeploymentContributor @@ -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.service.health.deploy.HealthServiceDeploymentContributor \ No newline at end of file http://git-wip-us.apache.org/repos/asf/knox/blob/43567b0a/gateway-service-knoxs3/src/test/java/org/apache/knox/gateway/service/knoxs3/S3BucketsResourceTest.java ---------------------------------------------------------------------- diff --git a/gateway-service-knoxs3/src/test/java/org/apache/knox/gateway/service/knoxs3/S3BucketsResourceTest.java b/gateway-service-knoxs3/src/test/java/org/apache/knox/gateway/service/knoxs3/S3BucketsResourceTest.java new file mode 100644 index 0000000..d75c7ce --- /dev/null +++ b/gateway-service-knoxs3/src/test/java/org/apache/knox/gateway/service/knoxs3/S3BucketsResourceTest.java @@ -0,0 +1,79 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.knox.gateway.service.knoxs3; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.Map; + +import org.apache.knox.gateway.util.JsonUtils; +import org.junit.Test; + +public class S3BucketsResourceTest { + @Test + public void testPolicyCreation() { + + String policy = "{\n" + + " \"Version\": \"2012-10-17\",\n" + + " \"Statement\": [\n" + + " {\n" + + " \"Effect\": \"Allow\",\n" + + " \"Action\": [\n" + + " \"s3:Get*\",\n" + + " \"s3:List*\"\n" + + // " \"s3:Delete*\"\n" + + " ],\n" + + " \"Resource\": \"*\"\n" + + " }\n" + + " ]\n" + + "}"; + System.out.println(policy); + + HashMap<String, Object> policyModel = new HashMap<String, Object>(); + policyModel.put("Version", "2012-10-17"); + ArrayList<Map<String, Object>> statement = new ArrayList<Map<String, Object>>(); + + policyModel.put("Version", "2012-10-17"); + policyModel.put("Statement", statement ); + HashMap<String, Object> statementMap = new HashMap<String, Object>(); + statementMap.put("Effect", "Allow"); + ArrayList<String> actionArray = new ArrayList<String>(); + actionArray.add("s3:Get*"); + actionArray.add("s3:List*"); + statementMap.put("Action", actionArray ); + statement.add(statementMap); + policyModel.put("Resource", "*"); + + System.out.println(JsonUtils.renderAsJsonString(policyModel)); + + S3PolicyModel model = new S3PolicyModel(); + model.setEffect("Allow"); + model.addAction("s3:Get*"); + model.addAction("s3:List*"); + model.setResource("*"); + System.out.println(model); + + model = new S3PolicyModel(); + model.setEffect("Allow"); + model.addAction("s3:Get*"); + model.addAction("s3:List*"); + model.addResource("this"); + model.addResource("that"); + System.out.println(model); +} +} \ No newline at end of file http://git-wip-us.apache.org/repos/asf/knox/blob/43567b0a/gateway-spi/src/main/java/org/apache/knox/gateway/services/s3client/KnoxS3ClientBuilder.java ---------------------------------------------------------------------- diff --git a/gateway-spi/src/main/java/org/apache/knox/gateway/services/s3client/KnoxS3ClientBuilder.java b/gateway-spi/src/main/java/org/apache/knox/gateway/services/s3client/KnoxS3ClientBuilder.java new file mode 100644 index 0000000..cebfba0 --- /dev/null +++ b/gateway-spi/src/main/java/org/apache/knox/gateway/services/s3client/KnoxS3ClientBuilder.java @@ -0,0 +1,219 @@ +/** + * 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.service.knoxs3; + +import java.security.AccessController; +import java.security.Principal; +import java.util.ArrayList; +import java.util.Enumeration; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Properties; + +import javax.security.auth.Subject; + +import org.apache.knox.gateway.security.GroupPrincipal; +import org.apache.knox.gateway.security.ImpersonatedPrincipal; +import org.apache.knox.gateway.security.PrimaryPrincipal; + +import com.amazonaws.auth.AWSStaticCredentialsProvider; +import com.amazonaws.auth.BasicSessionCredentials; +import com.amazonaws.regions.Regions; +import com.amazonaws.services.s3.AmazonS3; +import com.amazonaws.services.s3.AmazonS3ClientBuilder; +import com.amazonaws.services.securitytoken.AWSSecurityTokenService; +import com.amazonaws.services.securitytoken.AWSSecurityTokenServiceClientBuilder; +import com.amazonaws.services.securitytoken.model.Credentials; +import com.amazonaws.services.securitytoken.model.GetFederationTokenRequest; +import com.amazonaws.services.securitytoken.model.GetFederationTokenResult; + +public class KnoxS3ClientBuilder { + private Map<String, PolicyConfig> userPolicyConfig = new HashMap<String, PolicyConfig>(); + private Map<String, PolicyConfig> groupPolicyConfig = new HashMap<String, PolicyConfig>(); + + public KnoxS3ClientBuilder() { + } + + public AmazonS3 getS3Client() { + BasicSessionCredentials sessionCredentials = getSessionCredentials(); + if (sessionCredentials == null) { + throw new RuntimeException("No S3 credentials available."); + } + + AmazonS3 s3 = AmazonS3ClientBuilder.standard().withRegion(Regions.US_EAST_1) + .withCredentials(new AWSStaticCredentialsProvider(sessionCredentials)).build(); + return s3; + } + + public void init(Properties context) { + buildPolicyMaps(context); + } + + private void buildPolicyMaps(Properties context) { + /* + <service> + <role>KNOXS3</role> + <param> + <name>s3.user.policy.action.guest</name> + <value>s3:Get*,s3:List*</value> + </param> + <param> + <name>s3.user.policy.resource.guest</name> + <value>*</value> + </param> + <param> + <name>s3.group.policy.action.admin</name> + <value>*</value> + </param> + <param> + <name>s3.group.policy.resource.admin</name> + <value>*</value> + </param> + </service> + */ + + String paramName = null; + Enumeration<Object> e = context.keys(); + while (e.hasMoreElements()) { + paramName = (String)e.nextElement(); + if (paramName.startsWith("s3.")) { + String[] elements = paramName.split("\\."); + if (elements[1].equals("user")) { + PolicyConfig policy = userPolicyConfig.get(elements[4]); + if (policy == null) { + policy = new PolicyConfig(); + userPolicyConfig.put(elements[4], policy); + } + if (elements[3].equals("action")) { + policy.actions=context.getProperty(paramName); + } else { + policy.resources=context.getProperty(paramName); + } + if (policy.actions != null && policy.resources != null) { + buildS3PolicyModel(policy); + } + }else if (elements[1].equals("group")) { + PolicyConfig policy = groupPolicyConfig.get(elements[4]); + if (policy == null) { + policy = new PolicyConfig(); + groupPolicyConfig.put(elements[4], policy); + } + if (elements[3].equals("action")) { + policy.actions=context.getProperty(paramName); + } else { + policy.resources=context.getProperty(paramName); + } + if (policy.actions != null && policy.resources != null) { + buildS3PolicyModel(policy); + } + } + } + } + } + + private void buildS3PolicyModel(PolicyConfig policy) { + S3PolicyModel model = new S3PolicyModel(); + model.setEffect("Allow"); + String[] actions = policy.actions.split(","); + for (int i = 0; i < actions.length; i++) { + model.addAction(actions[i]); + } + String[] resources = policy.resources.split(","); + if (resources.length > 1) { + for (int i = 0; i < resources.length; i++) { + model.addResource(resources[i]); + } + } else { + model.setResource(resources[0]); + } + policy.policy = model.toString(); + } + + private BasicSessionCredentials getSessionCredentials() { + AWSSecurityTokenService sts_client = AWSSecurityTokenServiceClientBuilder.standard().withRegion(Regions.US_EAST_1).build(); + String policy = ""; + BasicSessionCredentials sessionCredentials = null; + try { + String username = null; + Subject subject = Subject.getSubject(AccessController.getContext()); + username = getEffectiveUserName(subject); + policy = buildPolicy(username, subject); + + if (policy != null) { + GetFederationTokenRequest request = new GetFederationTokenRequest(username).withPolicy(policy); + GetFederationTokenResult result = sts_client.getFederationToken(request); + System.out.println(result.getCredentials()); + + Credentials session_creds = result.getCredentials(); + sessionCredentials = new BasicSessionCredentials( + session_creds.getAccessKeyId(), + session_creds.getSecretAccessKey(), + session_creds.getSessionToken()); + } + } catch (Exception e) { + e.printStackTrace(); + } + return sessionCredentials; + } + + private String getEffectiveUserName(Subject subject) { + String username; + Principal primaryPrincipal = (Principal)subject.getPrincipals(PrimaryPrincipal.class).toArray()[0]; + Object[] impersonations = subject.getPrincipals(ImpersonatedPrincipal.class).toArray(); + if (impersonations.length > 0) { + username = ((Principal)impersonations[0]).getName(); + } + else { + username = primaryPrincipal.getName(); + } + return username; + } + + private String buildPolicy(String username, Subject subject) { + String policy = null; + List<String> groupNames = new ArrayList<String>(); + Object[] groups = subject.getPrincipals(GroupPrincipal.class).toArray(); + for (int i = 0; i < groups.length; i++) { + groupNames.add( + ((Principal)groups[0]).getName()); + } + + PolicyConfig config = userPolicyConfig.get(username); + if (config == null) { + // check for a group policy match + for (String groupName : groupNames) { + config = groupPolicyConfig.get(groupName); + if (config != null) { + // just accept first match for now + break; + } + } + } + if (config != null) { + policy = config.policy; + } + return policy; + } + + private class PolicyConfig { + public String actions = null; + public String resources = null; + public String policy = null; + } +} \ No newline at end of file http://git-wip-us.apache.org/repos/asf/knox/blob/43567b0a/gateway-spi/src/main/java/org/apache/knox/gateway/services/s3client/S3PolicyModel.java ---------------------------------------------------------------------- diff --git a/gateway-spi/src/main/java/org/apache/knox/gateway/services/s3client/S3PolicyModel.java b/gateway-spi/src/main/java/org/apache/knox/gateway/services/s3client/S3PolicyModel.java new file mode 100644 index 0000000..f7f3084 --- /dev/null +++ b/gateway-spi/src/main/java/org/apache/knox/gateway/services/s3client/S3PolicyModel.java @@ -0,0 +1,60 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.knox.gateway.service.knoxs3; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.Map; + +import org.apache.knox.gateway.util.JsonUtils; + +public class S3PolicyModel { + HashMap<String, Object> policyModel = new HashMap<String, Object>(); + ArrayList<String> actionArray = new ArrayList<String>(); + HashMap<String, Object> statementMap = new HashMap<String, Object>(); + ArrayList<String> resourcesArray = new ArrayList<String>(); + + public S3PolicyModel() { + policyModel.put("Version", "2012-10-17"); + ArrayList<Map<String, Object>> statement = new ArrayList<Map<String, Object>>(); + policyModel.put("Statement", statement ); + statement.add(statementMap); + statementMap.put("Action", actionArray ); + statementMap.put("Resource", resourcesArray); + } + + public void setEffect(String effect) { + statementMap.put("Effect", effect); + } + + public void addAction(String action) { + actionArray.add(action); + } + + public void addResource(String resource) { + resourcesArray.add(resource); + } + + public void setResource(String resource) { + statementMap.put("Resource", resource); + } + + public String toString() { + return JsonUtils.renderAsJsonString(policyModel); + } +} http://git-wip-us.apache.org/repos/asf/knox/blob/43567b0a/pom.xml ---------------------------------------------------------------------- diff --git a/pom.xml b/pom.xml index 3297aa8..1c49602 100644 --- a/pom.xml +++ b/pom.xml @@ -78,6 +78,7 @@ <module>gateway-service-knoxsso</module> <module>gateway-service-knoxssout</module> <module>gateway-service-knoxtoken</module> + <module>gateway-service-knoxs3</module> <module>gateway-service-health</module> <module>gateway-service-webhdfs</module> <module>gateway-service-tgs</module> @@ -633,6 +634,11 @@ </dependency> <dependency> <groupId>${gateway-group}</groupId> + <artifactId>gateway-service-knoxs3</artifactId> + <version>${gateway-version}</version> + </dependency> + <dependency> + <groupId>${gateway-group}</groupId> <artifactId>gateway-service-admin</artifactId> <version>${gateway-version}</version> </dependency>
