You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@ranger.apache.org by ga...@apache.org on 2016/04/21 08:20:17 UTC
[2/3] incubator-ranger git commit: RANGER-867 : Add Kerberos support
for ranger admin and clients
http://git-wip-us.apache.org/repos/asf/incubator-ranger/blob/8614032c/security-admin/src/main/java/org/apache/ranger/rest/ServiceREST.java
----------------------------------------------------------------------
diff --git a/security-admin/src/main/java/org/apache/ranger/rest/ServiceREST.java b/security-admin/src/main/java/org/apache/ranger/rest/ServiceREST.java
index c999f86..19a1509 100644
--- a/security-admin/src/main/java/org/apache/ranger/rest/ServiceREST.java
+++ b/security-admin/src/main/java/org/apache/ranger/rest/ServiceREST.java
@@ -52,12 +52,14 @@ import org.apache.ranger.biz.ServiceDBStore;
import org.apache.ranger.biz.ServiceMgr;
import org.apache.ranger.biz.TagDBStore;
import org.apache.ranger.biz.XUserMgr;
+import org.apache.ranger.common.ContextUtil;
import org.apache.ranger.common.GUIDUtil;
import org.apache.ranger.common.MessageEnums;
import org.apache.ranger.common.RESTErrorUtil;
import org.apache.ranger.common.RangerSearchUtil;
import org.apache.ranger.common.RangerValidatorFactory;
import org.apache.ranger.common.ServiceUtil;
+import org.apache.ranger.common.UserSessionBase;
import org.apache.ranger.db.RangerDaoManager;
import org.apache.ranger.entity.XXPolicyExportAudit;
import org.apache.ranger.entity.XXService;
@@ -108,6 +110,8 @@ public class ServiceREST {
final static public String PARAM_SERVICE_NAME = "serviceName";
final static public String PARAM_POLICY_NAME = "policyName";
final static public String PARAM_UPDATE_IF_EXISTS = "updateIfExists";
+ private static final String Allowed_User_List_For_Download = "policy.download.auth.users";
+ private static final String Allowed_User_List_For_Grant_Revoke = "policy.grantrevoke.auth.users";
@Autowired
RESTErrorUtil restErrorUtil;
@@ -441,14 +445,16 @@ public class ServiceREST {
RangerServiceValidator validator = validatorFactory.getServiceValidator(svcStore);
validator.validate(service, Action.CREATE);
- bizUtil.hasAdminPermissions("Services");
+ UserSessionBase session = ContextUtil.getCurrentUserSession();
+ if(session != null && !session.isSpnegoEnabled()){
+ bizUtil.hasAdminPermissions("Services");
- // TODO: As of now we are allowing SYS_ADMIN to create all the
- // services including KMS
-
- XXServiceDef xxServiceDef = daoManager.getXXServiceDef().findByName(service.getType());
- bizUtil.hasKMSPermissions("Service", xxServiceDef.getImplclassname());
+ // TODO: As of now we are allowing SYS_ADMIN to create all the
+ // services including KMS
+ XXServiceDef xxServiceDef = daoManager.getXXServiceDef().findByName(service.getType());
+ bizUtil.hasKMSPermissions("Service", xxServiceDef.getImplclassname());
+ }
ret = svcStore.createService(service);
} catch(WebApplicationException excp) {
throw excp;
@@ -911,6 +917,119 @@ public class ServiceREST {
return ret;
}
+
+ @POST
+ @Path("/secure/services/grant/{serviceName}")
+ @Produces({ "application/json", "application/xml" })
+ public RESTResponse secureGrantAccess(@PathParam("serviceName") String serviceName, GrantRevokeRequest grantRequest, @Context HttpServletRequest request) throws Exception {
+ if(LOG.isDebugEnabled()) {
+ LOG.debug("==> ServiceREST.secureGrantAccess(" + serviceName + ", " + grantRequest + ")");
+ }
+ RESTResponse ret = new RESTResponse();
+ RangerPerfTracer perf = null;
+ boolean isAllowed = false;
+ boolean isKeyAdmin = bizUtil.isKeyAdmin();
+ if (serviceUtil.isValidateHttpsAuthentication(serviceName, request)) {
+ try {
+ if(RangerPerfTracer.isPerfTraceEnabled(PERF_LOG)) {
+ perf = RangerPerfTracer.getPerfTracer(PERF_LOG, "ServiceREST.scureGrantAccess(serviceName=" + serviceName + ")");
+ }
+ String userName = grantRequest.getGrantor();
+ Set<String> userGroups = userMgr.getGroupsForUser(userName);
+ RangerAccessResource resource = new RangerAccessResourceImpl(grantRequest.getResource());
+ boolean isAdmin = hasAdminAccess(serviceName, userName, userGroups, resource);
+
+ if(!isAdmin) {
+ throw restErrorUtil.createRESTException(HttpServletResponse.SC_UNAUTHORIZED, "", true);
+ }
+ // New Code
+ XXService xService = daoManager.getXXService().findByName(serviceName);
+ XXServiceDef xServiceDef = daoManager.getXXServiceDef().getById(xService.getType());
+ RangerService rangerService = svcStore.getServiceByName(serviceName);
+
+ if (StringUtils.equals(xServiceDef.getImplclassname(), EmbeddedServiceDefsUtil.KMS_IMPL_CLASS_NAME)) {
+ if (isKeyAdmin) {
+ isAllowed = true;
+ }else {
+ isAllowed = bizUtil.isUserAllowed(rangerService, Allowed_User_List_For_Grant_Revoke);
+ }
+ }else{
+ if (isAdmin) {
+ isAllowed = true;
+ }
+ else{
+ isAllowed = bizUtil.isUserAllowed(rangerService, Allowed_User_List_For_Grant_Revoke);
+ }
+ }
+ // New Code
+ if (isAllowed) {
+ RangerPolicy policy = getExactMatchPolicyForResource(serviceName, resource);
+
+ if(policy != null) {
+ boolean policyUpdated = false;
+ policyUpdated = ServiceRESTUtil.processGrantRequest(policy, grantRequest);
+
+ if(policyUpdated) {
+ svcStore.updatePolicy(policy);
+ } else {
+ LOG.error("processSecureGrantRequest processing failed");
+ throw new Exception("processSecureGrantRequest processing failed");
+ }
+ } else {
+ policy = new RangerPolicy();
+ policy.setService(serviceName);
+ policy.setName("grant-" + System.currentTimeMillis()); // TODO: better policy name
+ policy.setDescription("created by grant");
+ policy.setIsAuditEnabled(grantRequest.getEnableAudit());
+ policy.setCreatedBy(userName);
+
+ Map<String, RangerPolicyResource> policyResources = new HashMap<String, RangerPolicyResource>();
+ Set<String> resourceNames = resource.getKeys();
+
+ if(! CollectionUtils.isEmpty(resourceNames)) {
+ for(String resourceName : resourceNames) {
+ RangerPolicyResource policyResource = new RangerPolicyResource(resource.getValue(resourceName));
+ policyResource.setIsRecursive(grantRequest.getIsRecursive());
+
+ policyResources.put(resourceName, policyResource);
+ }
+ }
+ policy.setResources(policyResources);
+
+ RangerPolicyItem policyItem = new RangerPolicyItem();
+
+ policyItem.setDelegateAdmin(grantRequest.getDelegateAdmin());
+ policyItem.getUsers().addAll(grantRequest.getUsers());
+ policyItem.getGroups().addAll(grantRequest.getGroups());
+
+ for(String accessType : grantRequest.getAccessTypes()) {
+ policyItem.getAccesses().add(new RangerPolicyItemAccess(accessType, Boolean.TRUE));
+ }
+
+ policy.getPolicyItems().add(policyItem);
+
+ svcStore.createPolicy(policy);
+ }
+ }else{
+ LOG.error("secureGrantAccess(" + serviceName + ", " + grantRequest + ") failed as User doesn't have permission to grant Policy");
+ }
+ } catch(WebApplicationException excp) {
+ throw excp;
+ } catch(Throwable excp) {
+ LOG.error("secureGrantAccess(" + serviceName + ", " + grantRequest + ") failed", excp);
+
+ throw restErrorUtil.createRESTException(excp.getMessage());
+ } finally {
+ RangerPerfTracer.log(perf);
+ }
+
+ ret.setStatusCode(RESTResponse.STATUS_SUCCESS);
+ }
+ if(LOG.isDebugEnabled()) {
+ LOG.debug("<== ServiceREST.secureGrantAccess(" + serviceName + ", " + grantRequest + "): " + ret);
+ }
+ return ret;
+ }
@POST
@Path("/services/revoke/{serviceName}")
@@ -976,6 +1095,86 @@ public class ServiceREST {
}
@POST
+ @Path("/secure/services/revoke/{serviceName}")
+ @Produces({ "application/json", "application/xml" })
+ public RESTResponse secureRevokeAccess(@PathParam("serviceName") String serviceName, GrantRevokeRequest revokeRequest, @Context HttpServletRequest request) throws Exception {
+ if(LOG.isDebugEnabled()) {
+ LOG.debug("==> ServiceREST.secureRevokeAccess(" + serviceName + ", " + revokeRequest + ")");
+ }
+ RESTResponse ret = new RESTResponse();
+ RangerPerfTracer perf = null;
+ if (serviceUtil.isValidateHttpsAuthentication(serviceName,request)) {
+ try {
+ if(RangerPerfTracer.isPerfTraceEnabled(PERF_LOG)) {
+ perf = RangerPerfTracer.getPerfTracer(PERF_LOG, "ServiceREST.secureRevokeAccess(serviceName=" + serviceName + ")");
+ }
+ String userName = revokeRequest.getGrantor();
+ Set<String> userGroups = userMgr.getGroupsForUser(userName);
+ RangerAccessResource resource = new RangerAccessResourceImpl(revokeRequest.getResource());
+ boolean isAdmin = hasAdminAccess(serviceName, userName, userGroups, resource);
+ boolean isAllowed = false;
+ boolean isKeyAdmin = bizUtil.isKeyAdmin();
+ if(!isAdmin) {
+ throw restErrorUtil.createRESTException(HttpServletResponse.SC_UNAUTHORIZED, "", true);
+ }
+
+ XXService xService = daoManager.getXXService().findByName(serviceName);
+ XXServiceDef xServiceDef = daoManager.getXXServiceDef().getById(xService.getType());
+ RangerService rangerService = svcStore.getServiceByName(serviceName);
+
+ if (StringUtils.equals(xServiceDef.getImplclassname(), EmbeddedServiceDefsUtil.KMS_IMPL_CLASS_NAME)) {
+ if (isKeyAdmin) {
+ isAllowed = true;
+ }else {
+ isAllowed = bizUtil.isUserAllowed(rangerService, Allowed_User_List_For_Grant_Revoke);
+ }
+ }else{
+ if (isAdmin) {
+ isAllowed = true;
+ }
+ else{
+ isAllowed = bizUtil.isUserAllowed(rangerService, Allowed_User_List_For_Grant_Revoke);
+ }
+ }
+ // New Code
+ if (isAllowed) {
+ RangerPolicy policy = getExactMatchPolicyForResource(serviceName, resource);
+
+ if(policy != null) {
+ boolean policyUpdated = false;
+ policyUpdated = ServiceRESTUtil.processRevokeRequest(policy, revokeRequest);
+
+ if(policyUpdated) {
+ svcStore.updatePolicy(policy);
+ } else {
+ LOG.error("processSecureRevokeRequest processing failed");
+ throw new Exception("processSecureRevokeRequest processing failed");
+ }
+ } else {
+ // nothing to revoke!
+ }
+ }else{
+ LOG.error("secureRevokeAccess(" + serviceName + ", " + revokeRequest + ") failed as User doesn't have permission to revoke Policy");
+ }
+ } catch(WebApplicationException excp) {
+ throw excp;
+ } catch(Throwable excp) {
+ LOG.error("secureRevokeAccess(" + serviceName + ", " + revokeRequest + ") failed", excp);
+
+ throw restErrorUtil.createRESTException(excp.getMessage());
+ } finally {
+ RangerPerfTracer.log(perf);
+ }
+
+ ret.setStatusCode(RESTResponse.STATUS_SUCCESS);
+ }
+ if(LOG.isDebugEnabled()) {
+ LOG.debug("<== ServiceREST.secureRevokeAccess(" + serviceName + ", " + revokeRequest + "): " + ret);
+ }
+ return ret;
+ }
+
+ @POST
@Path("/policies")
@Produces({ "application/json", "application/xml" })
public RangerPolicy createPolicy(RangerPolicy policy, @Context HttpServletRequest request) {
@@ -1558,7 +1757,6 @@ public class ServiceREST {
logMsg = excp.getMessage();
} finally {
createPolicyDownloadAudit(serviceName, lastKnownVersion, pluginId, httpCode, request);
-
RangerPerfTracer.log(perf);
}
@@ -1574,6 +1772,86 @@ public class ServiceREST {
return ret;
}
+
+ @GET
+ @Path("/secure/policies/download/{serviceName}")
+ @Produces({ "application/json", "application/xml" })
+ public ServicePolicies getSecureServicePoliciesIfUpdated(@PathParam("serviceName") String serviceName,@QueryParam("lastKnownVersion") Long lastKnownVersion,@QueryParam("pluginId") String pluginId,@Context HttpServletRequest request) throws Exception {
+ if (LOG.isDebugEnabled()) {
+ LOG.debug("==> ServiceREST.getSecureServicePoliciesIfUpdated("+ serviceName + ", " + lastKnownVersion + ")");
+ }
+ ServicePolicies ret = null;
+ int httpCode = HttpServletResponse.SC_OK;
+ String logMsg = null;
+ RangerPerfTracer perf = null;
+ boolean isAllowed = false;
+ boolean isAdmin = bizUtil.isAdmin();
+ boolean isKeyAdmin = bizUtil.isKeyAdmin();
+
+ if (serviceUtil.isValidateHttpsAuthentication(serviceName, request)) {
+ if (lastKnownVersion == null) {
+ lastKnownVersion = Long.valueOf(-1);
+ }
+ try {
+ if (RangerPerfTracer.isPerfTraceEnabled(PERF_LOG)) {
+ perf = RangerPerfTracer.getPerfTracer(PERF_LOG,"ServiceREST.getSecureServicePoliciesIfUpdated(serviceName="+ serviceName + ",lastKnownVersion="+ lastKnownVersion + ")");
+ }
+ XXService xService = daoManager.getXXService().findByName(serviceName);
+ XXServiceDef xServiceDef = daoManager.getXXServiceDef().getById(xService.getType());
+ RangerService rangerService = svcStore.getServiceByName(serviceName);
+
+ if (StringUtils.equals(xServiceDef.getImplclassname(), EmbeddedServiceDefsUtil.KMS_IMPL_CLASS_NAME)) {
+ if (isKeyAdmin) {
+ isAllowed = true;
+ }else {
+ isAllowed = bizUtil.isUserAllowed(rangerService, Allowed_User_List_For_Download);
+ if(!isAllowed){
+ isAllowed = bizUtil.isUserAllowed(rangerService, Allowed_User_List_For_Grant_Revoke);
+ }
+ }
+ }else{
+ if (isAdmin) {
+ isAllowed = true;
+ }
+ else{
+ isAllowed = bizUtil.isUserAllowed(rangerService, Allowed_User_List_For_Download);
+ if(!isAllowed){
+ isAllowed = bizUtil.isUserAllowed(rangerService, Allowed_User_List_For_Grant_Revoke);
+ }
+ }
+ }
+ if (isAllowed) {
+ ret = svcStore.getServicePoliciesIfUpdated(serviceName,lastKnownVersion);
+ if (ret == null) {
+ httpCode = HttpServletResponse.SC_NOT_MODIFIED;
+ logMsg = "No change since last update";
+ } else {
+ httpCode = HttpServletResponse.SC_OK;
+ logMsg = "Returning " + (ret.getPolicies() != null ? ret.getPolicies().size() : 0) + " policies. Policy version=" + ret.getPolicyVersion();
+ }
+ } else {
+ LOG.error("getSecureServicePoliciesIfUpdated(" + serviceName + ", " + lastKnownVersion + ") failed as User doesn't have permission to download Policy");
+ httpCode = HttpServletResponse.SC_UNAUTHORIZED;
+ logMsg = "User doesn't have permission to download policy";
+ }
+ } catch (Throwable excp) {
+ LOG.error("getSecureServicePoliciesIfUpdated(" + serviceName + ", " + lastKnownVersion + ") failed", excp);
+ httpCode = HttpServletResponse.SC_BAD_REQUEST;
+ logMsg = excp.getMessage();
+ } finally {
+ createPolicyDownloadAudit(serviceName, lastKnownVersion, pluginId, httpCode, request);
+ RangerPerfTracer.log(perf);
+ }
+ if (httpCode != HttpServletResponse.SC_OK) {
+ boolean logError = httpCode != HttpServletResponse.SC_NOT_MODIFIED;
+ throw restErrorUtil.createRESTException(httpCode, logMsg, logError);
+ }
+ }
+ if (LOG.isDebugEnabled()) {
+ LOG.debug("<== ServiceREST.getSecureServicePoliciesIfUpdated(" + serviceName + ", " + lastKnownVersion + "): count=" + ((ret == null || ret.getPolicies() == null) ? 0 : ret.getPolicies().size()));
+ }
+ return ret;
+ }
private void createPolicyDownloadAudit(String serviceName, Long lastKnownVersion, String pluginId, int httpRespCode, HttpServletRequest request) {
try {
http://git-wip-us.apache.org/repos/asf/incubator-ranger/blob/8614032c/security-admin/src/main/java/org/apache/ranger/rest/TagREST.java
----------------------------------------------------------------------
diff --git a/security-admin/src/main/java/org/apache/ranger/rest/TagREST.java b/security-admin/src/main/java/org/apache/ranger/rest/TagREST.java
index c69ceed..be70cfe 100644
--- a/security-admin/src/main/java/org/apache/ranger/rest/TagREST.java
+++ b/security-admin/src/main/java/org/apache/ranger/rest/TagREST.java
@@ -20,15 +20,22 @@
package org.apache.ranger.rest;
import org.apache.commons.collections.CollectionUtils;
+import org.apache.commons.lang.StringUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
+import org.apache.ranger.biz.RangerBizUtil;
import org.apache.ranger.biz.ServiceDBStore;
import org.apache.ranger.biz.TagDBStore;
import org.apache.ranger.common.RESTErrorUtil;
+import org.apache.ranger.db.RangerDaoManager;
+import org.apache.ranger.entity.XXService;
+import org.apache.ranger.entity.XXServiceDef;
+import org.apache.ranger.plugin.model.RangerService;
import org.apache.ranger.plugin.model.RangerServiceResource;
import org.apache.ranger.plugin.model.RangerTag;
import org.apache.ranger.plugin.model.RangerTagResourceMap;
import org.apache.ranger.plugin.model.RangerTagDef;
+import org.apache.ranger.plugin.store.EmbeddedServiceDefsUtil;
import org.apache.ranger.plugin.store.TagStore;
import org.apache.ranger.plugin.store.TagValidator;
import org.apache.ranger.plugin.util.SearchFilter;
@@ -53,6 +60,7 @@ import java.util.List;
public class TagREST {
private static final Log LOG = LogFactory.getLog(TagREST.class);
+ private static final String Allowed_User_List_For_Tag_Download = "tag.download.auth.users";
@Autowired
RESTErrorUtil restErrorUtil;
@@ -62,6 +70,12 @@ public class TagREST {
@Autowired
TagDBStore tagStore;
+
+ @Autowired
+ RangerDaoManager daoManager;
+
+ @Autowired
+ RangerBizUtil bizUtil;
TagValidator validator;
@@ -1109,4 +1123,70 @@ public class TagREST {
return ret;
}
+
+ @GET
+ @Path(TagRESTConstants.TAGS_SECURE_DOWNLOAD + "{serviceName}")
+ @Produces({ "application/json", "application/xml" })
+ public ServiceTags getSecureServiceTagsIfUpdated(@PathParam("serviceName") String serviceName,
+ @QueryParam(TagRESTConstants.LAST_KNOWN_TAG_VERSION_PARAM) Long lastKnownVersion, @QueryParam("pluginId") String pluginId) {
+ if(LOG.isDebugEnabled()) {
+ LOG.debug("==> TagREST.getSecureServiceTagsIfUpdated(" + serviceName + ", " + lastKnownVersion + ", " + pluginId + ")");
+ }
+
+ ServiceTags ret = null;
+ int httpCode = HttpServletResponse.SC_OK;
+ String logMsg = null;
+ boolean isAllowed = false;
+ boolean isAdmin = bizUtil.isAdmin();
+ boolean isKeyAdmin = bizUtil.isKeyAdmin();
+
+ try {
+ XXService xService = daoManager.getXXService().findByName(serviceName);
+ XXServiceDef xServiceDef = daoManager.getXXServiceDef().getById(xService.getType());
+ RangerService rangerService = svcStore.getServiceByName(serviceName);
+
+ if (StringUtils.equals(xServiceDef.getImplclassname(), EmbeddedServiceDefsUtil.KMS_IMPL_CLASS_NAME)) {
+ if (isKeyAdmin) {
+ isAllowed = true;
+ }else {
+ isAllowed = bizUtil.isUserAllowed(rangerService, Allowed_User_List_For_Tag_Download);
+ }
+ }else{
+ if (isAdmin) {
+ isAllowed = true;
+ }else{
+ isAllowed = bizUtil.isUserAllowed(rangerService, Allowed_User_List_For_Tag_Download);
+ }
+ }
+ if (isAllowed) {
+ ret = tagStore.getServiceTagsIfUpdated(serviceName, lastKnownVersion);
+
+ if(ret == null) {
+ httpCode = HttpServletResponse.SC_NOT_MODIFIED;
+ logMsg = "No change since last update";
+ } else {
+ httpCode = HttpServletResponse.SC_OK;
+ logMsg = "Returning " + (ret.getTags() != null ? ret.getTags().size() : 0) + " tags. Tag version=" + ret.getTagVersion();
+ }
+ }else{
+ // do nothing
+ }
+ } catch(Exception excp) {
+ LOG.error("getSecureServiceTagsIfUpdated(" + serviceName + ") failed", excp);
+
+ httpCode = HttpServletResponse.SC_BAD_REQUEST;
+ logMsg = excp.getMessage();
+ }
+
+ if(httpCode != HttpServletResponse.SC_OK) {
+ boolean logError = httpCode != HttpServletResponse.SC_NOT_MODIFIED;
+ throw restErrorUtil.createRESTException(httpCode, logMsg, logError);
+ }
+
+ if(LOG.isDebugEnabled()) {
+ LOG.debug("<==> TagREST.getSecureServiceTagsIfUpdated(" + serviceName + ", " + lastKnownVersion + ", " + pluginId + ")");
+ }
+
+ return ret;
+ }
}
http://git-wip-us.apache.org/repos/asf/incubator-ranger/blob/8614032c/security-admin/src/main/java/org/apache/ranger/rest/TagRESTConstants.java
----------------------------------------------------------------------
diff --git a/security-admin/src/main/java/org/apache/ranger/rest/TagRESTConstants.java b/security-admin/src/main/java/org/apache/ranger/rest/TagRESTConstants.java
index 919f814..7f836bc 100644
--- a/security-admin/src/main/java/org/apache/ranger/rest/TagRESTConstants.java
+++ b/security-admin/src/main/java/org/apache/ranger/rest/TagRESTConstants.java
@@ -34,6 +34,7 @@ public class TagRESTConstants {
static final String TAGTYPES_RESOURCE = "/types/";
static final String TAGTYPES_LOOKUP_RESOURCE = "/types/lookup/";
static final String TAGS_DOWNLOAD = "/download/";
+ static final String TAGS_SECURE_DOWNLOAD = "/secure/download/";
public static final String SERVICE_NAME_PARAM = "serviceName";
public static final String LAST_KNOWN_TAG_VERSION_PARAM = "lastKnownVersion";
http://git-wip-us.apache.org/repos/asf/incubator-ranger/blob/8614032c/security-admin/src/main/java/org/apache/ranger/security/context/RangerPreAuthSecurityHandler.java
----------------------------------------------------------------------
diff --git a/security-admin/src/main/java/org/apache/ranger/security/context/RangerPreAuthSecurityHandler.java b/security-admin/src/main/java/org/apache/ranger/security/context/RangerPreAuthSecurityHandler.java
index daf732e..899d866 100644
--- a/security-admin/src/main/java/org/apache/ranger/security/context/RangerPreAuthSecurityHandler.java
+++ b/security-admin/src/main/java/org/apache/ranger/security/context/RangerPreAuthSecurityHandler.java
@@ -93,4 +93,13 @@ public class RangerPreAuthSecurityHandler {
throw restErrorUtil.createRESTException(HttpServletResponse.SC_FORBIDDEN, "User is not allowed to access the API", true);
}
+ public boolean isAPISpnegoAccessible(){
+ UserSessionBase userSession = ContextUtil.getCurrentUserSession();
+ if (userSession != null && userSession.isSpnegoEnabled()) {
+ return true;
+ }else if(userSession != null && userSession.isUserAdmin()){
+ return true;
+ }
+ throw restErrorUtil.createRESTException(HttpServletResponse.SC_FORBIDDEN, "User is not allowed to access the API", true);
+ }
}
http://git-wip-us.apache.org/repos/asf/incubator-ranger/blob/8614032c/security-admin/src/main/java/org/apache/ranger/security/web/filter/RangerKRBAuthenticationFilter.java
----------------------------------------------------------------------
diff --git a/security-admin/src/main/java/org/apache/ranger/security/web/filter/RangerKRBAuthenticationFilter.java b/security-admin/src/main/java/org/apache/ranger/security/web/filter/RangerKRBAuthenticationFilter.java
new file mode 100644
index 0000000..c58c987
--- /dev/null
+++ b/security-admin/src/main/java/org/apache/ranger/security/web/filter/RangerKRBAuthenticationFilter.java
@@ -0,0 +1,569 @@
+/*
+ * 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.ranger.security.web.filter;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.MalformedURLException;
+import java.net.URL;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Enumeration;
+import java.util.EventListener;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import javax.servlet.Filter;
+import javax.servlet.FilterChain;
+import javax.servlet.FilterConfig;
+import javax.servlet.FilterRegistration;
+import javax.servlet.RequestDispatcher;
+import javax.servlet.Servlet;
+import javax.servlet.ServletContext;
+import javax.servlet.ServletException;
+import javax.servlet.ServletRegistration;
+import javax.servlet.ServletRequest;
+import javax.servlet.ServletResponse;
+import javax.servlet.SessionCookieConfig;
+import javax.servlet.SessionTrackingMode;
+import javax.servlet.FilterRegistration.Dynamic;
+import javax.servlet.descriptor.JspConfigDescriptor;
+import javax.servlet.http.Cookie;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+import org.apache.commons.collections.iterators.IteratorEnumeration;
+import org.apache.ranger.biz.UserMgr;
+import org.apache.ranger.common.PropertiesUtil;
+import org.apache.ranger.security.handler.RangerAuthenticationProvider;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.security.authentication.AbstractAuthenticationToken;
+import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
+import org.springframework.security.core.Authentication;
+import org.springframework.security.core.GrantedAuthority;
+import org.springframework.security.core.authority.SimpleGrantedAuthority;
+import org.springframework.security.core.context.SecurityContextHolder;
+import org.springframework.security.core.userdetails.User;
+import org.springframework.security.core.userdetails.UserDetails;
+import org.apache.commons.lang.StringUtils;
+import org.apache.hadoop.security.SecureClientLogin;
+import org.springframework.security.web.authentication.WebAuthenticationDetails;
+
+public class RangerKRBAuthenticationFilter extends RangerKrbFilter {
+ Logger LOG = LoggerFactory.getLogger(RangerKRBAuthenticationFilter.class);
+
+ @Autowired
+ UserMgr userMgr;
+
+ static final String NAME_RULES = "hadoop.security.auth_to_local";
+ static final String TOKEN_VALID = "ranger.admin.kerberos.token.valid.seconds";
+ static final String COOKIE_DOMAIN = "ranger.admin.kerberos.cookie.domain";
+ static final String COOKIE_PATH = "ranger.admin.kerberos.cookie.path";
+ static final String PRINCIPAL = "ranger.spnego.kerberos.principal";
+ static final String KEYTAB = "ranger.spnego.kerberos.keytab";
+ static final String NAME_RULES_PARAM = "kerberos.name.rules";
+ static final String TOKEN_VALID_PARAM = "token.validity";
+ static final String COOKIE_DOMAIN_PARAM = "cookie.domain";
+ static final String COOKIE_PATH_PARAM = "cookie.path";
+ static final String PRINCIPAL_PARAM = "kerberos.principal";
+ static final String KEYTAB_PARAM = "kerberos.keytab";
+ static final String AUTH_TYPE = "type";
+ static final String RANGER_AUTH_TYPE = "hadoop.security.authentication";
+ static final String AUTH_COOKIE_NAME = "hadoop.auth";
+ static final String HOST_NAME = "ranger.service.host";
+
+ private static final String KERBEROS_TYPE = "kerberos";
+
+ public RangerKRBAuthenticationFilter() {
+ try {
+ init(null);
+ } catch (ServletException e) {
+ LOG.error("Error while initializing Filter : "+e.getMessage());
+ }
+ }
+
+ @Override
+ public void init(FilterConfig conf) throws ServletException {
+ final FilterConfig globalConf = conf;
+ final Map<String, String> params = new HashMap<String, String>();
+ params.put(AUTH_TYPE, PropertiesUtil.getProperty(RANGER_AUTH_TYPE, "simple"));
+ params.put(NAME_RULES_PARAM, PropertiesUtil.getProperty(NAME_RULES, "DEFAULT"));
+ params.put(TOKEN_VALID_PARAM, PropertiesUtil.getProperty(TOKEN_VALID,"30"));
+ params.put(COOKIE_DOMAIN_PARAM, PropertiesUtil.getProperty(COOKIE_DOMAIN, PropertiesUtil.getProperty(HOST_NAME, "localhost")));
+ params.put(COOKIE_PATH_PARAM, PropertiesUtil.getProperty(COOKIE_PATH, "/"));
+ try {
+ params.put(PRINCIPAL_PARAM, SecureClientLogin.getPrincipal(PropertiesUtil.getProperty(PRINCIPAL,""), PropertiesUtil.getProperty(HOST_NAME)));
+ } catch (IOException ignored) {
+ // do nothing
+ }
+ params.put(KEYTAB_PARAM, PropertiesUtil.getProperty(KEYTAB,""));
+
+ FilterConfig myConf = new FilterConfig() {
+ @Override
+ public ServletContext getServletContext() {
+ if (globalConf != null) {
+ return globalConf.getServletContext();
+ } else {
+ return noContext;
+ }
+ }
+
+ @SuppressWarnings("unchecked")
+ @Override
+ public Enumeration<String> getInitParameterNames() {
+ return new IteratorEnumeration(params.keySet().iterator());
+ }
+
+ @Override
+ public String getInitParameter(String param) {
+ return params.get(param);
+ }
+
+ @Override
+ public String getFilterName() {
+ return "KerberosFilter";
+ }
+ };
+ super.init(myConf);
+ }
+
+ @Override
+ protected void doFilter(FilterChain filterChain,
+ HttpServletRequest request, HttpServletResponse response)
+ throws IOException, ServletException {
+ String authType = PropertiesUtil.getProperty(RANGER_AUTH_TYPE);
+ String userName = null;
+ boolean checkCookie = response.containsHeader("Set-Cookie");
+ if(checkCookie){
+ Collection<String> authUserName = response.getHeaders("Set-Cookie");
+ if(authUserName != null){
+ Iterator<String> i = authUserName.iterator();
+ while(i.hasNext()){
+ String cookie = i.next();
+ if(!StringUtils.isEmpty(cookie)){
+ if(cookie.toLowerCase().startsWith(AUTH_COOKIE_NAME.toLowerCase()) && cookie.contains("u=")){
+ String[] split = cookie.split(";");
+ if(split != null){
+ for(String s : split){
+ if(!StringUtils.isEmpty(s) && s.toLowerCase().startsWith(AUTH_COOKIE_NAME.toLowerCase())){
+ int ustr = s.indexOf("u=");
+ if(ustr != -1){
+ int andStr = s.indexOf("&", ustr);
+ if(andStr != -1){
+ try{
+ userName = s.substring(ustr+2, andStr);
+ }catch(Exception e){
+ userName = null;
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ if((isSpnegoEnable(authType) && (!StringUtils.isEmpty(userName)))){
+ Authentication existingAuth = SecurityContextHolder.getContext().getAuthentication();
+ if(existingAuth == null || !existingAuth.isAuthenticated()){
+ //--------------------------- To Create Ranger Session --------------------------------------
+ String rangerLdapDefaultRole = PropertiesUtil.getProperty("ranger.ldap.default.role", "ROLE_USER");
+ //if we get the userName from the token then log into ranger using the same user
+ final List<GrantedAuthority> grantedAuths = new ArrayList<>();
+ grantedAuths.add(new SimpleGrantedAuthority(rangerLdapDefaultRole));
+ final UserDetails principal = new User(userName, "",grantedAuths);
+ final Authentication finalAuthentication = new UsernamePasswordAuthenticationToken(principal, "", grantedAuths);
+ WebAuthenticationDetails webDetails = new WebAuthenticationDetails(request);
+ ((AbstractAuthenticationToken) finalAuthentication).setDetails(webDetails);
+ RangerAuthenticationProvider authenticationProvider = new RangerAuthenticationProvider();
+ Authentication authentication = authenticationProvider.authenticate(finalAuthentication);
+ authentication = getGrantedAuthority(authentication);
+ SecurityContextHolder.getContext().setAuthentication(authentication);
+ request.setAttribute("spnegoEnabled", true);
+ LOG.info("Logged into Ranger as = "+userName);
+ filterChain.doFilter(request, response);
+ }else{
+ try{
+ super.doFilter(filterChain, request, response);
+ }catch(Exception e){
+ LOG.error("Error RangerKRBAuthenticationFilter : "+e.getMessage());
+ }
+ }
+ }else{
+ filterChain.doFilter(request, response);
+ }
+ }
+
+ @Override
+ public void doFilter(ServletRequest request, ServletResponse response,
+ FilterChain filterChain) throws IOException, ServletException {
+ String authtype = PropertiesUtil.getProperty(RANGER_AUTH_TYPE);
+ HttpServletRequest httpRequest = (HttpServletRequest)request;
+ if(isSpnegoEnable(authtype)){
+ Authentication existingAuth = SecurityContextHolder.getContext().getAuthentication();
+ String userName = null;
+ Cookie[] cookie = httpRequest.getCookies();
+ if(cookie != null){
+ for(Cookie c : cookie){
+ String cname = c.getName();
+ if(cname != null && cname.equalsIgnoreCase("u"))
+ {
+ int ustr = cname.indexOf("u=");
+ if(ustr != -1){
+ int andStr = cname.indexOf("&", ustr);
+ if(andStr != -1){
+ userName = cname.substring(ustr+2, andStr);
+ }
+ }
+ }else if(cname != null && cname.equalsIgnoreCase(AUTH_COOKIE_NAME)){
+ int ustr = cname.indexOf("u=");
+ if(ustr != -1){
+ int andStr = cname.indexOf("&", ustr);
+ if(andStr != -1){
+ userName = cname.substring(ustr+2, andStr);
+ }
+ }
+ }
+ }
+ }
+ if((existingAuth == null || !existingAuth.isAuthenticated()) && (!StringUtils.isEmpty(userName))){
+ //--------------------------- To Create Ranger Session --------------------------------------
+ String rangerLdapDefaultRole = PropertiesUtil.getProperty("ranger.ldap.default.role", "ROLE_USER");
+ //if we get the userName from the token then log into ranger using the same user
+ final List<GrantedAuthority> grantedAuths = new ArrayList<>();
+ grantedAuths.add(new SimpleGrantedAuthority(rangerLdapDefaultRole));
+ final UserDetails principal = new User(userName, "",grantedAuths);
+ final Authentication finalAuthentication = new UsernamePasswordAuthenticationToken(principal, "", grantedAuths);
+ WebAuthenticationDetails webDetails = new WebAuthenticationDetails(httpRequest);
+ ((AbstractAuthenticationToken) finalAuthentication).setDetails(webDetails);
+ RangerAuthenticationProvider authenticationProvider = new RangerAuthenticationProvider();
+ Authentication authentication = authenticationProvider.authenticate(finalAuthentication);
+ authentication = getGrantedAuthority(authentication);
+ SecurityContextHolder.getContext().setAuthentication(authentication);
+ request.setAttribute("spnegoEnabled", true);
+ LOG.info("Logged into Ranger as = "+userName);
+ }else{
+ try{
+ super.doFilter(request, response, filterChain);
+ }catch(Exception e){
+ LOG.error("Error RangerKRBAuthenticationFilter : "+e.getMessage());
+ }
+ }
+ }else{
+ filterChain.doFilter(request, response);
+ }
+ }
+
+ private boolean isSpnegoEnable(String authType){
+ String principal = PropertiesUtil.getProperty(PRINCIPAL);
+ String keytabPath = PropertiesUtil.getProperty(KEYTAB);
+ return ((!StringUtils.isEmpty(authType)) && authType.equalsIgnoreCase(KERBEROS_TYPE) && SecureClientLogin.isKerberosCredentialExists(principal, keytabPath));
+ }
+
+ private Authentication getGrantedAuthority(Authentication authentication) {
+ UsernamePasswordAuthenticationToken result=null;
+ if(authentication!=null && authentication.isAuthenticated()){
+ final List<GrantedAuthority> grantedAuths=getAuthorities(authentication.getName().toString());
+ final UserDetails userDetails = new User(authentication.getName().toString(), authentication.getCredentials().toString(),grantedAuths);
+ result = new UsernamePasswordAuthenticationToken(userDetails,authentication.getCredentials(),grantedAuths);
+ result.setDetails(authentication.getDetails());
+ return result;
+ }
+ return authentication;
+ }
+
+ private List<GrantedAuthority> getAuthorities(String username) {
+ Collection<String> roleList=userMgr.getRolesByLoginId(username);
+ final List<GrantedAuthority> grantedAuths = new ArrayList<>();
+ for(String role:roleList){
+ grantedAuths.add(new SimpleGrantedAuthority(role));
+ }
+ return grantedAuths;
+ }
+
+ protected static ServletContext noContext = new ServletContext() {
+
+ @Override
+ public void setSessionTrackingModes(
+ Set<SessionTrackingMode> sessionTrackingModes) {
+ }
+
+ @Override
+ public boolean setInitParameter(String name, String value) {
+ return false;
+ }
+
+ @Override
+ public void setAttribute(String name, Object object) {
+ }
+
+ @Override
+ public void removeAttribute(String name) {
+ }
+
+ @Override
+ public void log(String message, Throwable throwable) {
+ }
+
+ @Override
+ public void log(Exception exception, String msg) {
+ }
+
+ @Override
+ public void log(String msg) {
+ }
+
+ @Override
+ public String getVirtualServerName() {
+ return null;
+ }
+
+ @Override
+ public SessionCookieConfig getSessionCookieConfig() {
+ return null;
+ }
+
+ @Override
+ public Enumeration<Servlet> getServlets() {
+ return null;
+ }
+
+ @Override
+ public Map<String, ? extends ServletRegistration> getServletRegistrations() {
+ return null;
+ }
+
+ @Override
+ public ServletRegistration getServletRegistration(String servletName) {
+ return null;
+ }
+
+ @Override
+ public Enumeration<String> getServletNames() {
+ return null;
+ }
+
+ @Override
+ public String getServletContextName() {
+ return null;
+ }
+
+ @Override
+ public Servlet getServlet(String name) throws ServletException {
+ return null;
+ }
+
+ @Override
+ public String getServerInfo() {
+ return null;
+ }
+
+ @Override
+ public Set<String> getResourcePaths(String path) {
+ return null;
+ }
+
+ @Override
+ public InputStream getResourceAsStream(String path) {
+ return null;
+ }
+
+ @Override
+ public URL getResource(String path) throws MalformedURLException {
+ return null;
+ }
+
+ @Override
+ public RequestDispatcher getRequestDispatcher(String path) {
+ return null;
+ }
+
+ @Override
+ public String getRealPath(String path) {
+ return null;
+ }
+
+ @Override
+ public RequestDispatcher getNamedDispatcher(String name) {
+ return null;
+ }
+
+ @Override
+ public int getMinorVersion() {
+ return 0;
+ }
+
+ @Override
+ public String getMimeType(String file) {
+ return null;
+ }
+
+ @Override
+ public int getMajorVersion() {
+ return 0;
+ }
+
+ @Override
+ public JspConfigDescriptor getJspConfigDescriptor() {
+ return null;
+ }
+
+ @Override
+ public Enumeration<String> getInitParameterNames() {
+ return null;
+ }
+
+ @Override
+ public String getInitParameter(String name) {
+ return null;
+ }
+
+ @Override
+ public Map<String, ? extends FilterRegistration> getFilterRegistrations() {
+ return null;
+ }
+
+ @Override
+ public FilterRegistration getFilterRegistration(String filterName) {
+ return null;
+ }
+
+ @Override
+ public Set<SessionTrackingMode> getEffectiveSessionTrackingModes() {
+ return null;
+ }
+
+ @Override
+ public int getEffectiveMinorVersion() {
+ return 0;
+ }
+
+ @Override
+ public int getEffectiveMajorVersion() {
+ return 0;
+ }
+
+ @Override
+ public Set<SessionTrackingMode> getDefaultSessionTrackingModes() {
+ return null;
+ }
+
+ @Override
+ public String getContextPath() {
+ return null;
+ }
+
+ @Override
+ public ServletContext getContext(String uripath) {
+ return null;
+ }
+
+ @Override
+ public ClassLoader getClassLoader() {
+ return null;
+ }
+
+ @Override
+ public Enumeration<String> getAttributeNames() {
+ return null;
+ }
+
+ @Override
+ public Object getAttribute(String name) {
+ return null;
+ }
+
+ @Override
+ public void declareRoles(String... roleNames) {
+ }
+
+ @Override
+ public <T extends Servlet> T createServlet(Class<T> clazz)
+ throws ServletException {
+ return null;
+ }
+
+ @Override
+ public <T extends EventListener> T createListener(Class<T> clazz)
+ throws ServletException {
+ return null;
+ }
+
+ @Override
+ public <T extends Filter> T createFilter(Class<T> clazz)
+ throws ServletException {
+ return null;
+ }
+
+ @Override
+ public javax.servlet.ServletRegistration.Dynamic addServlet(
+ String servletName, Class<? extends Servlet> servletClass) {
+ return null;
+ }
+
+ @Override
+ public javax.servlet.ServletRegistration.Dynamic addServlet(
+ String servletName, Servlet servlet) {
+ return null;
+ }
+
+ @Override
+ public javax.servlet.ServletRegistration.Dynamic addServlet(
+ String servletName, String className) {
+ return null;
+ }
+
+ @Override
+ public void addListener(Class<? extends EventListener> listenerClass) {
+ }
+
+ @Override
+ public <T extends EventListener> void addListener(T t) {
+ }
+
+ @Override
+ public void addListener(String className) {
+ }
+
+ @Override
+ public Dynamic addFilter(String filterName,
+ Class<? extends Filter> filterClass) {
+ return null;
+ }
+
+ @Override
+ public Dynamic addFilter(String filterName, Filter filter) {
+ return null;
+ }
+
+ @Override
+ public Dynamic addFilter(String filterName, String className) {
+ return null;
+ }
+ };
+
+}
http://git-wip-us.apache.org/repos/asf/incubator-ranger/blob/8614032c/security-admin/src/main/java/org/apache/ranger/security/web/filter/RangerKrbFilter.java
----------------------------------------------------------------------
diff --git a/security-admin/src/main/java/org/apache/ranger/security/web/filter/RangerKrbFilter.java b/security-admin/src/main/java/org/apache/ranger/security/web/filter/RangerKrbFilter.java
new file mode 100644
index 0000000..88ab020
--- /dev/null
+++ b/security-admin/src/main/java/org/apache/ranger/security/web/filter/RangerKrbFilter.java
@@ -0,0 +1,576 @@
+/**
+ * Licensed 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. See accompanying LICENSE file.
+ */
+package org.apache.ranger.security.web.filter;
+
+import org.apache.commons.lang.StringUtils;
+import org.apache.hadoop.classification.InterfaceAudience;
+import org.apache.hadoop.classification.InterfaceStability;
+import org.apache.hadoop.security.authentication.client.AuthenticatedURL;
+import org.apache.hadoop.security.authentication.client.AuthenticationException;
+import org.apache.hadoop.security.authentication.client.KerberosAuthenticator;
+import org.apache.hadoop.security.authentication.server.AuthenticationHandler;
+import org.apache.hadoop.security.authentication.server.AuthenticationToken;
+import org.apache.hadoop.security.authentication.server.KerberosAuthenticationHandler;
+import org.apache.hadoop.security.authentication.server.PseudoAuthenticationHandler;
+import org.apache.hadoop.security.authentication.util.*;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import javax.servlet.Filter;
+import javax.servlet.FilterChain;
+import javax.servlet.FilterConfig;
+import javax.servlet.ServletContext;
+import javax.servlet.ServletException;
+import javax.servlet.ServletRequest;
+import javax.servlet.ServletResponse;
+import javax.servlet.http.Cookie;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletRequestWrapper;
+import javax.servlet.http.HttpServletResponse;
+
+import java.io.IOException;
+import java.security.Principal;
+import java.text.SimpleDateFormat;
+import java.util.*;
+
+@InterfaceAudience.Private
+@InterfaceStability.Unstable
+public class RangerKrbFilter implements Filter {
+
+ private static Logger LOG = LoggerFactory.getLogger(RangerKrbFilter.class);
+
+ /**
+ * Constant for the property that specifies the configuration prefix.
+ */
+ public static final String CONFIG_PREFIX = "config.prefix";
+
+ /**
+ * Constant for the property that specifies the authentication handler to use.
+ */
+ public static final String AUTH_TYPE = "type";
+
+ /**
+ * Constant for the property that specifies the secret to use for signing the HTTP Cookies.
+ */
+ public static final String SIGNATURE_SECRET = "signature.secret";
+
+ public static final String SIGNATURE_SECRET_FILE = SIGNATURE_SECRET + ".file";
+
+ /**
+ * Constant for the configuration property that indicates the validity of the generated token.
+ */
+ public static final String AUTH_TOKEN_VALIDITY = "token.validity";
+
+ /**
+ * Constant for the configuration property that indicates the domain to use in the HTTP cookie.
+ */
+ public static final String COOKIE_DOMAIN = "cookie.domain";
+
+ /**
+ * Constant for the configuration property that indicates the path to use in the HTTP cookie.
+ */
+ public static final String COOKIE_PATH = "cookie.path";
+
+ /**
+ * Constant for the configuration property that indicates the name of the
+ * SignerSecretProvider class to use.
+ * Possible values are: "string", "random", "zookeeper", or a classname.
+ * If not specified, the "string" implementation will be used with
+ * SIGNATURE_SECRET; and if that's not specified, the "random" implementation
+ * will be used.
+ */
+ public static final String SIGNER_SECRET_PROVIDER =
+ "signer.secret.provider";
+
+ /**
+ * Constant for the ServletContext attribute that can be used for providing a
+ * custom implementation of the SignerSecretProvider. Note that the class
+ * should already be initialized. If not specified, SIGNER_SECRET_PROVIDER
+ * will be used.
+ */
+ public static final String SIGNER_SECRET_PROVIDER_ATTRIBUTE =
+ "signer.secret.provider.object";
+
+ private Properties config;
+ private Signer signer;
+ private SignerSecretProvider secretProvider;
+ private AuthenticationHandler authHandler;
+ private long validity;
+ private String cookieDomain;
+ private String cookiePath;
+
+ /**
+ * <p>Initializes the authentication filter and signer secret provider.</p>
+ * It instantiates and initializes the specified {@link
+ * AuthenticationHandler}.
+ *
+ * @param filterConfig filter configuration.
+ *
+ * @throws ServletException thrown if the filter or the authentication handler could not be initialized properly.
+ */
+ @Override
+ public void init(FilterConfig filterConfig) throws ServletException {
+ String configPrefix = filterConfig.getInitParameter(CONFIG_PREFIX);
+ configPrefix = (configPrefix != null) ? configPrefix + "." : "";
+ config = getConfiguration(configPrefix, filterConfig);
+ String authHandlerName = config.getProperty(AUTH_TYPE, null);
+ String authHandlerClassName;
+ if (authHandlerName == null) {
+ throw new ServletException("Authentication type must be specified: " +
+ PseudoAuthenticationHandler.TYPE + "|" +
+ KerberosAuthenticationHandler.TYPE + "|<class>");
+ }
+ if(StringUtils.equalsIgnoreCase(authHandlerName, PseudoAuthenticationHandler.TYPE)){
+ authHandlerClassName = PseudoAuthenticationHandler.class.getName();
+ }else if(StringUtils.equalsIgnoreCase(authHandlerName, KerberosAuthenticationHandler.TYPE)){
+ authHandlerClassName = KerberosAuthenticationHandler.class.getName();
+ } else {
+ authHandlerClassName = authHandlerName;
+ }
+
+ validity = Long.parseLong(config.getProperty(AUTH_TOKEN_VALIDITY, "36000"))
+ * 1000; //10 hours
+ initializeSecretProvider(filterConfig);
+
+ initializeAuthHandler(authHandlerClassName, filterConfig);
+
+ cookieDomain = config.getProperty(COOKIE_DOMAIN, null);
+ cookiePath = config.getProperty(COOKIE_PATH, null);
+ }
+
+ protected void initializeAuthHandler(String authHandlerClassName, FilterConfig filterConfig)
+ throws ServletException {
+ try {
+ Class<?> klass = Thread.currentThread().getContextClassLoader().loadClass(authHandlerClassName);
+ authHandler = (AuthenticationHandler) klass.newInstance();
+ authHandler.init(config);
+ } catch (ClassNotFoundException | InstantiationException |
+ IllegalAccessException ex) {
+ throw new ServletException(ex);
+ }
+ }
+
+ protected void initializeSecretProvider(FilterConfig filterConfig)
+ throws ServletException {
+ secretProvider = (SignerSecretProvider) filterConfig.getServletContext().
+ getAttribute(SIGNER_SECRET_PROVIDER_ATTRIBUTE);
+ if (secretProvider == null) {
+ // As tomcat cannot specify the provider object in the configuration.
+ // It'll go into this path
+ try {
+ secretProvider = constructSecretProvider(
+ filterConfig.getServletContext(),
+ config, false);
+ } catch (Exception ex) {
+ throw new ServletException(ex);
+ }
+ }
+ signer = new Signer(secretProvider);
+ }
+
+ public static SignerSecretProvider constructSecretProvider(
+ ServletContext ctx, Properties config,
+ boolean disallowFallbackToRandomSecretProvider) throws Exception {
+ long validity = Long.parseLong(config.getProperty(AUTH_TOKEN_VALIDITY,
+ "36000")) * 1000;
+
+ String name = config.getProperty(SIGNER_SECRET_PROVIDER);
+ if (StringUtils.isEmpty(name)) {
+ if (!disallowFallbackToRandomSecretProvider) {
+ name = "random";
+ } else {
+ name = "file";
+ }
+ }
+
+ SignerSecretProvider provider;
+ if ("file".equals(name)) {
+ provider = new FileSignerSecretProvider();
+ try {
+ provider.init(config, ctx, validity);
+ } catch (Exception e) {
+ if (!disallowFallbackToRandomSecretProvider) {
+ LOG.info("Unable to initialize FileSignerSecretProvider, " +
+ "falling back to use random secrets.");
+ provider = new RandomSignerSecretProvider();
+ provider.init(config, ctx, validity);
+ } else {
+ throw e;
+ }
+ }
+ } else if ("random".equals(name)) {
+ provider = new RandomSignerSecretProvider();
+ provider.init(config, ctx, validity);
+ } else if ("zookeeper".equals(name)) {
+ provider = new ZKSignerSecretProvider();
+ provider.init(config, ctx, validity);
+ } else {
+ provider = (SignerSecretProvider) Thread.currentThread().
+ getContextClassLoader().loadClass(name).newInstance();
+ provider.init(config, ctx, validity);
+ }
+ return provider;
+ }
+
+ /**
+ * Returns the configuration properties of the {@link RangerKrbFilter}
+ * without the prefix. The returned properties are the same that the
+ * {@link #getConfiguration(String, FilterConfig)} method returned.
+ *
+ * @return the configuration properties.
+ */
+ protected Properties getConfiguration() {
+ return config;
+ }
+
+ /**
+ * Returns the authentication handler being used.
+ *
+ * @return the authentication handler being used.
+ */
+ protected AuthenticationHandler getAuthenticationHandler() {
+ return authHandler;
+ }
+
+ /**
+ * Returns if a random secret is being used.
+ *
+ * @return if a random secret is being used.
+ */
+ protected boolean isRandomSecret() {
+ return secretProvider != null && secretProvider.getClass() == RandomSignerSecretProvider.class;
+ }
+
+ /**
+ * Returns if a custom implementation of a SignerSecretProvider is being used.
+ *
+ * @return if a custom implementation of a SignerSecretProvider is being used.
+ */
+ protected boolean isCustomSignerSecretProvider() {
+ Class<?> clazz = secretProvider != null ? secretProvider.getClass() : null;
+ return clazz != FileSignerSecretProvider.class && clazz !=
+ RandomSignerSecretProvider.class && clazz != ZKSignerSecretProvider
+ .class;
+ }
+
+ /**
+ * Returns the validity time of the generated tokens.
+ *
+ * @return the validity time of the generated tokens, in seconds.
+ */
+ protected long getValidity() {
+ return validity / 1000;
+ }
+
+ /**
+ * Returns the cookie domain to use for the HTTP cookie.
+ *
+ * @return the cookie domain to use for the HTTP cookie.
+ */
+ protected String getCookieDomain() {
+ return cookieDomain;
+ }
+
+ /**
+ * Returns the cookie path to use for the HTTP cookie.
+ *
+ * @return the cookie path to use for the HTTP cookie.
+ */
+ protected String getCookiePath() {
+ return cookiePath;
+ }
+
+ /**
+ * Destroys the filter.
+ * <p>
+ * It invokes the {@link AuthenticationHandler#destroy()} method to release any resources it may hold.
+ */
+ @Override
+ public void destroy() {
+ if (authHandler != null) {
+ authHandler.destroy();
+ authHandler = null;
+ }
+ }
+
+ /**
+ * Returns the filtered configuration (only properties starting with the specified prefix). The property keys
+ * are also trimmed from the prefix. The returned {@link Properties} object is used to initialized the
+ * {@link AuthenticationHandler}.
+ * <p>
+ * This method can be overriden by subclasses to obtain the configuration from other configuration source than
+ * the web.xml file.
+ *
+ * @param configPrefix configuration prefix to use for extracting configuration properties.
+ * @param filterConfig filter configuration object
+ *
+ * @return the configuration to be used with the {@link AuthenticationHandler} instance.
+ *
+ * @throws ServletException thrown if the configuration could not be created.
+ */
+ protected Properties getConfiguration(String configPrefix, FilterConfig filterConfig) throws ServletException {
+ Properties props = new Properties();
+ if(filterConfig != null){
+ Enumeration<?> names = filterConfig.getInitParameterNames();
+ if(names != null){
+ while (names.hasMoreElements()) {
+ String name = (String) names.nextElement();
+ if (name != null && configPrefix != null && name.startsWith(configPrefix)) {
+ String value = filterConfig.getInitParameter(name);
+ props.put(name.substring(configPrefix.length()), value);
+ }
+ }
+ }
+ }
+ return props;
+ }
+
+ /**
+ * Returns the full URL of the request including the query string.
+ * <p>
+ * Used as a convenience method for logging purposes.
+ *
+ * @param request the request object.
+ *
+ * @return the full URL of the request including the query string.
+ */
+ protected String getRequestURL(HttpServletRequest request) {
+ StringBuffer sb = request.getRequestURL();
+ if (request.getQueryString() != null) {
+ sb.append("?").append(request.getQueryString());
+ }
+ return sb.toString();
+ }
+
+ /**
+ * Returns the {@link AuthenticationToken} for the request.
+ * <p>
+ * It looks at the received HTTP cookies and extracts the value of the {@link AuthenticatedURL#AUTH_COOKIE}
+ * if present. It verifies the signature and if correct it creates the {@link AuthenticationToken} and returns
+ * it.
+ * <p>
+ * If this method returns <code>null</code> the filter will invoke the configured {@link AuthenticationHandler}
+ * to perform user authentication.
+ *
+ * @param request request object.
+ *
+ * @return the Authentication token if the request is authenticated, <code>null</code> otherwise.
+ *
+ * @throws IOException thrown if an IO error occurred.
+ * @throws AuthenticationException thrown if the token is invalid or if it has expired.
+ */
+ protected AuthenticationToken getToken(HttpServletRequest request) throws IOException, AuthenticationException {
+ AuthenticationToken token = null;
+ String tokenStr = null;
+ Cookie[] cookies = request.getCookies();
+ if (cookies != null) {
+ for (Cookie cookie : cookies) {
+ if (AuthenticatedURL.AUTH_COOKIE.equals(cookie.getName())) {
+ tokenStr = cookie.getValue();
+ try {
+ tokenStr = signer.verifyAndExtract(tokenStr);
+ } catch (SignerException ex) {
+ throw new AuthenticationException(ex);
+ }
+ break;
+ }
+ }
+ }
+ if (tokenStr != null) {
+ token = AuthenticationToken.parse(tokenStr);
+ if(token != null){
+ if (!token.getType().equals(authHandler.getType())) {
+ throw new AuthenticationException("Invalid AuthenticationToken type");
+ }
+ if (token.isExpired()) {
+ throw new AuthenticationException("AuthenticationToken expired");
+ }
+ }
+ }
+ return token;
+ }
+
+ /**
+ * If the request has a valid authentication token it allows the request to continue to the target resource,
+ * otherwise it triggers an authentication sequence using the configured {@link AuthenticationHandler}.
+ *
+ * @param request the request object.
+ * @param response the response object.
+ * @param filterChain the filter chain object.
+ *
+ * @throws IOException thrown if an IO error occurred.
+ * @throws ServletException thrown if a processing error occurred.
+ */
+ @Override
+ public void doFilter(ServletRequest request, ServletResponse response, FilterChain filterChain)
+ throws IOException, ServletException {
+ boolean unauthorizedResponse = true;
+ int errCode = HttpServletResponse.SC_UNAUTHORIZED;
+ AuthenticationException authenticationEx = null;
+ HttpServletRequest httpRequest = (HttpServletRequest) request;
+ HttpServletResponse httpResponse = (HttpServletResponse) response;
+ boolean isHttps = "https".equals(httpRequest.getScheme());
+ try {
+ boolean newToken = false;
+ AuthenticationToken token;
+ try {
+ token = getToken(httpRequest);
+ }
+ catch (AuthenticationException ex) {
+ ex.printStackTrace();
+ LOG.warn("AuthenticationToken ignored: " + ex.getMessage());
+ // will be sent back in a 401 unless filter authenticates
+ authenticationEx = ex;
+ token = null;
+ }
+ if (authHandler.managementOperation(token, httpRequest, httpResponse)) {
+ if (token == null) {
+ if (LOG.isDebugEnabled()) {
+ LOG.debug("Request [{}] triggering authentication", getRequestURL(httpRequest));
+ }
+ token = authHandler.authenticate(httpRequest, httpResponse);
+ if (token != null && token.getExpires() != 0 &&
+ token != AuthenticationToken.ANONYMOUS) {
+ token.setExpires(System.currentTimeMillis() + getValidity() * 1000);
+ }
+ newToken = true;
+ }
+ if (token != null) {
+ unauthorizedResponse = false;
+ if (LOG.isDebugEnabled()) {
+ LOG.debug("Request [{}] user [{}] authenticated", getRequestURL(httpRequest), token.getUserName());
+ }
+ final AuthenticationToken authToken = token;
+ httpRequest = new HttpServletRequestWrapper(httpRequest) {
+
+ @Override
+ public String getAuthType() {
+ return authToken.getType();
+ }
+
+ @Override
+ public String getRemoteUser() {
+ return authToken.getUserName();
+ }
+
+ @Override
+ public Principal getUserPrincipal() {
+ return (authToken != AuthenticationToken.ANONYMOUS) ? authToken : null;
+ }
+ };
+ if (newToken && !token.isExpired() && token != AuthenticationToken.ANONYMOUS) {
+ String signedToken = signer.sign(token.toString());
+ createAuthCookie(httpResponse, signedToken, getCookieDomain(),
+ getCookiePath(), token.getExpires(), isHttps);
+ }
+ doFilter(filterChain, httpRequest, httpResponse);
+ }
+ } else {
+ unauthorizedResponse = false;
+ }
+ } catch (AuthenticationException ex) {
+ // exception from the filter itself is fatal
+ ex.printStackTrace();
+ errCode = HttpServletResponse.SC_FORBIDDEN;
+ authenticationEx = ex;
+ LOG.warn("Authentication exception: " + ex.getMessage(), ex);
+ }
+ if (unauthorizedResponse) {
+ if (!httpResponse.isCommitted()) {
+ createAuthCookie(httpResponse, "", getCookieDomain(),
+ getCookiePath(), 0, isHttps);
+ // If response code is 401. Then WWW-Authenticate Header should be
+ // present.. reset to 403 if not found..
+ if ((errCode == HttpServletResponse.SC_UNAUTHORIZED)
+ && (!httpResponse.containsHeader(
+ KerberosAuthenticator.WWW_AUTHENTICATE))) {
+ errCode = HttpServletResponse.SC_FORBIDDEN;
+ }
+ if (authenticationEx == null) {
+ boolean chk = true;
+ Collection<String> headerNames = httpResponse.getHeaderNames();
+ for(String headerName : headerNames){
+ String value = httpResponse.getHeader(headerName);
+ if(headerName.equalsIgnoreCase("Set-Cookie") && value.startsWith("JSESSIONID")){
+ chk = false;
+ break;
+ }
+ }
+ String authHeader = httpRequest.getHeader("Authorization");
+ if(authHeader == null && chk){
+ filterChain.doFilter(request, response);
+ }else if(authHeader != null && authHeader.startsWith("Basic")){
+ filterChain.doFilter(request, response);
+ }
+ } else {
+ httpResponse.sendError(errCode, authenticationEx.getMessage());
+ }
+ }
+ }
+ }
+
+ /**
+ * Delegates call to the servlet filter chain. Sub-classes my override this
+ * method to perform pre and post tasks.
+ */
+ protected void doFilter(FilterChain filterChain, HttpServletRequest request,
+ HttpServletResponse response) throws IOException, ServletException {
+ filterChain.doFilter(request, response);
+ }
+
+ /**
+ * Creates the Hadoop authentication HTTP cookie.
+ *
+ * @param token authentication token for the cookie.
+ * @param expires UNIX timestamp that indicates the expire date of the
+ * cookie. It has no effect if its value < 0.
+ *
+ * XXX the following code duplicate some logic in Jetty / Servlet API,
+ * because of the fact that Hadoop is stuck at servlet 2.5 and jetty 6
+ * right now.
+ */
+ public static void createAuthCookie(HttpServletResponse resp, String token,
+ String domain, String path, long expires,
+ boolean isSecure) {
+ StringBuilder sb = new StringBuilder(AuthenticatedURL.AUTH_COOKIE)
+ .append("=");
+ if (token != null && token.length() > 0) {
+ sb.append("\"").append(token).append("\"");
+ }
+
+ if (path != null) {
+ sb.append("; Path=").append(path);
+ }
+
+ if (domain != null) {
+ sb.append("; Domain=").append(domain);
+ }
+
+ if (expires >= 0) {
+ Date date = new Date(expires);
+ SimpleDateFormat df = new SimpleDateFormat("EEE, " +
+ "dd-MMM-yyyy HH:mm:ss zzz");
+ df.setTimeZone(TimeZone.getTimeZone("GMT"));
+ sb.append("; Expires=").append(df.format(date));
+ }
+
+ if (isSecure) {
+ sb.append("; Secure");
+ }
+
+ sb.append("; HttpOnly");
+ resp.addHeader("Set-Cookie", sb.toString());
+ }
+}
+
http://git-wip-us.apache.org/repos/asf/incubator-ranger/blob/8614032c/security-admin/src/main/resources/conf.dist/ranger-admin-site.xml
----------------------------------------------------------------------
diff --git a/security-admin/src/main/resources/conf.dist/ranger-admin-site.xml b/security-admin/src/main/resources/conf.dist/ranger-admin-site.xml
index b2ec9de..7d748c5 100644
--- a/security-admin/src/main/resources/conf.dist/ranger-admin-site.xml
+++ b/security-admin/src/main/resources/conf.dist/ranger-admin-site.xml
@@ -233,4 +233,42 @@
<value>Mozilla,chrome</value>
</property>
<!-- SSO Properties Ends-->
+ <!-- Kerberos Properties starts-->
+ <property>
+ <name>ranger.admin.kerberos.token.valid.seconds</name>
+ <value>30</value>
+ </property>
+ <property>
+ <name>ranger.admin.kerberos.cookie.domain</name>
+ <value></value>
+ </property>
+ <property>
+ <name>ranger.admin.kerberos.cookie.path</name>
+ <value>/</value>
+ </property>
+ <property>
+ <name>ranger.admin.kerberos.principal</name>
+ <value>rangeradmin/_HOST@REALM</value>
+ </property>
+ <property>
+ <name>ranger.admin.kerberos.keytab</name>
+ <value></value>
+ </property>
+ <property>
+ <name>ranger.spnego.kerberos.principal</name>
+ <value>HTTP/_HOST@REALM</value>
+ </property>
+ <property>
+ <name>ranger.spnego.kerberos.keytab</name>
+ <value></value>
+ </property>
+ <property>
+ <name>ranger.lookup.kerberos.principal</name>
+ <value>rangerlookup/_HOST@REALM</value>
+ </property>
+ <property>
+ <name>ranger.lookup.kerberos.keytab</name>
+ <value></value>
+ </property>
+ <!-- Kerberos Properties ENDs-->
</configuration>
http://git-wip-us.apache.org/repos/asf/incubator-ranger/blob/8614032c/security-admin/src/main/resources/conf.dist/security-applicationContext.xml
----------------------------------------------------------------------
diff --git a/security-admin/src/main/resources/conf.dist/security-applicationContext.xml b/security-admin/src/main/resources/conf.dist/security-applicationContext.xml
index 2f711ad..6becfcd 100644
--- a/security-admin/src/main/resources/conf.dist/security-applicationContext.xml
+++ b/security-admin/src/main/resources/conf.dist/security-applicationContext.xml
@@ -36,6 +36,7 @@ http://www.springframework.org/schema/security/spring-security-oauth2-1.0.xsd">
<security:http pattern="/scripts/**" security="none" />
<security:http pattern="/libs/**" security="none" />
<security:http pattern="/images/**" security="none" />
+ <security:http pattern="/templates/**" security="none" />
<security:http pattern="/service/assets/policyList/*" security="none"/>
<security:http pattern="/service/assets/resources/grant" security="none"/>
<security:http pattern="/service/assets/resources/revoke" security="none"/>
@@ -48,7 +49,7 @@ http://www.springframework.org/schema/security/spring-security-oauth2-1.0.xsd">
<security:session-management session-fixation-protection="newSession" />
<intercept-url pattern="/**" access="isAuthenticated()"/>
<custom-filter ref="ssoAuthenticationFilter" after="BASIC_AUTH_FILTER" />
-
+ <security:custom-filter ref="krbAuthenticationFilter" after="SERVLET_API_SUPPORT_FILTER" />
<security:custom-filter position="FORM_LOGIN_FILTER" ref="customUsernamePasswordAuthenticationFilter"/>
<security:custom-filter position="LAST" ref="userContextFormationFilter"/>
@@ -89,7 +90,10 @@ http://www.springframework.org/schema/security/spring-security-oauth2-1.0.xsd">
<beans:bean id="customLogoutSuccessHandler" class="org.apache.ranger.security.web.authentication.CustomLogoutSuccessHandler">
</beans:bean>
- <beans:bean id="ssoAuthenticationFilter" class="org.apache.ranger.security.web.filter.RangerSSOAuthenticationFilter">
+ <beans:bean id="krbAuthenticationFilter" class="org.apache.ranger.security.web.filter.RangerKRBAuthenticationFilter">
+ </beans:bean>
+
+ <beans:bean id="ssoAuthenticationFilter" class="org.apache.ranger.security.web.filter.RangerSSOAuthenticationFilter">
</beans:bean>
<beans:bean id="userContextFormationFilter" class="org.apache.ranger.security.web.filter.RangerSecurityContextFormationFilter"/>
http://git-wip-us.apache.org/repos/asf/incubator-ranger/blob/8614032c/security-admin/src/main/resources/resourcenamemap.properties
----------------------------------------------------------------------
diff --git a/security-admin/src/main/resources/resourcenamemap.properties b/security-admin/src/main/resources/resourcenamemap.properties
index 201c0fa..16bf704 100644
--- a/security-admin/src/main/resources/resourcenamemap.properties
+++ b/security-admin/src/main/resources/resourcenamemap.properties
@@ -16,3 +16,5 @@
username=xalogin.xml
keytabfile=xalogin.xml
password=xalogin.xml
+lookupprincipal=xalogin.xml
+lookupkeytab=xalogin.xml
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/incubator-ranger/blob/8614032c/security-admin/src/main/webapp/META-INF/applicationContext.xml
----------------------------------------------------------------------
diff --git a/security-admin/src/main/webapp/META-INF/applicationContext.xml b/security-admin/src/main/webapp/META-INF/applicationContext.xml
index c1a9387..17f35a2 100644
--- a/security-admin/src/main/webapp/META-INF/applicationContext.xml
+++ b/security-admin/src/main/webapp/META-INF/applicationContext.xml
@@ -91,8 +91,9 @@ http://www.springframework.org/schema/util/spring-util.xsd">
<!-- <value>classpath:xa_system.properties</value> -->
<!-- <value>classpath:xa_custom.properties</value> -->
<!-- <value>classpath:xa_ldap.properties</value> -->
+ <value>classpath:core-site.xml</value>
<value>classpath:ranger-admin-default-site.xml</value>
- <value>classpath:ranger-admin-site.xml</value>
+ <value>classpath:ranger-admin-site.xml</value>
</list>
</property>
<property name="propertiesPersister" ref="xmlPropertyConfigurer" />
http://git-wip-us.apache.org/repos/asf/incubator-ranger/blob/8614032c/security-admin/src/test/java/org/apache/ranger/rest/TestServiceREST.java
----------------------------------------------------------------------
diff --git a/security-admin/src/test/java/org/apache/ranger/rest/TestServiceREST.java b/security-admin/src/test/java/org/apache/ranger/rest/TestServiceREST.java
index 083c777..48acaa0 100644
--- a/security-admin/src/test/java/org/apache/ranger/rest/TestServiceREST.java
+++ b/security-admin/src/test/java/org/apache/ranger/rest/TestServiceREST.java
@@ -499,7 +499,6 @@ public class TestServiceREST {
dbRangerService.getUpdatedBy());
Mockito.verify(validatorFactory).getServiceValidator(svcStore);
- Mockito.verify(daoManager).getXXServiceDef();
Mockito.verify(svcStore).createService(rangerService);
}
http://git-wip-us.apache.org/repos/asf/incubator-ranger/blob/8614032c/src/main/assembly/admin-web.xml
----------------------------------------------------------------------
diff --git a/src/main/assembly/admin-web.xml b/src/main/assembly/admin-web.xml
index ca68ac6..ea24bf4 100644
--- a/src/main/assembly/admin-web.xml
+++ b/src/main/assembly/admin-web.xml
@@ -200,6 +200,12 @@
<includes>
<include>org.apache.tomcat.embed:tomcat-embed*</include>
<include>org.eclipse.jdt.core.compiler:ecj:jar:P20140317-1600</include>
+ <include>log4j:log4j</include>
+ <include>org.apache.hadoop:hadoop-auth:jar:${hadoop-common.version}</include>
+ <include>org.apache.ranger:ranger-plugins-common</include>
+ <include>org.slf4j:slf4j-api</include>
+ <include>org.apache.hadoop:hadoop-common</include>
+ <include>commons-logging:commons-logging</include>
</includes>
<unpack>false</unpack>
</dependencySet>
http://git-wip-us.apache.org/repos/asf/incubator-ranger/blob/8614032c/src/main/assembly/usersync.xml
----------------------------------------------------------------------
diff --git a/src/main/assembly/usersync.xml b/src/main/assembly/usersync.xml
index b032a1d..e60aae0 100644
--- a/src/main/assembly/usersync.xml
+++ b/src/main/assembly/usersync.xml
@@ -53,6 +53,7 @@
<include>org.apache.htrace:htrace-core</include>
<include>commons-httpclient:commons-httpclient</include>
<include>commons-codec:commons-codec</include>
+ <include>org.apache.ranger:ranger-plugins-common</include>
</includes>
<unpack>false</unpack>
</dependencySet>
http://git-wip-us.apache.org/repos/asf/incubator-ranger/blob/8614032c/storm-agent/src/main/java/org/apache/ranger/services/storm/client/StormClient.java
----------------------------------------------------------------------
diff --git a/storm-agent/src/main/java/org/apache/ranger/services/storm/client/StormClient.java b/storm-agent/src/main/java/org/apache/ranger/services/storm/client/StormClient.java
index 74170fe..432ed78 100644
--- a/storm-agent/src/main/java/org/apache/ranger/services/storm/client/StormClient.java
+++ b/storm-agent/src/main/java/org/apache/ranger/services/storm/client/StormClient.java
@@ -33,7 +33,9 @@ import javax.security.auth.login.LoginContext;
import javax.security.auth.login.LoginException;
import org.apache.commons.io.FilenameUtils;
+import org.apache.commons.lang.StringUtils;
import org.apache.hadoop.security.KrbPasswordSaverLoginModule;
+import org.apache.hadoop.security.SecureClientLogin;
import org.apache.hadoop.security.authentication.util.KerberosUtil;
import org.apache.log4j.Logger;
import org.apache.ranger.plugin.client.BaseClient;
@@ -62,12 +64,18 @@ public class StormClient {
String stormUIUrl;
String userName;
String password;
+ String lookupPrincipal;
+ String lookupKeytab;
+ String nameRules;
- public StormClient(String aStormUIUrl, String aUserName, String aPassword) {
+ public StormClient(String aStormUIUrl, String aUserName, String aPassword, String lookupPrincipal, String lookupKeytab, String nameRules) {
this.stormUIUrl = aStormUIUrl;
this.userName = aUserName ;
this.password = aPassword;
+ this.lookupPrincipal = lookupPrincipal;
+ this.lookupKeytab = lookupKeytab;
+ this.nameRules = nameRules;
if (LOG.isDebugEnabled()) {
LOG.debug("Storm Client is build with url [" + aStormUIUrl + "] user: [" + aUserName + "], password: [" + "" + "]");
@@ -173,7 +181,7 @@ public class StormClient {
} ;
try {
- ret = executeUnderKerberos(this.userName, this.password, topologyListGetter) ;
+ ret = executeUnderKerberos(this.userName, this.password, this.lookupPrincipal, this.lookupKeytab, this.nameRules, topologyListGetter) ;
} catch (IOException e) {
LOG.error("Unable to get Topology list from [" + stormUIUrl + "]", e) ;
}
@@ -181,7 +189,7 @@ public class StormClient {
return ret;
}
- public static <T> T executeUnderKerberos(String userName, String password,
+ public static <T> T executeUnderKerberos(String userName, String password, String lookupPrincipal, String lookupKeytab, String nameRules,
PrivilegedAction<T> action) throws IOException {
final String errMsg = errMessage;
@@ -247,20 +255,28 @@ public class StormClient {
LoginContext loginContext = null;
try {
- subject = new Subject();
- LOG.debug("executeUnderKerberos():user=" + userName + ",pass=");
- LOG.debug("executeUnderKerberos():Creating config..");
- MySecureClientLoginConfiguration loginConf = new MySecureClientLoginConfiguration(
- userName, password);
- LOG.debug("executeUnderKerberos():Creating Context..");
- loginContext = new LoginContext("hadoop-keytab-kerberos", subject,
- null, loginConf);
-
- LOG.debug("executeUnderKerberos():Logging in..");
- loginContext.login();
-
- Subject loginSubj = loginContext.getSubject();
-
+ Subject loginSubj = null;
+ if(!StringUtils.isEmpty(lookupPrincipal) && !StringUtils.isEmpty(lookupKeytab)){
+ LOG.info("Init Lookup Login: security enabled, using lookupPrincipal/lookupKeytab");
+ if(StringUtils.isEmpty(nameRules)){
+ nameRules = "DEFAULT";
+ }
+ loginSubj = SecureClientLogin.loginUserFromKeytab(lookupPrincipal, lookupKeytab, nameRules);
+ }else{
+ subject = new Subject();
+ LOG.debug("executeUnderKerberos():user=" + userName + ",pass=");
+ LOG.debug("executeUnderKerberos():Creating config..");
+ MySecureClientLoginConfiguration loginConf = new MySecureClientLoginConfiguration(
+ userName, password);
+ LOG.debug("executeUnderKerberos():Creating Context..");
+ loginContext = new LoginContext("hadoop-keytab-kerberos", subject,
+ null, loginConf);
+
+ LOG.debug("executeUnderKerberos():Logging in..");
+ loginContext.login();
+ LOG.info("Init Login: using username/password");
+ loginSubj = loginContext.getSubject();
+ }
if (loginSubj != null) {
ret = Subject.doAs(loginSubj, action);
}
@@ -344,8 +360,11 @@ public class StormClient {
String stormUrl = configs.get("nimbus.url");
String stormAdminUser = configs.get("username");
String stormAdminPassword = configs.get("password");
+ String lookupPrincipal = configs.get("lookupprincipal");
+ String lookupKeytab = configs.get("lookupkeytab");
+ String nameRules = configs.get("namerules");
stormClient = new StormClient(stormUrl, stormAdminUser,
- stormAdminPassword);
+ stormAdminPassword, lookupPrincipal, lookupKeytab, nameRules);
}
return stormClient;
}
http://git-wip-us.apache.org/repos/asf/incubator-ranger/blob/8614032c/storm-agent/src/main/java/org/apache/ranger/services/storm/client/StormConnectionMgr.java
----------------------------------------------------------------------
diff --git a/storm-agent/src/main/java/org/apache/ranger/services/storm/client/StormConnectionMgr.java b/storm-agent/src/main/java/org/apache/ranger/services/storm/client/StormConnectionMgr.java
index 5d008e7..55e52e2 100644
--- a/storm-agent/src/main/java/org/apache/ranger/services/storm/client/StormConnectionMgr.java
+++ b/storm-agent/src/main/java/org/apache/ranger/services/storm/client/StormConnectionMgr.java
@@ -19,6 +19,7 @@
package org.apache.ranger.services.storm.client;
+import org.apache.commons.lang.StringUtils;
import org.apache.log4j.Logger;
@@ -26,16 +27,18 @@ public class StormConnectionMgr {
public static final Logger LOG = Logger.getLogger(StormConnectionMgr.class);
- public static StormClient getStormClient(final String stormUIURL, String userName, String password) {
+ public static StormClient getStormClient(final String stormUIURL, String userName, String password, String lookupPrincipal, String lookupKeytab, String nameRules) {
StormClient stormClient = null;
if (stormUIURL == null || stormUIURL.isEmpty()) {
LOG.error("Can not create StormClient: stormUIURL is empty");
- } else if (userName == null || userName.isEmpty()) {
- LOG.error("Can not create StormClient: stormAdminUser is empty");
- } else if (password == null || password.isEmpty()) {
- LOG.error("Can not create StormClient: stormAdminPassword is empty");
- } else {
- stormClient = new StormClient(stormUIURL, userName, password);
+ } else if(StringUtils.isEmpty(lookupPrincipal) || StringUtils.isEmpty(lookupKeytab)){
+ if (userName == null || userName.isEmpty()) {
+ LOG.error("Can not create StormClient: stormAdminUser is empty");
+ } else if (password == null || password.isEmpty()) {
+ LOG.error("Can not create StormClient: stormAdminPassword is empty");
+ }
+ }else {
+ stormClient = new StormClient(stormUIURL, userName, password, lookupPrincipal, lookupKeytab, nameRules);
}
return stormClient;
}
http://git-wip-us.apache.org/repos/asf/incubator-ranger/blob/8614032c/storm-agent/src/main/java/org/apache/ranger/services/storm/client/StormResourceMgr.java
----------------------------------------------------------------------
diff --git a/storm-agent/src/main/java/org/apache/ranger/services/storm/client/StormResourceMgr.java b/storm-agent/src/main/java/org/apache/ranger/services/storm/client/StormResourceMgr.java
index a16fce1..bf9fea3 100644
--- a/storm-agent/src/main/java/org/apache/ranger/services/storm/client/StormResourceMgr.java
+++ b/storm-agent/src/main/java/org/apache/ranger/services/storm/client/StormResourceMgr.java
@@ -75,14 +75,17 @@ public class StormResourceMgr {
String url = configs.get("nimbus.url");
String username = configs.get("username");
String password = configs.get("password");
- resultList = getStormResources(url, username, password,StromTopologyName,StormTopologyList) ;
+ String lookupPrincipal = configs.get("lookupprincipal");
+ String lookupKeytab = configs.get("lookupkeytab");
+ String nameRules = configs.get("namerules");
+ resultList = getStormResources(url, username, password,lookupPrincipal, lookupKeytab, nameRules, StromTopologyName,StormTopologyList) ;
}
return resultList ;
}
- public static List<String> getStormResources(String url, String username, String password,String topologyName, List<String> StormTopologyList) {
+ public static List<String> getStormResources(String url, String username, String password, String lookupPrincipal, String lookupKeytab, String nameRules, String topologyName, List<String> StormTopologyList) {
List<String> topologyList = null;
- final StormClient stormClient = StormConnectionMgr.getStormClient(url, username, password);
+ final StormClient stormClient = StormConnectionMgr.getStormClient(url, username, password, lookupPrincipal, lookupKeytab, nameRules);
if (stormClient == null) {
LOG.error("Storm Client is null");
return new ArrayList<String>();
http://git-wip-us.apache.org/repos/asf/incubator-ranger/blob/8614032c/tagsync/conf/templates/installprop2xml.properties
----------------------------------------------------------------------
diff --git a/tagsync/conf/templates/installprop2xml.properties b/tagsync/conf/templates/installprop2xml.properties
index a6840b0..8f0ea75 100644
--- a/tagsync/conf/templates/installprop2xml.properties
+++ b/tagsync/conf/templates/installprop2xml.properties
@@ -40,4 +40,7 @@ TAGSYNC_ATLAS_ZOOKEEPER_ENDPOINT = atlas.kafka.zookeeper.connect
TAGSYNC_ATLAS_CONSUMER_GROUP = atlas.kafka.entities.group.id
TAGSYNC_ATLAS_TO_RANGER_SERVICE_MAPPING = ranger.tagsync.atlas.to.service.mapping
-TAGSYNC_SOURCE_ATLAS_CUSTOM_RESOURCE_MAPPERS = ranger.tagsync.source.atlas.custom.resource.mappers
\ No newline at end of file
+TAGSYNC_SOURCE_ATLAS_CUSTOM_RESOURCE_MAPPERS = ranger.tagsync.source.atlas.custom.resource.mappers
+
+tagsync_principal = ranger.tagsync.kerberos.principal
+tagsync_keytab = ranger.tagsync.kerberos.keytab
http://git-wip-us.apache.org/repos/asf/incubator-ranger/blob/8614032c/tagsync/conf/templates/ranger-tagsync-template.xml
----------------------------------------------------------------------
diff --git a/tagsync/conf/templates/ranger-tagsync-template.xml b/tagsync/conf/templates/ranger-tagsync-template.xml
index bad71bd..d82b6d1 100644
--- a/tagsync/conf/templates/ranger-tagsync-template.xml
+++ b/tagsync/conf/templates/ranger-tagsync-template.xml
@@ -70,4 +70,13 @@
<property>
<name>ranger.tagsync.source.atlas.custom.resource.mappers</name>
<value></value>
- </property></configuration>
+ </property>
+ <property>
+ <name>ranger.tagsync.kerberos.keytab</name>
+ <value></value>
+ </property>
+ <property>
+ <name>ranger.tagsync.kerberos.principal</name>
+ <value></value>
+ </property>
+</configuration>
http://git-wip-us.apache.org/repos/asf/incubator-ranger/blob/8614032c/tagsync/scripts/install.properties
----------------------------------------------------------------------
diff --git a/tagsync/scripts/install.properties b/tagsync/scripts/install.properties
index b6665d1..695371d 100644
--- a/tagsync/scripts/install.properties
+++ b/tagsync/scripts/install.properties
@@ -34,6 +34,11 @@ logdir = log
# URL for TagAdmin
TAGADMIN_ENDPOINT = http://localhost:6080
+#Set to run in kerberos environment
+tagsync_principal=
+tagsync_keytab=
+hadoop_conf=/etc/hadoop/conf
+
# SSL config file name for TagAdmin
TAGADMIN_SSL_CONFIG_FILENAME =
@@ -82,4 +87,4 @@ TAGSYNC_ATLAS_TO_RANGER_SERVICE_MAPPING=
# RangerServiceResource structures are specified here. If there are no custom mappers,
# then it can be left blank
-TAGSYNC_SOURCE_ATLAS_CUSTOM_RESOURCE_MAPPERS=
\ No newline at end of file
+TAGSYNC_SOURCE_ATLAS_CUSTOM_RESOURCE_MAPPERS=
http://git-wip-us.apache.org/repos/asf/incubator-ranger/blob/8614032c/tagsync/scripts/ranger-tagsync-services.sh
----------------------------------------------------------------------
diff --git a/tagsync/scripts/ranger-tagsync-services.sh b/tagsync/scripts/ranger-tagsync-services.sh
index add42ee..1235e86 100755
--- a/tagsync/scripts/ranger-tagsync-services.sh
+++ b/tagsync/scripts/ranger-tagsync-services.sh
@@ -59,7 +59,7 @@ if [ "${action}" == "START" ]; then
chmod 777 $logdir
fi
- cp="${cdir}/conf:${cdir}/dist/*:${cdir}/lib/*"
+ cp="${cdir}/conf:${cdir}/dist/*:${cdir}/lib/*:${RANGER_TAGSYNC_HADOOP_CONF_DIR}/*"
if [ -f $pidf ]; then
PID=`cat $pidf`
http://git-wip-us.apache.org/repos/asf/incubator-ranger/blob/8614032c/tagsync/scripts/setup.py
----------------------------------------------------------------------
diff --git a/tagsync/scripts/setup.py b/tagsync/scripts/setup.py
index 59cb5c8..1abb1c8 100755
--- a/tagsync/scripts/setup.py
+++ b/tagsync/scripts/setup.py
@@ -80,6 +80,25 @@ TAG_SOURCE_ATLAS = 'atlas'
TAG_SOURCE_ATLASREST = 'atlasrest'
TAG_SOURCE_FILE = 'file'
+hadoopConfFileName = 'core-site.xml'
+ENV_HADOOP_CONF_FILE = "ranger-tagsync-env-hadoopconfdir.sh"
+globalDict = {}
+
+RANGER_TAGSYNC_HOME = os.getenv("RANGER_TAGSYNC_HOME")
+if RANGER_TAGSYNC_HOME is None:
+ RANGER_TAGSYNC_HOME = os.getcwd()
+
+def populate_global_dict():
+ global globalDict
+ read_config_file = open(os.path.join(RANGER_TAGSYNC_HOME,'install.properties'))
+ for each_line in read_config_file.read().split('\n') :
+ if len(each_line) == 0 : continue
+ if re.search('=', each_line):
+ key , value = each_line.strip().split("=",1)
+ key = key.strip()
+ value = value.strip()
+ globalDict[key] = value
+
def archiveFile(originalFileName):
archiveDir = dirname(originalFileName)
archiveFileName = "." + basename(originalFileName) + "." + (strftime("%d%m%Y%H%M%S", localtime()))
@@ -258,11 +277,32 @@ def initializeInitD():
os.remove(ubinScriptName)
os.symlink(localScriptName,ubinScriptName)
+def write_env_files(exp_var_name, log_path, file_name):
+ final_path = "{0}/{1}".format(confBaseDirName,file_name)
+ if not os.path.isfile(final_path):
+ print "Creating %s file" % file_name
+ f = open(final_path, "w")
+ f.write("export {0}={1}".format(exp_var_name,log_path))
+ f.close()
def main():
print "\nINFO: Installing ranger-tagsync .....\n"
+ populate_global_dict()
+ hadoop_conf = globalDict['hadoop_conf']
+
+ hadoop_conf_full_path = os.path.join(hadoop_conf, hadoopConfFileName)
+ tagsync_conf_full_path = os.path.join(tagsyncBaseDirFullName,confBaseDirName,hadoopConfFileName)
+ if not isfile(hadoop_conf_full_path):
+ print "WARN: core-site.xml file not found in provided hadoop conf path..."
+ f = open(tagsync_conf_full_path, "w")
+ f.write("<configuration></configuration>")
+ f.close()
+ else:
+ if os.path.islink(tagsync_conf_full_path):
+ os.remove(tagsync_conf_full_path)
+
dirList = [ rangerBaseDirName, tagsyncBaseDirFullName, confFolderName ]
for dir in dirList:
if (not os.path.isdir(dir)):
@@ -389,6 +429,13 @@ def main():
os.chown(fn, ownerId, groupId)
os.chmod(fn, 0755)
+ write_env_files("RANGER_TAGSYNC_HADOOP_CONF_DIR", hadoop_conf, ENV_HADOOP_CONF_FILE);
+ os.chown(os.path.join(confBaseDirName, ENV_HADOOP_CONF_FILE),ownerId,groupId)
+ os.chmod(os.path.join(confBaseDirName, ENV_HADOOP_CONF_FILE),0755)
+
+ if isfile(hadoop_conf_full_path):
+ os.symlink(hadoop_conf_full_path, tagsync_conf_full_path)
+
print "\nINFO: Completed ranger-tagsync installation.....\n"
main()