LENS-1514:Support HDFS delegation token authentication

Project: http://git-wip-us.apache.org/repos/asf/lens/repo
Commit: http://git-wip-us.apache.org/repos/asf/lens/commit/26d8f57a
Tree: http://git-wip-us.apache.org/repos/asf/lens/tree/26d8f57a
Diff: http://git-wip-us.apache.org/repos/asf/lens/diff/26d8f57a

Branch: refs/heads/master
Commit: 26d8f57a21bf281f1152c3b60a6ac425041e83af
Parents: 0edb80f
Author: Rajitha.R <[email protected]>
Authored: Thu May 24 19:56:54 2018 +0530
Committer: Rajitha.R <[email protected]>
Committed: Thu May 24 19:56:54 2018 +0530

----------------------------------------------------------------------
 .../org/apache/lens/api/auth/AuthHeader.java    |  26 ++++
 .../client/DelegationTokenClientFilter.java     |  53 ++++++++
 .../DelegationTokenAuthenticationFilter.java    | 122 +++++++++++++++++++
 3 files changed, 201 insertions(+)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/lens/blob/26d8f57a/lens-api/src/main/java/org/apache/lens/api/auth/AuthHeader.java
----------------------------------------------------------------------
diff --git a/lens-api/src/main/java/org/apache/lens/api/auth/AuthHeader.java 
b/lens-api/src/main/java/org/apache/lens/api/auth/AuthHeader.java
new file mode 100644
index 0000000..ae017d6
--- /dev/null
+++ b/lens-api/src/main/java/org/apache/lens/api/auth/AuthHeader.java
@@ -0,0 +1,26 @@
+/**
+ * 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
+ * <p>
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * <p>
+ * 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.lens.api.auth;
+
+public class AuthHeader {
+  private AuthHeader() {}
+
+  public static final String HDFS_DELEGATION_TKN_HEADER = 
"X-Hadoop-Delegation-Token";
+}

http://git-wip-us.apache.org/repos/asf/lens/blob/26d8f57a/lens-client/src/main/java/org/apache/lens/client/DelegationTokenClientFilter.java
----------------------------------------------------------------------
diff --git 
a/lens-client/src/main/java/org/apache/lens/client/DelegationTokenClientFilter.java
 
b/lens-client/src/main/java/org/apache/lens/client/DelegationTokenClientFilter.java
new file mode 100644
index 0000000..0a11bf6
--- /dev/null
+++ 
b/lens-client/src/main/java/org/apache/lens/client/DelegationTokenClientFilter.java
@@ -0,0 +1,53 @@
+/**
+ * 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
+ * <p>
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * <p>
+ * 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.lens.client;
+
+import static org.apache.lens.api.auth.AuthHeader.HDFS_DELEGATION_TKN_HEADER;
+
+import java.io.IOException;
+import java.util.Optional;
+
+import javax.ws.rs.client.ClientRequestContext;
+import javax.ws.rs.client.ClientRequestFilter;
+
+import org.apache.hadoop.security.UserGroupInformation;
+import org.apache.hadoop.security.token.Token;
+import org.apache.hadoop.security.token.TokenIdentifier;
+
+/**
+ * A client filter for Jersey client which forewards delegation token in 
{@code X-Hadoop-Delegation-Token} header.
+ *
+ * Currently the HDFS_DELEGATION_TOKEN is sent.
+ */
+public class DelegationTokenClientFilter implements ClientRequestFilter {
+  private static final String DELEGATION_TKN_KIND = "HDFS_DELEGATION_TOKEN";
+
+  @Override
+  public void filter(ClientRequestContext requestContext) throws IOException {
+    Optional<Token<? extends TokenIdentifier>> hdfsDelegationToken = 
UserGroupInformation
+      .getLoginUser().getTokens().stream()
+      .filter(tkn -> tkn.getKind().toString().equals(DELEGATION_TKN_KIND))
+      .findFirst();
+
+    if (hdfsDelegationToken.isPresent()) {
+      requestContext.getHeaders().add(HDFS_DELEGATION_TKN_HEADER, 
hdfsDelegationToken.get().encodeToUrlString());
+    }
+  }
+}

http://git-wip-us.apache.org/repos/asf/lens/blob/26d8f57a/lens-server/src/main/java/org/apache/lens/server/auth/DelegationTokenAuthenticationFilter.java
----------------------------------------------------------------------
diff --git 
a/lens-server/src/main/java/org/apache/lens/server/auth/DelegationTokenAuthenticationFilter.java
 
