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/18e49c4b
Tree: http://git-wip-us.apache.org/repos/asf/knox/tree/18e49c4b
Diff: http://git-wip-us.apache.org/repos/asf/knox/diff/18e49c4b

Branch: refs/heads/KNOX-1204
Commit: 18e49c4bccb6319ffdc370c313f6fe62fa06d31f
Parents: 43567b0
Author: Larry McCay <[email protected]>
Authored: Fri Mar 30 11:22:21 2018 -0400
Committer: Larry McCay <[email protected]>
Committed: Fri Mar 30 11:22:21 2018 -0400

----------------------------------------------------------------------
 ...ctIdentityAsserterDeploymentContributor.java |   4 +
 .../filter/AbstractIdentityAssertionFilter.java |  27 +--
 .../filter/CommonIdentityAssertionFilter.java   |  76 ++++++-
 .../filter/HadoopGroupProviderFilter.java       |   1 -
 gateway-service-knoxs3/pom.xml                  |  29 ++-
 .../gateway/service/knoxs3/AWSPolicyModel.java  |  60 +++++
 .../service/knoxs3/IdentityBrokerResource.java  | 133 +++++++++++
 .../service/knoxs3/KnoxS3ClientBuilder.java     | 227 +++++++++++++++++++
 .../service/knoxs3/S3BucketsResource.java       | 214 ++++++++++++++++-
 ....gateway.deploy.ServiceDeploymentContributor |   2 +-
 .../service/knoxs3/S3BucketsResourceTest.java   |   4 +-
 .../security/ClientImpersonatedPrincipal.java   |  33 +++
 .../knox/gateway/security/SubjectUtils.java     |   8 +
 .../services/s3client/KnoxS3ClientBuilder.java  | 219 ------------------
 .../services/s3client/S3PolicyModel.java        |  60 -----
 15 files changed, 786 insertions(+), 311 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/knox/blob/18e49c4b/gateway-provider-identity-assertion-common/src/main/java/org/apache/knox/gateway/identityasserter/common/filter/AbstractIdentityAsserterDeploymentContributor.java
----------------------------------------------------------------------
diff --git 
a/gateway-provider-identity-assertion-common/src/main/java/org/apache/knox/gateway/identityasserter/common/filter/AbstractIdentityAsserterDeploymentContributor.java
 
b/gateway-provider-identity-assertion-common/src/main/java/org/apache/knox/gateway/identityasserter/common/filter/AbstractIdentityAsserterDeploymentContributor.java
index 8f2adb8..170a5f0 100644
--- 
a/gateway-provider-identity-assertion-common/src/main/java/org/apache/knox/gateway/identityasserter/common/filter/AbstractIdentityAsserterDeploymentContributor.java
+++ 
b/gateway-provider-identity-assertion-common/src/main/java/org/apache/knox/gateway/identityasserter/common/filter/AbstractIdentityAsserterDeploymentContributor.java
@@ -50,6 +50,10 @@ public abstract class 
AbstractIdentityAsserterDeploymentContributor extends
     if (params == null) {
       params = new ArrayList<FilterParamDescriptor>();
     }
+    // add resource role to params so that we can determine the service 
specific impersonation
+    // method when configured
+    params.add( resource.createFilterParam().name( "resource.role" 
).value(resource.role() ) );
+
     Map<String, String> providerParams = provider.getParams();
     for(Entry<String, String> entry : providerParams.entrySet()) {
       params.add( 
resource.createFilterParam().name(entry.getKey().toLowerCase()).value(entry.getValue()));

http://git-wip-us.apache.org/repos/asf/knox/blob/18e49c4b/gateway-provider-identity-assertion-common/src/main/java/org/apache/knox/gateway/identityasserter/common/filter/AbstractIdentityAssertionFilter.java
----------------------------------------------------------------------
diff --git 
a/gateway-provider-identity-assertion-common/src/main/java/org/apache/knox/gateway/identityasserter/common/filter/AbstractIdentityAssertionFilter.java
 
b/gateway-provider-identity-assertion-common/src/main/java/org/apache/knox/gateway/identityasserter/common/filter/AbstractIdentityAssertionFilter.java
index a007ab6..c2ca08d 100644
--- 
a/gateway-provider-identity-assertion-common/src/main/java/org/apache/knox/gateway/identityasserter/common/filter/AbstractIdentityAssertionFilter.java
+++ 
b/gateway-provider-identity-assertion-common/src/main/java/org/apache/knox/gateway/identityasserter/common/filter/AbstractIdentityAssertionFilter.java
@@ -23,6 +23,7 @@ import java.security.Principal;
 import java.security.PrivilegedActionException;
 import java.security.PrivilegedExceptionAction;
 import java.util.Arrays;
+import java.util.HashSet;
 import java.util.Set;
 
 import javax.security.auth.Subject;
@@ -44,6 +45,7 @@ import 
org.apache.knox.gateway.audit.log4j.audit.AuditConstants;
 import org.apache.knox.gateway.filter.security.AbstractIdentityAssertionBase;
 import org.apache.knox.gateway.i18n.GatewaySpiResources;
 import org.apache.knox.gateway.i18n.resources.ResourcesFactory;
+import org.apache.knox.gateway.security.ClientImpersonatedPrincipal;
 import org.apache.knox.gateway.security.GroupPrincipal;
 import org.apache.knox.gateway.security.ImpersonatedPrincipal;
 import org.apache.knox.gateway.security.PrimaryPrincipal;
@@ -68,7 +70,7 @@ public abstract class AbstractIdentityAssertionFilter extends
   }
 
   /**
-   * This method returns a Stringp[] of new group principal names to use
+   * This method returns a String[] of new group principal names to use
    * based on implementation specific mapping or lookup mechanisms.
    * Returning null means that whatever set of GroupPrincipals is in the
    * provided Subject is sufficient to use and no additional mapping is 
required.
@@ -87,7 +89,7 @@ public abstract class AbstractIdentityAssertionFilter extends
    */
   public abstract String mapUserPrincipal(String principalName);
 
-  /**
+    /**
    * @param wrapper
    * @param response
    * @param chain
@@ -95,22 +97,21 @@ public abstract class AbstractIdentityAssertionFilter 
extends
    * @param groups
    */
   protected void continueChainAsPrincipal(HttpServletRequestWrapper request, 
ServletResponse response,
-      FilterChain chain, String mappedPrincipalName, String[] groups) throws 
IOException,
-      ServletException {
+      FilterChain chain, String mappedPrincipalName, String[] groups) throws 
IOException, ServletException {
         Subject subject = null;
         Principal impersonationPrincipal = null;
         Principal primaryPrincipal = null;
-        
+
         // get the current subject and determine whether we need another doAs 
with 
         // an impersonatedPrincipal and/or mapped group principals
         boolean impersonationNeeded = false;
         boolean groupsMapped = false;
-        
-        // look up the current Java Subject and assosciated group principals
+
+        Set<?> currentGroups = null;
+        // look up the current Java Subject and associated group principals
         Subject currentSubject = 
Subject.getSubject(AccessController.getContext());
-        Set<?> currentGroups = 
currentSubject.getPrincipals(GroupPrincipal.class);
-        
-        primaryPrincipal = (PrimaryPrincipal) 
currentSubject.getPrincipals(PrimaryPrincipal.class).toArray()[0];
+        currentGroups = currentSubject.getPrincipals(GroupPrincipal.class);
+
         if (primaryPrincipal != null) {
           if (!primaryPrincipal.getName().equals(mappedPrincipalName)) {
             impersonationNeeded = true;
@@ -126,9 +127,9 @@ public abstract class AbstractIdentityAssertionFilter 
extends
           // TODO: log as appropriate
           primaryPrincipal = new PrimaryPrincipal(((HttpServletRequest) 
request).getUserPrincipal().getName());
         }
-        
+
         groupsMapped = groups != null || !currentGroups.isEmpty();
-        
+
         if (impersonationNeeded || groupsMapped) {
           // gonna need a new subject and doAs
           subject = new Subject();
@@ -139,7 +140,7 @@ public abstract class AbstractIdentityAssertionFilter 
extends
           for (Object obj : currentGroups) {
             principals.add((Principal)obj);
           }
-          
+
           if (impersonationNeeded) {
             impersonationPrincipal = new 
ImpersonatedPrincipal(mappedPrincipalName);
             subject.getPrincipals().add(impersonationPrincipal);

http://git-wip-us.apache.org/repos/asf/knox/blob/18e49c4b/gateway-provider-identity-assertion-common/src/main/java/org/apache/knox/gateway/identityasserter/common/filter/CommonIdentityAssertionFilter.java
----------------------------------------------------------------------
diff --git 
a/gateway-provider-identity-assertion-common/src/main/java/org/apache/knox/gateway/identityasserter/common/filter/CommonIdentityAssertionFilter.java
 
b/gateway-provider-identity-assertion-common/src/main/java/org/apache/knox/gateway/identityasserter/common/filter/CommonIdentityAssertionFilter.java
index 391aa9e..2e3adaf 100644
--- 
a/gateway-provider-identity-assertion-common/src/main/java/org/apache/knox/gateway/identityasserter/common/filter/CommonIdentityAssertionFilter.java
+++ 
b/gateway-provider-identity-assertion-common/src/main/java/org/apache/knox/gateway/identityasserter/common/filter/CommonIdentityAssertionFilter.java
@@ -32,17 +32,56 @@ import 
org.apache.knox.gateway.security.principal.SimplePrincipalMapper;
 
 import java.io.IOException;
 import java.security.AccessController;
+import java.util.HashMap;
 
 public class CommonIdentityAssertionFilter extends 
AbstractIdentityAssertionFilter {
   private static final String GROUP_PRINCIPAL_MAPPING = 
"group.principal.mapping";
   private static final String PRINCIPAL_MAPPING = "principal.mapping";
   private SimplePrincipalMapper mapper = new SimplePrincipalMapper();
+  private HashMap<String, Impersonation> impMap = new HashMap<String, 
Impersonation>();
+  private String resourceRole = null;
 
   /* (non-Javadoc)
    * @see javax.servlet.Filter#init(javax.servlet.FilterConfig)
    */
   @Override
   public void init(FilterConfig filterConfig) throws ServletException {
+
+    /*
+     <param>
+       <name>path.segment.impersonated.principal</name>
+       <value>IDBROKER;credentials</value>
+     </param>
+
+     <param>
+       <name>header.impersonated.principal</name>
+       <value>*;SM_USER</value>
+     </param>
+
+     <param>
+       <name>query.param.impersonated.principal</name>
+       <value>WEBHDFS,HIVE;doas</value>
+     </param>
+    */
+
+    resourceRole = filterConfig.getInitParameter("resource.role");
+    String pathSegmentImpersonation = 
filterConfig.getInitParameter("path.segment.impersonated.principal");
+    if (pathSegmentImpersonation != null) {
+      String services = pathSegmentImpersonation.substring(0, 
pathSegmentImpersonation.indexOf(";"));
+      String[] svcArray = services.split(",");
+      String service = null;
+      int segmentIndex;
+      for (int i = 0; i < svcArray.length; i++) {
+        service = svcArray[i];
+        segmentIndex = pathSegmentImpersonation.indexOf(";");
+        if (segmentIndex != -1) {
+          Impersonation imp = new Impersonation(service, "path.segment", 
+              pathSegmentImpersonation.substring(segmentIndex+1));
+          impMap.put(svcArray[i], imp);
+        }
+      }
+    }
+
     String principalMapping = filterConfig.getInitParameter(PRINCIPAL_MAPPING);
     if (principalMapping == null || principalMapping.isEmpty()) {
       principalMapping = 
filterConfig.getServletContext().getInitParameter(PRINCIPAL_MAPPING);
@@ -78,7 +117,30 @@ public class CommonIdentityAssertionFilter extends 
AbstractIdentityAssertionFilt
 
     String principalName = getPrincipalName(subject);
 
-    String mappedPrincipalName = mapUserPrincipalBase(principalName);
+    String mappedPrincipalName = null;
+    
+    Impersonation imp = impMap.get(resourceRole);
+    if (imp != null) {
+      if (imp.type.equals("path.segment")) {
+        String pathInfo = ((HttpServletRequest)request).getPathInfo();
+        String[] segments = pathInfo.split("/");
+        for (int i = 0; i < segments.length; i++) {
+          if (segments[i].equals(imp.name)) {
+            if (segments.length > i+1) {
+              mappedPrincipalName = segments[i+1];
+              break;
+            }
+          }
+        }
+      }
+    }
+
+    if (mappedPrincipalName != null && 
!mappedPrincipalName.equals(principalName)) {
+      // TODO: audit this
+      principalName = mappedPrincipalName;
+    }
+
+    mappedPrincipalName = mapUserPrincipalBase(principalName);
     mappedPrincipalName = mapUserPrincipal(mappedPrincipalName);
     String[] mappedGroups = mapGroupPrincipals(mappedPrincipalName, subject);
     String[] groups = mapGroupPrincipals(mappedPrincipalName, subject);
@@ -140,4 +202,16 @@ public class CommonIdentityAssertionFilter extends 
AbstractIdentityAssertionFilt
     // NOP
     return principalName;
   }
+  
+  private class Impersonation {
+    public String service = null;
+    public String type = null;
+    public String name = null;
+    
+    public Impersonation(String service, String type, String name) {
+      this.service = service;
+      this.type = type;
+      this.name = name;
+    }
+  }
 }

http://git-wip-us.apache.org/repos/asf/knox/blob/18e49c4b/gateway-provider-identity-assertion-hadoop-groups/src/main/java/org/apache/knox/gateway/identityasserter/hadoop/groups/filter/HadoopGroupProviderFilter.java
----------------------------------------------------------------------
diff --git 
a/gateway-provider-identity-assertion-hadoop-groups/src/main/java/org/apache/knox/gateway/identityasserter/hadoop/groups/filter/HadoopGroupProviderFilter.java
 
b/gateway-provider-identity-assertion-hadoop-groups/src/main/java/org/apache/knox/gateway/identityasserter/hadoop/groups/filter/HadoopGroupProviderFilter.java
index 1459498..6a5b5a4 100644
--- 
a/gateway-provider-identity-assertion-hadoop-groups/src/main/java/org/apache/knox/gateway/identityasserter/hadoop/groups/filter/HadoopGroupProviderFilter.java
+++ 
b/gateway-provider-identity-assertion-hadoop-groups/src/main/java/org/apache/knox/gateway/identityasserter/hadoop/groups/filter/HadoopGroupProviderFilter.java
@@ -114,7 +114,6 @@ public class HadoopGroupProviderFilter extends 
CommonIdentityAssertionFilter {
   }
 
   public String mapUserPrincipal(final String principalName) {
-    /* return the passed principal */
     return principalName;
   }
 

http://git-wip-us.apache.org/repos/asf/knox/blob/18e49c4b/gateway-service-knoxs3/pom.xml
----------------------------------------------------------------------
diff --git a/gateway-service-knoxs3/pom.xml b/gateway-service-knoxs3/pom.xml
index 37fcc52..d83613c 100644
--- a/gateway-service-knoxs3/pom.xml
+++ b/gateway-service-knoxs3/pom.xml
@@ -22,16 +22,29 @@
     <parent>
         <groupId>org.apache.knox</groupId>
         <artifactId>gateway</artifactId>
-        <version>1.0.0</version>
+        <version>1.1.0-SNAPSHOT</version>
     </parent>
     <groupId>org.apache.knox</groupId>
     <artifactId>gateway-service-knoxs3</artifactId>
-    <version>1.0.0</version>
-    <name>gateway-service-health</name>
+    <version>1.1.0-SNAPSHOT</version>
+    <name>gateway-service-knoxs3</name>
     <url>http://maven.apache.org</url>
     <properties>
         <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
     </properties>
+    
+        <dependencyManagement>
+        <dependencies>
+            <dependency>
+                <groupId>com.amazonaws</groupId>
+                <artifactId>aws-java-sdk-bom</artifactId>
+                <version>1.11.106</version>
+                <type>pom</type>
+                <scope>import</scope>
+            </dependency>
+        </dependencies>
+    </dependencyManagement>
+    
     <dependencies>
         <dependency>
             <groupId>${gateway-group}</groupId>
@@ -72,5 +85,15 @@
             <groupId>org.apache.knox</groupId>
             <artifactId>gateway-server</artifactId>
         </dependency>
+        <dependency>
+            <groupId>com.amazonaws</groupId>
+            <artifactId>aws-java-sdk-s3</artifactId>
+            <version>1.11.106</version>
+        </dependency>
+        <dependency>
+            <groupId>com.amazonaws</groupId>
+            <artifactId>aws-java-sdk-sts</artifactId>
+            <version>1.11.106</version>
+        </dependency>
     </dependencies>
 </project>

http://git-wip-us.apache.org/repos/asf/knox/blob/18e49c4b/gateway-service-knoxs3/src/main/java/org/apache/knox/gateway/service/knoxs3/AWSPolicyModel.java
----------------------------------------------------------------------
diff --git 
a/gateway-service-knoxs3/src/main/java/org/apache/knox/gateway/service/knoxs3/AWSPolicyModel.java
 
b/gateway-service-knoxs3/src/main/java/org/apache/knox/gateway/service/knoxs3/AWSPolicyModel.java
new file mode 100644
index 0000000..4b51dc3
--- /dev/null
+++ 
b/gateway-service-knoxs3/src/main/java/org/apache/knox/gateway/service/knoxs3/AWSPolicyModel.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 AWSPolicyModel {
+  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 AWSPolicyModel() {
+    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/18e49c4b/gateway-service-knoxs3/src/main/java/org/apache/knox/gateway/service/knoxs3/IdentityBrokerResource.java
----------------------------------------------------------------------
diff --git 
a/gateway-service-knoxs3/src/main/java/org/apache/knox/gateway/service/knoxs3/IdentityBrokerResource.java
 
b/gateway-service-knoxs3/src/main/java/org/apache/knox/gateway/service/knoxs3/IdentityBrokerResource.java
new file mode 100644
index 0000000..ed235dd
--- /dev/null
+++ 
b/gateway-service-knoxs3/src/main/java/org/apache/knox/gateway/service/knoxs3/IdentityBrokerResource.java
@@ -0,0 +1,133 @@
+/**
+ * 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.security.ImpersonatedPrincipal;
+import org.apache.knox.gateway.security.PrimaryPrincipal;
+import org.apache.knox.gateway.security.SubjectUtils;
+
+import com.amazonaws.auth.BasicSessionCredentials;
+import com.amazonaws.services.s3.AmazonS3;
+import com.amazonaws.services.securitytoken.model.GetFederationTokenResult;
+
+import javax.annotation.PostConstruct;
+import javax.security.auth.Subject;
+import javax.servlet.ServletContext;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import javax.ws.rs.GET;
+import javax.ws.rs.Path;
+import javax.ws.rs.Produces;
+import javax.ws.rs.core.Context;
+import javax.ws.rs.core.Response;
+import java.io.PrintWriter;
+import java.security.AccessController;
+import java.security.Principal;
+import java.util.Enumeration;
+import java.util.Properties;
+
+import static javax.ws.rs.core.MediaType.APPLICATION_JSON;
+
+@Path(IdentityBrokerResource.RESOURCE_PATH)
+public class IdentityBrokerResource {
+  private static final String CREDENTIALS_API_PATH = "credentials";
+  private static final String USER_CREDENTIALS_API_PATH = "credentials/{id}";
+  private static KnoxS3ServiceMessages log = 
MessagesFactory.get(KnoxS3ServiceMessages.class);
+  private static final String VERSION_TAG = "api/v1";
+  static final String RESOURCE_PATH = "/idbroker/" + 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;
+  }
+
+  @GET
+  @Produces({APPLICATION_JSON})
+  @Path(CREDENTIALS_API_PATH)
+  public Response getCredentials() {
+    return getCredentialsResponse();
+  }
+
+  @GET
+  @Produces({APPLICATION_JSON})
+  @Path(USER_CREDENTIALS_API_PATH)
+  public Response getUserCredentials() {
+    return getCredentialsResponse();
+  }
+
+  private Response getCredentialsResponse() {
+    response.setStatus(HttpServletResponse.SC_OK);
+    response.setHeader(CACHE_CONTROL, NO_CACHE);
+    response.setContentType(CONTENT_TYPE);
+    PrintWriter writer = null;
+    try {
+      writer = response.getWriter();
+      writer.println(getFederationToken());
+    } 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();
+  }
+
+  protected String getFederationToken() {
+//    Subject subject = Subject.getSubject(AccessController.getContext());
+//    String username = getEffectiveUserName(subject);
+    GetFederationTokenResult creds = (GetFederationTokenResult) 
s3b.getFederationTokenResult();
+    return creds.toString();
+  }
+
+  private String getEffectiveUserName(Subject subject) {
+    return SubjectUtils.getEffectivePrincipalName(subject);
+  }
+
+}

http://git-wip-us.apache.org/repos/asf/knox/blob/18e49c4b/gateway-service-knoxs3/src/main/java/org/apache/knox/gateway/service/knoxs3/KnoxS3ClientBuilder.java
----------------------------------------------------------------------
diff --git 
a/gateway-service-knoxs3/src/main/java/org/apache/knox/gateway/service/knoxs3/KnoxS3ClientBuilder.java
 
b/gateway-service-knoxs3/src/main/java/org/apache/knox/gateway/service/knoxs3/KnoxS3ClientBuilder.java
new file mode 100644
index 0000000..aab399a
--- /dev/null
+++ 
b/gateway-service-knoxs3/src/main/java/org/apache/knox/gateway/service/knoxs3/KnoxS3ClientBuilder.java
@@ -0,0 +1,227 @@
+/**
+ * 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 org.apache.knox.gateway.security.SubjectUtils;
+
+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 = (BasicSessionCredentials) 
getCredentials();
+
+    AmazonS3 s3 = 
AmazonS3ClientBuilder.standard().withRegion(Regions.US_EAST_1)
+        .withCredentials(new 
AWSStaticCredentialsProvider(sessionCredentials)).build();
+    return s3;
+  }
+
+  /**
+   * Get an opaque Object representation of the credentials.
+   * This method will only be called by callers that are aware
+   * of the actual form of the credentials in the given context
+   * and therefore able to cast it appropriately.
+   * @return opaque object
+   */
+  public Object getCredentials() {
+    BasicSessionCredentials sessionCredentials = getSessionCredentials();
+    if (sessionCredentials == null) {
+      throw new RuntimeException("No S3 credentials available.");
+    }
+    return sessionCredentials;
+  }
+
+  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) {
+    AWSPolicyModel model = new AWSPolicyModel();
+    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() {
+    BasicSessionCredentials sessionCredentials = null;
+    try {
+      GetFederationTokenResult result = getFederationTokenResult();
+      Credentials session_creds = result.getCredentials();
+      sessionCredentials = new BasicSessionCredentials(
+          session_creds.getAccessKeyId(),
+          session_creds.getSecretAccessKey(),
+          session_creds.getSessionToken());
+    } catch (Exception e) {
+      e.printStackTrace();
+    }
+    return sessionCredentials;
+  }
+
+  public GetFederationTokenResult getFederationTokenResult() {
+    String policy;
+    AWSSecurityTokenService sts_client = 
AWSSecurityTokenServiceClientBuilder.standard().withRegion(Regions.US_EAST_1).build();
+    String username = null;
+    Subject subject = Subject.getSubject(AccessController.getContext());
+    username = getEffectiveUserName(subject);
+    policy = buildPolicy(username, subject);
+    GetFederationTokenResult result = null;
+    if (policy != null) {
+      GetFederationTokenRequest request = new 
GetFederationTokenRequest(username).withPolicy(policy);
+      result = sts_client.getFederationToken(request);
+      System.out.println(result.getCredentials());
+    }
+    return result;
+  }
+
+  private String getEffectiveUserName(Subject subject) {
+    return SubjectUtils.getEffectivePrincipalName(subject);
+  }
+
+  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/18e49c4b/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
index d0b25d7..b261749 100644
--- 
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
@@ -18,24 +18,48 @@
 package org.apache.knox.gateway.service.knoxs3;
 
 import org.apache.knox.gateway.i18n.messages.MessagesFactory;
+import org.apache.knox.gateway.security.ImpersonatedPrincipal;
+import org.apache.knox.gateway.security.PrimaryPrincipal;
+import org.apache.knox.gateway.security.SubjectUtils;
 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 com.amazonaws.services.s3.model.GetObjectRequest;
+import com.amazonaws.services.s3.model.ListObjectsRequest;
+import com.amazonaws.services.s3.model.ObjectListing;
+import com.amazonaws.services.s3.model.S3Object;
+import com.amazonaws.services.s3.model.S3ObjectSummary;
+
 import javax.annotation.PostConstruct;
+import javax.security.auth.Subject;
 import javax.servlet.ServletContext;
 import javax.servlet.http.HttpServletRequest;
 import javax.servlet.http.HttpServletResponse;
+import javax.ws.rs.Consumes;
 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.WebApplicationException;
 import javax.ws.rs.core.Context;
+import javax.ws.rs.core.HttpHeaders;
 import javax.ws.rs.core.Response;
+import javax.ws.rs.core.StreamingOutput;
+
+import java.io.BufferedReader;
+import java.io.BufferedWriter;
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.io.OutputStream;
+import java.io.OutputStreamWriter;
 import java.io.PrintWriter;
+import java.io.Writer;
+import java.security.AccessController;
+import java.security.Principal;
 import java.util.Enumeration;
 import java.util.HashMap;
 import java.util.List;
@@ -43,12 +67,16 @@ import java.util.Map;
 import java.util.Properties;
 
 import static javax.ws.rs.core.MediaType.APPLICATION_JSON;
+import static javax.ws.rs.core.MediaType.APPLICATION_XML;
+import static javax.ws.rs.core.MediaType.TEXT_PLAIN;
 
 
 @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 final String OBJECT_API_PATH = "buckets/{bucket}/{id}";
+  private static final String OBJECTS_API_PATH = "buckets/{bucket}";
   private static KnoxS3ServiceMessages log = 
MessagesFactory.get(KnoxS3ServiceMessages.class);
   private static final String VERSION_TAG = "v1";
   static final String RESOURCE_PATH = "/knoxs3/" + VERSION_TAG;
@@ -87,14 +115,157 @@ public class S3BucketsResource {
     return props;
   }
 
+  @DELETE
+  @Consumes({APPLICATION_XML, APPLICATION_JSON, TEXT_PLAIN})
+  @Produces({APPLICATION_JSON})
+  @Path(OBJECT_API_PATH)
+  public Response deleteObject(@PathParam("bucket") String bucket,
+      @PathParam("id") String id,
+      @Context HttpHeaders headers) {
+    return getDeleteObjectResponse(bucket, id);
+  }
+
+  private Response getDeleteObjectResponse(String bucket, String id) {
+    response.setStatus(HttpServletResponse.SC_OK);
+    response.setHeader(CACHE_CONTROL, NO_CACHE);
+    response.setContentType(CONTENT_TYPE);
+    PrintWriter writer = null;
+    try {
+      writer = response.getWriter();
+      doDeleteObject(bucket, 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 doDeleteObject(String bucket, String id) {
+    AmazonS3 s3 = getS3Client();
+    s3.deleteObject(bucket, id);
+  }
+
+  @PUT
+  @Consumes({APPLICATION_XML, APPLICATION_JSON, TEXT_PLAIN})
+  @Produces({APPLICATION_JSON})
+  @Path(OBJECT_API_PATH)
+  public Response createObject(@PathParam("bucket") String bucket,
+      @PathParam("id") String id,
+      @Context HttpHeaders headers, String content) {
+    return getCreateObjectResponse(bucket, id, content);
+  }
+
+  private Response getCreateObjectResponse(String bucket, String id, String 
content) {
+    response.setStatus(HttpServletResponse.SC_OK);
+    response.setHeader(CACHE_CONTROL, NO_CACHE);
+    response.setContentType(CONTENT_TYPE);
+    PrintWriter writer = null;
+    try {
+      writer = response.getWriter();
+      doCreateObject(bucket, id, content);
+    } 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 doCreateObject(String bucket, String id, String content) {
+    AmazonS3 s3 = getS3Client();
+    s3.putObject(bucket, id, content);
+  }
+
   @PUT
   @Produces({APPLICATION_JSON})
   @Path(BUCKET_API_PATH)
   public Response createBucket(@PathParam("id") String id) {
+    return getCreateBucketResponse(id);
+  }
+
+  @GET
+  @Produces({APPLICATION_JSON})
+  @Path(OBJECTS_API_PATH)
+  public Response listObjects(@PathParam("bucket") String bucket) {
     // use this to get to idbroker service once moved there
     GatewayServices services = (GatewayServices) request.getServletContext()
         .getAttribute(GatewayServices.GATEWAY_SERVICES_ATTRIBUTE);
-    return getCreateBucketResponse(id);
+    return getListObjectsResponse(bucket);
+  }
+
+  private Response getListObjectsResponse(String bucket) {
+    response.setStatus(HttpServletResponse.SC_OK);
+    response.setHeader(CACHE_CONTROL, NO_CACHE);
+    response.setContentType(CONTENT_TYPE);
+    PrintWriter writer = null;
+    try {
+      writer = response.getWriter();
+      writer.println(doGetObjects(bucket));
+    } 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 doGetObjects(String bucket) {
+    AmazonS3 s3 = getS3Client();
+    Map<String, Object> objectMap = new HashMap<String, Object>();
+    ObjectListing objectListing = s3.listObjects(new ListObjectsRequest()
+        .withBucketName(bucket));
+    for (S3ObjectSummary objectSummary : objectListing.getObjectSummaries()) {
+      objectMap.put(objectSummary.getKey(), objectSummary);
+    }
+    return JsonUtils.renderAsJsonString(objectMap);
+  }
+
+  @GET
+  @Produces({APPLICATION_JSON})
+  @Path(OBJECT_API_PATH)
+  public Response listObjects(@PathParam("bucket") String bucket,
+      @PathParam("id") String id) {
+    return getObjectResponse(bucket, id);
+  }
+
+  private Response getObjectResponse(String bucket, String id) {
+    response.setStatus(HttpServletResponse.SC_OK);
+    response.setHeader(CACHE_CONTROL, NO_CACHE);
+    response.setContentType(CONTENT_TYPE);
+
+    S3Object o = doGetObject(bucket, id);
+    BufferedReader reader = new BufferedReader(new 
InputStreamReader(o.getObjectContent()));
+    StreamingOutput stream = new StreamingOutput() {
+      @Override
+      public void write(OutputStream os) throws IOException,
+      WebApplicationException {
+        Writer writer = new BufferedWriter(new OutputStreamWriter(os));
+        while (true) {
+          String line = reader.readLine();
+          if (line == null) break;
+          writer.write(line);
+        }
+        writer.flush();
+      }
+    };
+    return Response.ok(stream).build();
+  }
+
+  private S3Object doGetObject(String bucket, String id) {
+    AmazonS3 s3 = getS3Client();
+    S3Object object = s3.getObject(new GetObjectRequest(bucket, id));
+//    System.out.println("Content-Type: "  + 
object.getObjectMetadata().getContentType());
+    return object;
   }
 
   private Response getCreateBucketResponse(String id) {
@@ -117,7 +288,7 @@ public class S3BucketsResource {
   }
 
   private void doCreateBucket(String id) {
-    AmazonS3 s3 = s3b.getS3Client();
+    AmazonS3 s3 = getS3Client();
     s3.createBucket(id);
   }
 
@@ -125,9 +296,6 @@ public class S3BucketsResource {
   @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);
 
   }
@@ -152,7 +320,7 @@ public class S3BucketsResource {
   }
 
   private void doDeleteBucket(String id) {
-    AmazonS3 s3 = s3b.getS3Client();
+    AmazonS3 s3 = getS3Client();
     s3.deleteBucket(id);
   }
 
@@ -160,9 +328,6 @@ public class S3BucketsResource {
   @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();
   }
 
@@ -186,14 +351,41 @@ public class S3BucketsResource {
   }
 
   private String getBuckets() {
-    AmazonS3 s3 = s3b.getS3Client();
+    AmazonS3 s3 = 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);
   }
 
+  protected AmazonS3 getS3Client() {
+    HashMap<String, AmazonS3> registry = (HashMap<String, AmazonS3>)
+        context.getAttribute("s3.client.registry");
+
+    if (registry == null) {
+      registry = new HashMap<String, AmazonS3>();
+      context.setAttribute("s3.client.registry", registry);
+    }
+    Subject subject = Subject.getSubject(AccessController.getContext());
+    String username = getEffectiveUserName(subject);
+    AmazonS3 s3 = registry.get(username);
+    if (s3 == null || expired(s3)) {
+      s3 = s3b.getS3Client();
+      registry.put(username, s3);
+    }
+    return s3;
+  }
+
+  private boolean expired(AmazonS3 s3) {
+    // TODO: change to registering a wrapper that keeps track of expiration 
time
+    // return true when a new client should be create for the effective user 
name
+    return false;
+  }
+
+  private String getEffectiveUserName(Subject subject) {
+    return SubjectUtils.getEffectivePrincipalName(subject);
+  }
+
 }

http://git-wip-us.apache.org/repos/asf/knox/blob/18e49c4b/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
index fcfbdd7..14cb164 100644
--- 
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
@@ -16,4 +16,4 @@
 # limitations under the License.
 ##########################################################################
 
-org.apache.knox.gateway.service.health.deploy.HealthServiceDeploymentContributor
\ No newline at end of file
+org.apache.knox.gateway.service.knoxs3.deploy.KnoxS3ServiceDeploymentContributor
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/knox/blob/18e49c4b/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
index d75c7ce..ec7f438 100644
--- 
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
@@ -61,14 +61,14 @@ public class S3BucketsResourceTest {
     
     System.out.println(JsonUtils.renderAsJsonString(policyModel));
     
-    S3PolicyModel model = new S3PolicyModel();
+    AWSPolicyModel model = new AWSPolicyModel();
     model.setEffect("Allow");
     model.addAction("s3:Get*");
     model.addAction("s3:List*");
     model.setResource("*");
     System.out.println(model);
 
-    model = new S3PolicyModel();
+    model = new AWSPolicyModel();
     model.setEffect("Allow");
     model.addAction("s3:Get*");
     model.addAction("s3:List*");

http://git-wip-us.apache.org/repos/asf/knox/blob/18e49c4b/gateway-spi/src/main/java/org/apache/knox/gateway/security/ClientImpersonatedPrincipal.java
----------------------------------------------------------------------
diff --git 
a/gateway-spi/src/main/java/org/apache/knox/gateway/security/ClientImpersonatedPrincipal.java
 
b/gateway-spi/src/main/java/org/apache/knox/gateway/security/ClientImpersonatedPrincipal.java
new file mode 100644
index 0000000..81f131c
--- /dev/null
+++ 
b/gateway-spi/src/main/java/org/apache/knox/gateway/security/ClientImpersonatedPrincipal.java
@@ -0,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.knox.gateway.security;
+
+import java.security.Principal;
+
+public class ClientImpersonatedPrincipal implements Principal {
+  private String name = null;
+
+  public ClientImpersonatedPrincipal(String name) {
+    this.name = name;
+  }
+  
+  public String getName() {
+    return name;
+  }
+
+}

http://git-wip-us.apache.org/repos/asf/knox/blob/18e49c4b/gateway-spi/src/main/java/org/apache/knox/gateway/security/SubjectUtils.java
----------------------------------------------------------------------
diff --git 
a/gateway-spi/src/main/java/org/apache/knox/gateway/security/SubjectUtils.java 
b/gateway-spi/src/main/java/org/apache/knox/gateway/security/SubjectUtils.java
index 3fc51ee..65cf9ea 100644
--- 
a/gateway-spi/src/main/java/org/apache/knox/gateway/security/SubjectUtils.java
+++ 
b/gateway-spi/src/main/java/org/apache/knox/gateway/security/SubjectUtils.java
@@ -70,6 +70,14 @@ public class SubjectUtils {
     return name;
   }
   
+  /**
+   * Determine the effective user name. The order of precedence is:
+   * "mapped, client impersonated, primary. Rationale is that mapping
+   * is how we take actual end users and map them to in cluster users.
+   * Therefore, mapped users take precedence.
+   * @param subject
+   * @return
+   */
   public static String getEffectivePrincipalName(Subject subject) {
     String name = null;
     

http://git-wip-us.apache.org/repos/asf/knox/blob/18e49c4b/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
deleted file mode 100644
index cebfba0..0000000
--- 
a/gateway-spi/src/main/java/org/apache/knox/gateway/services/s3client/KnoxS3ClientBuilder.java
+++ /dev/null
@@ -1,219 +0,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.
- */
-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/18e49c4b/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
deleted file mode 100644
index f7f3084..0000000
--- 
a/gateway-spi/src/main/java/org/apache/knox/gateway/services/s3client/S3PolicyModel.java
+++ /dev/null
@@ -1,60 +0,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.
- */
-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);
-  }
-}

Reply via email to