b/lens-server/src/main/java/org/apache/lens/server/auth/DelegationTokenAuthenticationFilter.java
new file mode 100644
index 0000000..2650bc7
--- /dev/null
+++ 
b/lens-server/src/main/java/org/apache/lens/server/auth/DelegationTokenAuthenticationFilter.java
@@ -0,0 +1,122 @@
+/**
+ * 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
+ * <p>
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * <p>
+ * 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.lens.server.auth;
+
+import static org.apache.lens.api.auth.AuthHeader.HDFS_DELEGATION_TKN_HEADER;
+
+import java.io.IOException;
+import java.security.Principal;
+import java.security.PrivilegedExceptionAction;
+
+import javax.annotation.Priority;
+import javax.ws.rs.NotAuthorizedException;
+import javax.ws.rs.container.ContainerRequestContext;
+import javax.ws.rs.container.ContainerRequestFilter;
+import javax.ws.rs.container.ResourceInfo;
+import javax.ws.rs.core.Context;
+import javax.ws.rs.core.Response;
+import javax.ws.rs.core.SecurityContext;
+
+import org.apache.lens.server.LensServerConf;
+
+import org.apache.commons.lang3.StringUtils;
+import org.apache.hadoop.conf.Configuration;
+import org.apache.hadoop.fs.FileSystem;
+import org.apache.hadoop.fs.Path;
+import org.apache.hadoop.security.UserGroupInformation;
+import org.apache.hadoop.security.token.Token;
+import 
org.apache.hadoop.security.token.delegation.AbstractDelegationTokenIdentifier;
+
+import lombok.extern.slf4j.Slf4j;
+
+/**
+ * A JAX-RS filter for delegation token authentication.
+ *
+ * <p>Currently the delegation token of HDFS is received and is passed to HDFS 
using a FS operation to authenticate.
+ * If FS operation returns normally, we assume the user is authenticated.
+ * </p>
+ *
+ * <p>This filter can be enabled by adding an entry in {@code 
lens.server.ws.filternames} property and providing
+ * the impl class.</p>
+ *
+ */
+@Priority(10)
+@Slf4j
+public class DelegationTokenAuthenticationFilter implements 
ContainerRequestFilter {
+  private static final String AUTH_SCHEME = "Digest-MD5";
+  private static final org.apache.hadoop.conf.Configuration CONF = 
LensServerConf.getHiveConf();
+  private static final Path PATH_TO_CHECK = new 
Path(CONF.get("DELEGATION_TOKEN_AUTH_HDFS_PATH_TO_CHECK"));
+
+  private ResourceInfo resourceInfo;;
+
+  @Context
+  public void setResourceInfo(ResourceInfo resourceInfo) {
+    this.resourceInfo = resourceInfo;
+  }
+
+  @Override
+  public void filter(ContainerRequestContext requestContext) throws 
IOException {
+    Principal userPrincipal = 
requestContext.getSecurityContext().getUserPrincipal();
+    if (userPrincipal != null) {
+      log.info("Authentication already done for principal {}, skipping this 
filter...", userPrincipal.getName());
+      return;
+    }
+    // only authenticate when @Authenticate is present on resource
+    if (resourceInfo.getResourceClass() == null || 
resourceInfo.getResourceMethod() == null) {
+      return;
+    }
+    if 
(!(resourceInfo.getResourceClass().isAnnotationPresent(Authenticate.class)
+      || 
resourceInfo.getResourceMethod().isAnnotationPresent(Authenticate.class))) {
+      return;
+    }
+
+    String delegationToken = 
requestContext.getHeaderString(HDFS_DELEGATION_TKN_HEADER);
+    if (StringUtils.isBlank(delegationToken)) {
+      return;
+    }
+
+    Token<AbstractDelegationTokenIdentifier> dt = new Token();
+    dt.decodeFromUrlString(delegationToken);
+    UserGroupInformation user = dt.decodeIdentifier().getUser();
+    user.addToken(dt);
+
+    log.info("Received delegation token for user: {}", user.getUserName());
+
+    try {
+      user.doAs(new PrivilegedExceptionAction<Void>() {
+        @Override
+        public Void run() throws IOException {
+          try (FileSystem fs = FileSystem.get(new Configuration())) {
+            fs.exists(PATH_TO_CHECK); // dummy hdfs call
+            
requestContext.setSecurityContext(createSecurityContext(user.getUserName(), 
AUTH_SCHEME));
+            return null;
+          }
+        }
+      });
+    } catch (InterruptedException | IOException e) {
+      log.error("Error while doing HDFS op: ", e);
+      throw new NotAuthorizedException(Response.status(401).entity("Invalid 
HDFS delegation token").build());
+    }
+  }
+
+  private SecurityContext createSecurityContext(String simpleUserName, String 
authScheme) {
+    return new LensSecurityContext(simpleUserName, authScheme);
+  }
+}

Reply via email to