RANGER-867 : Add Kerberos support for ranger admin and clients Signed-off-by: Gautam Borad <[email protected]>
Project: http://git-wip-us.apache.org/repos/asf/incubator-ranger/repo Commit: http://git-wip-us.apache.org/repos/asf/incubator-ranger/commit/8614032c Tree: http://git-wip-us.apache.org/repos/asf/incubator-ranger/tree/8614032c Diff: http://git-wip-us.apache.org/repos/asf/incubator-ranger/diff/8614032c Branch: refs/heads/master Commit: 8614032c909dd5599fedc35c8f4b80f71b3a950d Parents: 981f01a Author: Ankita Sinha <[email protected]> Authored: Wed Apr 20 14:35:46 2016 +0530 Committer: Gautam Borad <[email protected]> Committed: Thu Apr 21 11:50:01 2016 +0530 ---------------------------------------------------------------------- .../hadoop/security/SecureClientLogin.java | 71 ++- .../admin/client/RangerAdminRESTClient.java | 121 +++- .../hadoop/config/RangerConfiguration.java | 5 + .../apache/ranger/plugin/client/BaseClient.java | 86 +-- .../plugin/client/HadoopConfigHolder.java | 31 +- .../plugin/store/rest/ServiceRESTStore.java | 23 +- .../ranger/plugin/util/RangerRESTUtils.java | 5 + .../main/resources/resourcenamemap.properties | 2 + embeddedwebserver/pom.xml | 15 + .../scripts/ranger-admin-services.sh | 4 +- .../ranger/server/tomcat/EmbeddedServer.java | 80 ++- .../ranger/services/hdfs/client/HdfsClient.java | 32 +- .../ranger/services/kms/client/KMSClient.java | 28 +- .../services/kms/client/KMSConnectionMgr.java | 15 +- .../services/kms/client/KMSResourceMgr.java | 9 +- security-admin/scripts/install.properties | 11 + security-admin/scripts/setup.sh | 93 +++ .../java/org/apache/ranger/biz/KmsKeyMgr.java | 7 +- .../org/apache/ranger/biz/RangerBizUtil.java | 22 + .../org/apache/ranger/biz/ServiceDBStore.java | 51 +- .../java/org/apache/ranger/biz/ServiceMgr.java | 37 +- .../java/org/apache/ranger/biz/SessionMgr.java | 19 + .../java/org/apache/ranger/biz/XUserMgr.java | 2 +- .../apache/ranger/common/UserSessionBase.java | 9 + .../org/apache/ranger/rest/PublicAPIsv2.java | 5 +- .../org/apache/ranger/rest/ServiceREST.java | 292 +++++++++- .../java/org/apache/ranger/rest/TagREST.java | 80 +++ .../apache/ranger/rest/TagRESTConstants.java | 1 + .../context/RangerPreAuthSecurityHandler.java | 9 + .../filter/RangerKRBAuthenticationFilter.java | 569 ++++++++++++++++++ .../security/web/filter/RangerKrbFilter.java | 576 +++++++++++++++++++ .../resources/conf.dist/ranger-admin-site.xml | 38 ++ .../conf.dist/security-applicationContext.xml | 8 +- .../main/resources/resourcenamemap.properties | 2 + .../main/webapp/META-INF/applicationContext.xml | 3 +- .../org/apache/ranger/rest/TestServiceREST.java | 1 - src/main/assembly/admin-web.xml | 6 + src/main/assembly/usersync.xml | 1 + .../services/storm/client/StormClient.java | 55 +- .../storm/client/StormConnectionMgr.java | 17 +- .../services/storm/client/StormResourceMgr.java | 9 +- .../conf/templates/installprop2xml.properties | 5 +- .../conf/templates/ranger-tagsync-template.xml | 11 +- tagsync/scripts/install.properties | 7 +- tagsync/scripts/ranger-tagsync-services.sh | 2 +- tagsync/scripts/setup.py | 47 ++ .../ranger/tagsync/process/TagSyncConfig.java | 45 +- .../tagsync/sink/tagadmin/TagAdminRESTSink.java | 50 +- ugsync/pom.xml | 5 + .../config/UserGroupSyncConfig.java | 5 +- .../process/PolicyMgrUserGroupBuilder.java | 332 ++++++++--- unixauthservice/scripts/install.properties | 4 + .../scripts/ranger-usersync-services.sh | 2 +- unixauthservice/scripts/setup.py | 31 +- .../templates/installprop2xml.properties | 2 + .../templates/ranger-ugsync-template.xml | 8 + 56 files changed, 2758 insertions(+), 248 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/incubator-ranger/blob/8614032c/agents-common/src/main/java/org/apache/hadoop/security/SecureClientLogin.java ---------------------------------------------------------------------- diff --git a/agents-common/src/main/java/org/apache/hadoop/security/SecureClientLogin.java b/agents-common/src/main/java/org/apache/hadoop/security/SecureClientLogin.java index ba0c443..ce78cbe 100644 --- a/agents-common/src/main/java/org/apache/hadoop/security/SecureClientLogin.java +++ b/agents-common/src/main/java/org/apache/hadoop/security/SecureClientLogin.java @@ -18,6 +18,7 @@ */ package org.apache.hadoop.security; +import java.io.File; import java.io.IOException; import java.security.Principal; import java.util.HashMap; @@ -31,11 +32,16 @@ import javax.security.auth.login.AppConfigurationEntry.LoginModuleControlFlag; import javax.security.auth.login.LoginContext; import javax.security.auth.login.LoginException; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; import org.apache.hadoop.security.UserGroupInformation.AuthenticationMethod; import org.apache.hadoop.security.authentication.util.KerberosUtil; - +import org.apache.hadoop.security.authentication.util.KerberosName; +import org.apache.hadoop.util.StringUtils; public class SecureClientLogin { + private static final Log LOG = LogFactory.getLog(SecureClientLogin.class); + public static final String HOSTNAME_PATTERN = "_HOST"; public synchronized static Subject loginUserFromKeytab(String user, String path) throws IOException { try { @@ -49,6 +55,20 @@ public class SecureClientLogin { throw new IOException("Login failure for " + user + " from keytab " + path, le); } } + + public synchronized static Subject loginUserFromKeytab(String user, String path, String nameRules) throws IOException { + try { + Subject subject = new Subject(); + SecureClientLoginConfiguration loginConf = new SecureClientLoginConfiguration(true, user, path); + LoginContext login = new LoginContext("hadoop-keytab-kerberos", subject, null, loginConf); + KerberosName.setRules(nameRules); + subject.getPrincipals().add(new User(user, AuthenticationMethod.KERBEROS, login)); + login.login(); + return login.getSubject(); + } catch (LoginException le) { + throw new IOException("Login failure for " + user + " from keytab " + path, le); + } + } public synchronized static Subject loginUserWithPassword(String user, String password) throws IOException { String tmpPass = password; @@ -90,7 +110,54 @@ public class SecureClientLogin { public static Principal createUserPrincipal(String aLoginName) { return new User(aLoginName) ; } - + + public static boolean isKerberosCredentialExists(String principal, String keytabPath){ + boolean isValid = false; + if (keytabPath != null && !keytabPath.isEmpty()) { + File keytabFile = new File(keytabPath); + if (!keytabFile.exists()) { + LOG.warn(keytabPath + " doesn't exist."); + } else if (!keytabFile.canRead()) { + LOG.warn("Unable to read " + keytabPath + " Please check the file access permissions for user"); + }else{ + isValid = true; + } + } else { + LOG.warn("Can't find keyTab Path : "+keytabPath); + } + if (!(principal != null && !principal.isEmpty() && isValid)) { + isValid = false; + LOG.warn("Can't find principal : "+principal); + } + return isValid; + } + + public static String getPrincipal(String principalConfig, String hostName) throws IOException { + String[] components = getComponents(principalConfig); + if (components == null || components.length != 3 || !components[1].equals(HOSTNAME_PATTERN)) { + return principalConfig; + } else { + if (hostName == null) { + throw new IOException("Can't replace " + HOSTNAME_PATTERN + " pattern since client ranger.service.host is null"); + } + return replacePattern(components, hostName); + } + } + + private static String[] getComponents(String principalConfig) { + if (principalConfig == null) + return null; + return principalConfig.split("[/@]"); + } + + private static String replacePattern(String[] components, String hostname) + throws IOException { + String fqdn = hostname; + if (fqdn == null || fqdn.isEmpty() || fqdn.equals("0.0.0.0")) { + fqdn = java.net.InetAddress.getLocalHost().getCanonicalHostName(); + } + return components[0] + "/" + StringUtils.toLowerCase(fqdn) + "@" + components[2]; + } } class SecureClientLoginConfiguration extends javax.security.auth.login.Configuration { http://git-wip-us.apache.org/repos/asf/incubator-ranger/blob/8614032c/agents-common/src/main/java/org/apache/ranger/admin/client/RangerAdminRESTClient.java ---------------------------------------------------------------------- diff --git a/agents-common/src/main/java/org/apache/ranger/admin/client/RangerAdminRESTClient.java b/agents-common/src/main/java/org/apache/ranger/admin/client/RangerAdminRESTClient.java index bd2b749..afa347e 100644 --- a/agents-common/src/main/java/org/apache/ranger/admin/client/RangerAdminRESTClient.java +++ b/agents-common/src/main/java/org/apache/ranger/admin/client/RangerAdminRESTClient.java @@ -27,13 +27,15 @@ import com.sun.jersey.api.client.WebResource; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.apache.hadoop.security.AccessControlException; +import org.apache.hadoop.security.UserGroupInformation; import org.apache.ranger.admin.client.datatype.RESTResponse; - +import org.apache.ranger.audit.provider.MiscUtil; import org.apache.ranger.authorization.hadoop.config.RangerConfiguration; import org.apache.ranger.plugin.util.*; import java.lang.reflect.ParameterizedType; import java.lang.reflect.Type; +import java.security.PrivilegedAction; import java.util.List; public class RangerAdminRESTClient implements RangerAdminClient { @@ -44,7 +46,6 @@ public class RangerAdminRESTClient implements RangerAdminClient { private RangerRESTClient restClient = null; private RangerRESTUtils restUtils = new RangerRESTUtils(); - public RangerAdminRESTClient() { } @@ -76,31 +77,44 @@ public class RangerAdminRESTClient implements RangerAdminClient { String sslConfigFileName = RangerConfiguration.getInstance().get(propertyPrefix + ".policy.rest.ssl.config.file"); int restClientConnTimeOutMs = RangerConfiguration.getInstance().getInt(propertyPrefix + ".policy.rest.client.connection.timeoutMs", 120 * 1000); int restClientReadTimeOutMs = RangerConfiguration.getInstance().getInt(propertyPrefix + ".policy.rest.client.read.timeoutMs", 30 * 1000); - + init(url, sslConfigFileName, restClientConnTimeOutMs , restClientReadTimeOutMs); } @Override - public ServicePolicies getServicePoliciesIfUpdated(long lastKnownVersion) throws Exception { + public ServicePolicies getServicePoliciesIfUpdated(final long lastKnownVersion) throws Exception { if(LOG.isDebugEnabled()) { LOG.debug("==> RangerAdminRESTClient.getServicePoliciesIfUpdated(" + lastKnownVersion + ")"); } ServicePolicies ret = null; - WebResource webResource = createWebResource(RangerRESTUtils.REST_URL_POLICY_GET_FOR_SERVICE_IF_UPDATED + serviceName) - .queryParam(RangerRESTUtils.REST_PARAM_LAST_KNOWN_POLICY_VERSION, Long.toString(lastKnownVersion)) - .queryParam(RangerRESTUtils.REST_PARAM_PLUGIN_ID, pluginId); - ClientResponse response = webResource.accept(RangerRESTUtils.REST_MIME_TYPE_JSON).get(ClientResponse.class); - + ClientResponse response = null; + if (MiscUtil.getUGILoginUser() != null && UserGroupInformation.isSecurityEnabled()) { + LOG.info("Checking Service policy if updated as user : " + MiscUtil.getUGILoginUser()); + PrivilegedAction<ClientResponse> action = new PrivilegedAction<ClientResponse>() { + public ClientResponse run() { + WebResource secureWebResource = createWebResource(RangerRESTUtils.REST_URL_POLICY_GET_FOR_SECURE_SERVICE_IF_UPDATED + serviceName) + .queryParam(RangerRESTUtils.REST_PARAM_LAST_KNOWN_POLICY_VERSION, Long.toString(lastKnownVersion)) + .queryParam(RangerRESTUtils.REST_PARAM_PLUGIN_ID, pluginId); + return secureWebResource.accept(RangerRESTUtils.REST_MIME_TYPE_JSON).get(ClientResponse.class); + }; + }; + response = MiscUtil.getUGILoginUser().doAs(action); + }else{ + WebResource webResource = createWebResource(RangerRESTUtils.REST_URL_POLICY_GET_FOR_SERVICE_IF_UPDATED + serviceName) + .queryParam(RangerRESTUtils.REST_PARAM_LAST_KNOWN_POLICY_VERSION, Long.toString(lastKnownVersion)) + .queryParam(RangerRESTUtils.REST_PARAM_PLUGIN_ID, pluginId); + response = webResource.accept(RangerRESTUtils.REST_MIME_TYPE_JSON).get(ClientResponse.class); + } + if(response != null && response.getStatus() == 200) { ret = response.getEntity(ServicePolicies.class); } else if(response != null && response.getStatus() == 304) { // no change } else { RESTResponse resp = RESTResponse.fromClientResponse(response); - LOG.error("Error getting policies. request=" + webResource.toString() - + ", response=" + resp.toString() + ", serviceName=" + serviceName); + LOG.error("Error getting policies. response=" + resp.toString() + ", serviceName=" + serviceName); throw new Exception(resp.getMessage()); } @@ -112,15 +126,27 @@ public class RangerAdminRESTClient implements RangerAdminClient { } @Override - public void grantAccess(GrantRevokeRequest request) throws Exception { + public void grantAccess(final GrantRevokeRequest request) throws Exception { if(LOG.isDebugEnabled()) { LOG.debug("==> RangerAdminRESTClient.grantAccess(" + request + ")"); } - WebResource webResource = createWebResource(RangerRESTUtils.REST_URL_SERVICE_GRANT_ACCESS + serviceName) - .queryParam(RangerRESTUtils.REST_PARAM_PLUGIN_ID, pluginId); - ClientResponse response = webResource.accept(RangerRESTUtils.REST_EXPECTED_MIME_TYPE).type(RangerRESTUtils.REST_EXPECTED_MIME_TYPE).post(ClientResponse.class, restClient.toJson(request)); - + ClientResponse response = null; + if (MiscUtil.getUGILoginUser() != null && UserGroupInformation.isSecurityEnabled()) { + PrivilegedAction<ClientResponse> action = new PrivilegedAction<ClientResponse>() { + public ClientResponse run() { + WebResource secureWebResource = createWebResource(RangerRESTUtils.REST_URL_SECURE_SERVICE_GRANT_ACCESS + serviceName) + .queryParam(RangerRESTUtils.REST_PARAM_PLUGIN_ID, pluginId); + return secureWebResource.accept(RangerRESTUtils.REST_EXPECTED_MIME_TYPE).type(RangerRESTUtils.REST_EXPECTED_MIME_TYPE).post(ClientResponse.class, restClient.toJson(request)); + }; + }; + LOG.info("grantAccess as user " + MiscUtil.getUGILoginUser()); + response = MiscUtil.getUGILoginUser().doAs(action); + } else { + WebResource webResource = createWebResource(RangerRESTUtils.REST_URL_SERVICE_GRANT_ACCESS + serviceName) + .queryParam(RangerRESTUtils.REST_PARAM_PLUGIN_ID, pluginId); + response = webResource.accept(RangerRESTUtils.REST_EXPECTED_MIME_TYPE).type(RangerRESTUtils.REST_EXPECTED_MIME_TYPE).post(ClientResponse.class, restClient.toJson(request)); + } if(response != null && response.getStatus() != 200) { LOG.error("grantAccess() failed: HTTP status=" + response.getStatus()); @@ -139,14 +165,27 @@ public class RangerAdminRESTClient implements RangerAdminClient { } @Override - public void revokeAccess(GrantRevokeRequest request) throws Exception { + public void revokeAccess(final GrantRevokeRequest request) throws Exception { if(LOG.isDebugEnabled()) { LOG.debug("==> RangerAdminRESTClient.revokeAccess(" + request + ")"); } - WebResource webResource = createWebResource(RangerRESTUtils.REST_URL_SERVICE_REVOKE_ACCESS + serviceName) - .queryParam(RangerRESTUtils.REST_PARAM_PLUGIN_ID, pluginId); - ClientResponse response = webResource.accept(RangerRESTUtils.REST_EXPECTED_MIME_TYPE).type(RangerRESTUtils.REST_EXPECTED_MIME_TYPE).post(ClientResponse.class, restClient.toJson(request)); + ClientResponse response = null; + if (MiscUtil.getUGILoginUser() != null && UserGroupInformation.isSecurityEnabled()) { + PrivilegedAction<ClientResponse> action = new PrivilegedAction<ClientResponse>() { + public ClientResponse run() { + WebResource secureWebResource = createWebResource(RangerRESTUtils.REST_URL_SECURE_SERVICE_REVOKE_ACCESS + serviceName) + .queryParam(RangerRESTUtils.REST_PARAM_PLUGIN_ID, pluginId); + return secureWebResource.accept(RangerRESTUtils.REST_EXPECTED_MIME_TYPE).type(RangerRESTUtils.REST_EXPECTED_MIME_TYPE).post(ClientResponse.class, restClient.toJson(request)); + }; + }; + LOG.info("revokeAccess as user " + MiscUtil.getUGILoginUser()); + response = MiscUtil.getUGILoginUser().doAs(action); + } else { + WebResource webResource = createWebResource(RangerRESTUtils.REST_URL_SERVICE_REVOKE_ACCESS + serviceName) + .queryParam(RangerRESTUtils.REST_PARAM_PLUGIN_ID, pluginId); + response = webResource.accept(RangerRESTUtils.REST_EXPECTED_MIME_TYPE).type(RangerRESTUtils.REST_EXPECTED_MIME_TYPE).post(ClientResponse.class, restClient.toJson(request)); + } if(response != null && response.getStatus() != 200) { LOG.error("revokeAccess() failed: HTTP status=" + response.getStatus()); @@ -186,18 +225,31 @@ public class RangerAdminRESTClient implements RangerAdminClient { } @Override - public ServiceTags getServiceTagsIfUpdated(long lastKnownVersion) throws Exception { + public ServiceTags getServiceTagsIfUpdated(final long lastKnownVersion) throws Exception { if(LOG.isDebugEnabled()) { LOG.debug("==> RangerAdminRESTClient.getServiceTagsIfUpdated(" + lastKnownVersion + "): "); } ServiceTags ret = null; - - WebResource webResource = createWebResource(RangerRESTUtils.REST_URL_GET_SERVICE_TAGS_IF_UPDATED + serviceName) - .queryParam(RangerRESTUtils.LAST_KNOWN_TAG_VERSION_PARAM, Long.toString(lastKnownVersion)) - .queryParam(RangerRESTUtils.REST_PARAM_PLUGIN_ID, pluginId); - - ClientResponse response = webResource.accept(RangerRESTUtils.REST_MIME_TYPE_JSON).get(ClientResponse.class); + ClientResponse response = null; + WebResource webResource = null; + if (MiscUtil.getUGILoginUser() != null && UserGroupInformation.isSecurityEnabled()) { + PrivilegedAction<ClientResponse> action = new PrivilegedAction<ClientResponse>() { + public ClientResponse run() { + WebResource secureWebResource = createWebResource(RangerRESTUtils.REST_URL_GET_SECURE_SERVICE_TAGS_IF_UPDATED + serviceName) + .queryParam(RangerRESTUtils.LAST_KNOWN_TAG_VERSION_PARAM, Long.toString(lastKnownVersion)) + .queryParam(RangerRESTUtils.REST_PARAM_PLUGIN_ID, pluginId); + return secureWebResource.accept(RangerRESTUtils.REST_MIME_TYPE_JSON).get(ClientResponse.class); + }; + }; + LOG.info("getServiceTagsIfUpdated as user " + MiscUtil.getUGILoginUser()); + response = MiscUtil.getUGILoginUser().doAs(action); + } else { + webResource = createWebResource(RangerRESTUtils.REST_URL_GET_SERVICE_TAGS_IF_UPDATED + serviceName) + .queryParam(RangerRESTUtils.LAST_KNOWN_TAG_VERSION_PARAM, Long.toString(lastKnownVersion)) + .queryParam(RangerRESTUtils.REST_PARAM_PLUGIN_ID, pluginId); + response = webResource.accept(RangerRESTUtils.REST_MIME_TYPE_JSON).get(ClientResponse.class); + } if(response != null && response.getStatus() == 200) { ret = response.getEntity(ServiceTags.class); @@ -227,11 +279,22 @@ public class RangerAdminRESTClient implements RangerAdminClient { List<String> ret = null; String emptyString = ""; - WebResource webResource = createWebResource(RangerRESTUtils.REST_URL_LOOKUP_TAG_NAMES) + final WebResource webResource = createWebResource(RangerRESTUtils.REST_URL_LOOKUP_TAG_NAMES) .queryParam(RangerRESTUtils.SERVICE_NAME_PARAM, serviceName) .queryParam(RangerRESTUtils.PATTERN_PARAM, pattern); - ClientResponse response = webResource.accept(RangerRESTUtils.REST_MIME_TYPE_JSON).get(ClientResponse.class); + ClientResponse response = null; + if (MiscUtil.getUGILoginUser() != null) { + PrivilegedAction<ClientResponse> action = new PrivilegedAction<ClientResponse>() { + public ClientResponse run() { + return webResource.accept(RangerRESTUtils.REST_MIME_TYPE_JSON).get(ClientResponse.class); + }; + }; + LOG.info("getTagTypes as user " + MiscUtil.getUGILoginUser()); + response = MiscUtil.getUGILoginUser().doAs(action); + } else { + response = webResource.accept(RangerRESTUtils.REST_MIME_TYPE_JSON).get(ClientResponse.class); + } if(response != null && response.getStatus() == 200) { ret = response.getEntity(getGenericType(emptyString)); http://git-wip-us.apache.org/repos/asf/incubator-ranger/blob/8614032c/agents-common/src/main/java/org/apache/ranger/authorization/hadoop/config/RangerConfiguration.java ---------------------------------------------------------------------- diff --git a/agents-common/src/main/java/org/apache/ranger/authorization/hadoop/config/RangerConfiguration.java b/agents-common/src/main/java/org/apache/ranger/authorization/hadoop/config/RangerConfiguration.java index 6cb289f..2a4241c 100644 --- a/agents-common/src/main/java/org/apache/ranger/authorization/hadoop/config/RangerConfiguration.java +++ b/agents-common/src/main/java/org/apache/ranger/authorization/hadoop/config/RangerConfiguration.java @@ -55,6 +55,7 @@ public class RangerConfiguration extends Configuration { public boolean addAdminResources() { String defaultCfg = "ranger-admin-default-site.xml"; String addlCfg = "ranger-admin-site.xml"; + String coreCfg = "core-site.xml"; if(LOG.isDebugEnabled()) { LOG.debug("==> addAdminResources()"); @@ -68,6 +69,10 @@ public class RangerConfiguration extends Configuration { if (! addResourceIfReadable(addlCfg)) { ret = false; } + + if(! addResourceIfReadable(coreCfg)){ + ret = false; + } if(LOG.isDebugEnabled()) { LOG.debug("<== addAdminResources(), result=" + ret); http://git-wip-us.apache.org/repos/asf/incubator-ranger/blob/8614032c/agents-common/src/main/java/org/apache/ranger/plugin/client/BaseClient.java ---------------------------------------------------------------------- diff --git a/agents-common/src/main/java/org/apache/ranger/plugin/client/BaseClient.java b/agents-common/src/main/java/org/apache/ranger/plugin/client/BaseClient.java index df69e2a..86a91a4 100644 --- a/agents-common/src/main/java/org/apache/ranger/plugin/client/BaseClient.java +++ b/agents-common/src/main/java/org/apache/ranger/plugin/client/BaseClient.java @@ -36,8 +36,11 @@ public abstract class BaseClient { private static final Log LOG = LogFactory.getLog(BaseClient.class) ; - private String serviceName ; - private String defaultConfigFile ; + private static final String DEFAULT_NAME_RULE = "DEFAULT"; + + + private String serviceName ; + private String defaultConfigFile ; private Subject loginSubject ; private HadoopConfigHolder configHolder; @@ -50,7 +53,7 @@ public abstract class BaseClient { public BaseClient(String serivceName, Map<String,String> connectionProperties, String defaultConfigFile) { this.serviceName = serivceName ; this.connectionProperties = connectionProperties ; - this.defaultConfigFile = defaultConfigFile ; + this.defaultConfigFile = defaultConfigFile ; init() ; login() ; } @@ -73,38 +76,57 @@ public abstract class BaseClient { + "resource names. Check xa_portal.log for more info."; try { //Thread.currentThread().setContextClassLoader(configHolder.getClassLoader()); - String userName = configHolder.getUserName() ; - if (userName == null) { - String msgDesc = "Unable to find login username for hadoop environment, [" + String lookupPrincipal = SecureClientLogin.getPrincipal(configHolder.getLookupPrincipal(), java.net.InetAddress.getLocalHost().getCanonicalHostName()); + String lookupKeytab = configHolder.getLookupKeytab(); + String nameRules = configHolder.getNameRules(); + if(StringUtils.isEmpty(nameRules)){ + if(LOG.isDebugEnabled()){ + LOG.debug("Name is empty. Setting Name Rule as 'DEFAULT'"); + } + nameRules = DEFAULT_NAME_RULE; + } + String userName = configHolder.getUserName() ; + if(StringUtils.isEmpty(lookupPrincipal) || StringUtils.isEmpty(lookupKeytab)){ + if (userName == null) { + String msgDesc = "Unable to find login username for hadoop environment, [" + serviceName + "]"; - HadoopException hdpException = new HadoopException(msgDesc); - hdpException.generateResponseDataMap(false, msgDesc + errMsg, msgDesc + errMsg, + HadoopException hdpException = new HadoopException(msgDesc); + hdpException.generateResponseDataMap(false, msgDesc + errMsg, msgDesc + errMsg, null, null); - throw hdpException; - } - String keyTabFile = configHolder.getKeyTabFile() ; - if (keyTabFile != null) { - if ( configHolder.isKerberosAuthentication() ) { - LOG.info("Init Login: security enabled, using username/keytab"); - loginSubject = SecureClientLogin.loginUserFromKeytab(userName, keyTabFile) ; - } - else { - LOG.info("Init Login: using username"); - loginSubject = SecureClientLogin.login(userName) ; - } - } - else { - String password = configHolder.getPassword() ; - if ( configHolder.isKerberosAuthentication() ) { - LOG.info("Init Login: using username/password"); - loginSubject = SecureClientLogin.loginUserWithPassword(userName, password) ; - } - else { - LOG.info("Init Login: security not enabled, using username"); - loginSubject = SecureClientLogin.login(userName) ; - } - } + throw hdpException; + } + String keyTabFile = configHolder.getKeyTabFile() ; + if (keyTabFile != null) { + if ( configHolder.isKerberosAuthentication() ) { + LOG.info("Init Login: security enabled, using username/keytab"); + loginSubject = SecureClientLogin.loginUserFromKeytab(userName, keyTabFile, nameRules) ; + } + else { + LOG.info("Init Login: using username"); + loginSubject = SecureClientLogin.login(userName) ; + } + } + else { + String password = configHolder.getPassword() ; + if ( configHolder.isKerberosAuthentication() ) { + LOG.info("Init Login: using username/password"); + loginSubject = SecureClientLogin.loginUserWithPassword(userName, password) ; + } + else { + LOG.info("Init Login: security not enabled, using username"); + loginSubject = SecureClientLogin.login(userName) ; + } + } + }else{ + if ( configHolder.isKerberosAuthentication() ) { + LOG.info("Init Lookup Login: security enabled, using lookupPrincipal/lookupKeytab"); + loginSubject = SecureClientLogin.loginUserFromKeytab(lookupPrincipal, lookupKeytab, nameRules) ; + }else{ + LOG.info("Init Login: security not enabled, using username"); + loginSubject = SecureClientLogin.login(userName); + } + } } catch (IOException ioe) { String msgDesc = "Unable to login to Hadoop environment [" + serviceName + "]"; http://git-wip-us.apache.org/repos/asf/incubator-ranger/blob/8614032c/agents-common/src/main/java/org/apache/ranger/plugin/client/HadoopConfigHolder.java ---------------------------------------------------------------------- diff --git a/agents-common/src/main/java/org/apache/ranger/plugin/client/HadoopConfigHolder.java b/agents-common/src/main/java/org/apache/ranger/plugin/client/HadoopConfigHolder.java index b7416b4..1f3987f 100644 --- a/agents-common/src/main/java/org/apache/ranger/plugin/client/HadoopConfigHolder.java +++ b/agents-common/src/main/java/org/apache/ranger/plugin/client/HadoopConfigHolder.java @@ -29,6 +29,7 @@ import java.util.Set; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; +import org.apache.hadoop.security.SecureClientLogin; public class HadoopConfigHolder { private static final Log LOG = LogFactory.getLog(HadoopConfigHolder.class) ; @@ -40,7 +41,11 @@ public class HadoopConfigHolder { public static final String RANGER_LOGIN_USER_NAME_PROP = "username" ; public static final String RANGER_LOGIN_KEYTAB_FILE_PROP = "keytabfile" ; public static final String RANGER_LOGIN_PASSWORD = "password" ; + public static final String RANGER_LOOKUP_PRINCIPAL = "lookupprincipal"; + public static final String RANGER_LOOKUP_KEYTAB = "lookupkeytab"; + public static final String RANGER_NAME_RULES = "namerules"; public static final String HADOOP_SECURITY_AUTHENTICATION = "hadoop.security.authentication"; + public static final String HADOOP_NAME_RULES = "hadoop.security.auth_to_local"; public static final String HADOOP_SECURITY_AUTHENTICATION_METHOD = "kerberos"; public static final String HADOOP_RPC_PROTECTION = "hadoop.rpc.protection"; @@ -53,11 +58,14 @@ public class HadoopConfigHolder { private String datasourceName ; - private String defaultConfigFile ; + private String defaultConfigFile ; private String userName ; private String keyTabFile ; private String password ; private boolean isKerberosAuth ; + private String lookupPrincipal; + private String lookupKeytab; + private String nameRules; private Map<String,String> connectionProperties; @@ -270,14 +278,17 @@ public class HadoopConfigHolder { userName = prop.getProperty(RANGER_LOGIN_USER_NAME_PROP) ; keyTabFile = prop.getProperty(RANGER_LOGIN_KEYTAB_FILE_PROP) ; password = prop.getProperty(RANGER_LOGIN_PASSWORD) ; - + lookupPrincipal = prop.getProperty(RANGER_LOOKUP_PRINCIPAL); + lookupKeytab = prop.getProperty(RANGER_LOOKUP_KEYTAB); + nameRules = prop.getProperty(RANGER_NAME_RULES); + String hadoopSecurityAuthenticationn = getHadoopSecurityAuthentication(); if ( hadoopSecurityAuthenticationn != null) { isKerberosAuth = ( hadoopSecurityAuthenticationn.equalsIgnoreCase(HADOOP_SECURITY_AUTHENTICATION_METHOD)); } else { - isKerberosAuth = (userName != null) && (userName.indexOf("@") > -1) ; + isKerberosAuth = (((userName != null) && (userName.indexOf("@") > -1)) || (SecureClientLogin.isKerberosCredentialExists(lookupPrincipal, lookupKeytab))); } } } @@ -367,7 +378,7 @@ public class HadoopConfigHolder { return ret; } - + public String getUserName() { return userName; } @@ -383,6 +394,18 @@ public class HadoopConfigHolder { public boolean isKerberosAuthentication() { return isKerberosAuth; } + + public String getLookupPrincipal(){ + return lookupPrincipal; + } + + public String getLookupKeytab(){ + return lookupKeytab; + } + + public String getNameRules(){ + return nameRules; + } public Set<String> getRangerInternalPropertyKeys() { return rangerInternalPropertyKeys; http://git-wip-us.apache.org/repos/asf/incubator-ranger/blob/8614032c/agents-common/src/main/java/org/apache/ranger/plugin/store/rest/ServiceRESTStore.java ---------------------------------------------------------------------- diff --git a/agents-common/src/main/java/org/apache/ranger/plugin/store/rest/ServiceRESTStore.java b/agents-common/src/main/java/org/apache/ranger/plugin/store/rest/ServiceRESTStore.java index cf81d1f..1cb2175 100644 --- a/agents-common/src/main/java/org/apache/ranger/plugin/store/rest/ServiceRESTStore.java +++ b/agents-common/src/main/java/org/apache/ranger/plugin/store/rest/ServiceRESTStore.java @@ -19,13 +19,16 @@ package org.apache.ranger.plugin.store.rest; +import java.security.PrivilegedAction; import java.util.List; import java.util.Map; import org.apache.commons.collections.MapUtils; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; +import org.apache.hadoop.security.UserGroupInformation; import org.apache.ranger.admin.client.datatype.RESTResponse; +import org.apache.ranger.audit.provider.MiscUtil; import org.apache.ranger.authorization.hadoop.config.RangerConfiguration; import org.apache.ranger.plugin.model.RangerPolicy; import org.apache.ranger.plugin.model.RangerService; @@ -67,6 +70,7 @@ public class ServiceRESTStore extends AbstractServiceStore { public final String REST_URL_POLICY_GET_FOR_SERVICE = "/service/plugins/policies/service/"; public final String REST_URL_POLICY_GET_FOR_SERVICE_BY_NAME = "/service/plugins/policies/service/name/"; public final String REST_URL_POLICY_GET_FOR_SERVICE_IF_UPDATED = "/service/plugins/policies/download/"; + public final String REST_URL_POLICY_GET_FOR_SECURE_SERVICE_IF_UPDATED = "/service/plugins/secure/policies/download/"; public static final String REST_MIME_TYPE_JSON = "application/json" ; @@ -572,15 +576,26 @@ public class ServiceRESTStore extends AbstractServiceStore { } @Override - public ServicePolicies getServicePoliciesIfUpdated(String serviceName, Long lastKnownVersion) throws Exception { + public ServicePolicies getServicePoliciesIfUpdated(final String serviceName, final Long lastKnownVersion) throws Exception { if(LOG.isDebugEnabled()) { LOG.debug("==> ServiceRESTStore.getServicePoliciesIfUpdated(" + serviceName + ", " + lastKnownVersion + ")"); } ServicePolicies ret = null; - - WebResource webResource = createWebResource(REST_URL_POLICY_GET_FOR_SERVICE_IF_UPDATED + serviceName + "/" + lastKnownVersion); - ClientResponse response = webResource.accept(REST_MIME_TYPE_JSON).get(ClientResponse.class); + ClientResponse response = null; + if (MiscUtil.getUGILoginUser() != null && UserGroupInformation.isSecurityEnabled()) { + LOG.info("Checking Service policy if updated as user : "+ MiscUtil.getUGILoginUser()); + PrivilegedAction<ClientResponse> action = new PrivilegedAction<ClientResponse>() { + public ClientResponse run() { + WebResource secureWebResource = createWebResource(REST_URL_POLICY_GET_FOR_SECURE_SERVICE_IF_UPDATED + serviceName + "/" + lastKnownVersion); + return secureWebResource.accept(REST_MIME_TYPE_JSON).get(ClientResponse.class); + }; + }; + response = MiscUtil.getUGILoginUser().doAs(action); + } else { + WebResource webResource = createWebResource(REST_URL_POLICY_GET_FOR_SERVICE_IF_UPDATED + serviceName + "/" + lastKnownVersion); + response = webResource.accept(REST_MIME_TYPE_JSON).get(ClientResponse.class); + } if(response != null && response.getStatus() == 200) { ret = response.getEntity(ServicePolicies.class); http://git-wip-us.apache.org/repos/asf/incubator-ranger/blob/8614032c/agents-common/src/main/java/org/apache/ranger/plugin/util/RangerRESTUtils.java ---------------------------------------------------------------------- diff --git a/agents-common/src/main/java/org/apache/ranger/plugin/util/RangerRESTUtils.java b/agents-common/src/main/java/org/apache/ranger/plugin/util/RangerRESTUtils.java index ad113fe..9a47280 100644 --- a/agents-common/src/main/java/org/apache/ranger/plugin/util/RangerRESTUtils.java +++ b/agents-common/src/main/java/org/apache/ranger/plugin/util/RangerRESTUtils.java @@ -39,8 +39,13 @@ public class RangerRESTUtils { public static final String REST_URL_POLICY_GET_FOR_SERVICE_IF_UPDATED = "/service/plugins/policies/download/"; public static final String REST_URL_SERVICE_GRANT_ACCESS = "/service/plugins/services/grant/"; public static final String REST_URL_SERVICE_REVOKE_ACCESS = "/service/plugins/services/revoke/"; + + public static final String REST_URL_POLICY_GET_FOR_SECURE_SERVICE_IF_UPDATED = "/service/plugins/secure/policies/download/"; + public static final String REST_URL_SECURE_SERVICE_GRANT_ACCESS = "/service/plugins/secure/services/grant/"; + public static final String REST_URL_SECURE_SERVICE_REVOKE_ACCESS = "/service/plugins/secure/services/revoke/"; public static final String REST_URL_GET_SERVICE_TAGS_IF_UPDATED = "/service/tags/download/"; + public static final String REST_URL_GET_SECURE_SERVICE_TAGS_IF_UPDATED = "/service/tags/secure/download/"; public static final String SERVICE_NAME_PARAM = "serviceName"; public static final String LAST_KNOWN_TAG_VERSION_PARAM = "lastKnownVersion"; public static final String PATTERN_PARAM = "pattern"; http://git-wip-us.apache.org/repos/asf/incubator-ranger/blob/8614032c/agents-common/src/main/resources/resourcenamemap.properties ---------------------------------------------------------------------- diff --git a/agents-common/src/main/resources/resourcenamemap.properties b/agents-common/src/main/resources/resourcenamemap.properties index d9b4d71..9bfaf61 100644 --- a/agents-common/src/main/resources/resourcenamemap.properties +++ b/agents-common/src/main/resources/resourcenamemap.properties @@ -24,6 +24,8 @@ dfs.secondary.namenode.kerberos.principal=hdfs-site.xml username=xalogin.xml keytabfile=xalogin.xml password=xalogin.xml +lookupprincipal=xalogin.xml +lookupkeytab=xalogin.xml hbase.master.kerberos.principal=hbase-site.xml hbase.rpc.engine=hbase-site.xml hbase.rpc.protection=hbase-site.xml http://git-wip-us.apache.org/repos/asf/incubator-ranger/blob/8614032c/embeddedwebserver/pom.xml ---------------------------------------------------------------------- diff --git a/embeddedwebserver/pom.xml b/embeddedwebserver/pom.xml index 9772075..6fde208 100644 --- a/embeddedwebserver/pom.xml +++ b/embeddedwebserver/pom.xml @@ -63,5 +63,20 @@ <artifactId>ecj</artifactId> <version>P20140317-1600</version> </dependency> + <dependency> + <groupId>log4j</groupId> + <artifactId>log4j</artifactId> + <version>${log4j.version}</version> + </dependency> + <dependency> + <groupId>org.apache.ranger</groupId> + <artifactId>ranger-plugins-audit</artifactId> + <version>${project.version}</version> + </dependency> + <dependency> + <groupId>org.apache.ranger</groupId> + <artifactId>ranger-plugins-common</artifactId> + <version>${project.version}</version> + </dependency> </dependencies> </project> http://git-wip-us.apache.org/repos/asf/incubator-ranger/blob/8614032c/embeddedwebserver/scripts/ranger-admin-services.sh ---------------------------------------------------------------------- diff --git a/embeddedwebserver/scripts/ranger-admin-services.sh b/embeddedwebserver/scripts/ranger-admin-services.sh index 92016b6..bd913af 100755 --- a/embeddedwebserver/scripts/ranger-admin-services.sh +++ b/embeddedwebserver/scripts/ranger-admin-services.sh @@ -53,12 +53,12 @@ then fi start() { - java -Dproc_rangeradmin ${JAVA_OPTS} -Dlogdir=${RANGER_ADMIN_LOG_DIR} -Dcatalina.base=${XAPOLICYMGR_EWS_DIR} -cp "${XAPOLICYMGR_EWS_DIR}/webapp/WEB-INF/classes/conf:${XAPOLICYMGR_EWS_DIR}/lib/*:${RANGER_JAAS_LIB_DIR}/*:${RANGER_JAAS_CONF_DIR}:${JAVA_HOME}/lib/*:$CLASSPATH" org.apache.ranger.server.tomcat.EmbeddedServer > ${RANGER_ADMIN_LOG_DIR}/catalina.out 2>&1 & + java -Dproc_rangeradmin ${JAVA_OPTS} -Dlogdir=${RANGER_ADMIN_LOG_DIR} -Dcatalina.base=${XAPOLICYMGR_EWS_DIR} -cp "${XAPOLICYMGR_EWS_DIR}/webapp/WEB-INF/classes/conf:${XAPOLICYMGR_EWS_DIR}/lib/*:${RANGER_JAAS_LIB_DIR}/*:${RANGER_JAAS_CONF_DIR}:${JAVA_HOME}/lib/*:${RANGER_HADOOP_CONF_DIR}/*:$CLASSPATH" org.apache.ranger.server.tomcat.EmbeddedServer > ${RANGER_ADMIN_LOG_DIR}/catalina.out 2>&1 & echo "Apache Ranger Admin has started." } stop(){ - java ${JAVA_OPTS} -Dlogdir=${RANGER_ADMIN_LOG_DIR} -Dcatalina.base=${XAPOLICYMGR_EWS_DIR} -cp "${XAPOLICYMGR_EWS_DIR}/webapp/WEB-INF/classes/conf:${XAPOLICYMGR_EWS_DIR}/lib/*:${RANGER_JAAS_LIB_DIR}/*:${RANGER_JAAS_CONF_DIR}:$CLASSPATH" org.apache.ranger.server.tomcat.StopEmbeddedServer > ${RANGER_ADMIN_LOG_DIR}/catalina.out 2>&1 + java ${JAVA_OPTS} -Dlogdir=${RANGER_ADMIN_LOG_DIR} -Dcatalina.base=${XAPOLICYMGR_EWS_DIR} -cp "${XAPOLICYMGR_EWS_DIR}/webapp/WEB-INF/classes/conf:${XAPOLICYMGR_EWS_DIR}/lib/*:${RANGER_JAAS_LIB_DIR}/*:${RANGER_JAAS_CONF_DIR}:${RANGER_HADOOP_CONF_DIR}/*:$CLASSPATH" org.apache.ranger.server.tomcat.StopEmbeddedServer > ${RANGER_ADMIN_LOG_DIR}/catalina.out 2>&1 echo "Apache Ranger Admin has been stopped." } http://git-wip-us.apache.org/repos/asf/incubator-ranger/blob/8614032c/embeddedwebserver/src/main/java/org/apache/ranger/server/tomcat/EmbeddedServer.java ---------------------------------------------------------------------- diff --git a/embeddedwebserver/src/main/java/org/apache/ranger/server/tomcat/EmbeddedServer.java b/embeddedwebserver/src/main/java/org/apache/ranger/server/tomcat/EmbeddedServer.java index d49ea61..19e944b 100644 --- a/embeddedwebserver/src/main/java/org/apache/ranger/server/tomcat/EmbeddedServer.java +++ b/embeddedwebserver/src/main/java/org/apache/ranger/server/tomcat/EmbeddedServer.java @@ -20,7 +20,9 @@ package org.apache.ranger.server.tomcat; import java.io.File; +import java.io.IOException; import java.net.URL; +import java.security.PrivilegedAction; import java.util.Date; import java.util.Iterator; import java.util.Properties; @@ -35,6 +37,10 @@ import org.apache.catalina.LifecycleException; import org.apache.catalina.connector.Connector; import org.apache.catalina.startup.Tomcat; import org.apache.catalina.valves.AccessLogValve; +import org.apache.hadoop.security.SecureClientLogin; + +import javax.security.auth.Subject; + import org.w3c.dom.Document; import org.w3c.dom.Element; import org.w3c.dom.Node; @@ -46,11 +52,19 @@ public class EmbeddedServer { .getName()); private static final String DEFAULT_CONFIG_FILENAME = "ranger-admin-site.xml"; + private static final String CORE_SITE_CONFIG_FILENAME = "core-site.xml"; private static final String DEFAULT_WEBAPPS_ROOT_FOLDER = "webapps"; private static String configFile = DEFAULT_CONFIG_FILENAME; + private static final String AUTH_TYPE_KERBEROS = "kerberos"; + private static final String AUTHENTICATION_TYPE = "hadoop.security.authentication"; + private static final String ADMIN_USER_PRINCIPAL = "ranger.admin.kerberos.principal"; + private static final String ADMIN_USER_KEYTAB = "ranger.admin.kerberos.keytab"; + + private static final String ADMIN_NAME_RULES = "hadoop.security.auth_to_local"; + private Properties serverConfigProperties = new Properties(); public static void main(String[] args) { @@ -61,14 +75,15 @@ public class EmbeddedServer { if (args.length > 0) { configFile = args[0]; } - loadRangerSiteConfig(); + loadConfig(CORE_SITE_CONFIG_FILENAME); + loadConfig(configFile); } public static int DEFAULT_SHUTDOWN_PORT = 6185; public static String DEFAULT_SHUTDOWN_COMMAND = "SHUTDOWN"; public void start() { - Tomcat server = new Tomcat(); + final Tomcat server = new Tomcat(); String logDir = null; logDir = getConfig("logdir"); @@ -198,16 +213,55 @@ public class EmbeddedServer { LOG.severe("Tomcat Server failed to start webapp:" + lce.toString()); lce.printStackTrace(); } - + + String keytab = getConfig(ADMIN_USER_KEYTAB); +// String principal = getConfig(ADMIN_USER_PRINCIPAL); + String principal = null; try { - server.start(); - server.getServer().await(); - shutdownServer(); - - } catch (LifecycleException e) { - LOG.severe("Tomcat Server failed to start:" + e.toString()); - e.printStackTrace(); - } + principal = SecureClientLogin.getPrincipal(getConfig(ADMIN_USER_PRINCIPAL), hostName); + } catch (IOException ignored) { + // do nothing + } + String nameRules = getConfig(ADMIN_NAME_RULES); + if(getConfig(AUTHENTICATION_TYPE) != null && getConfig(AUTHENTICATION_TYPE).trim().equalsIgnoreCase(AUTH_TYPE_KERBEROS) && SecureClientLogin.isKerberosCredentialExists(principal, keytab)){ + try{ + LOG.info("Provided Kerberos Credential : Principal = "+principal+" and Keytab = "+keytab); + Subject sub = SecureClientLogin.loginUserFromKeytab(principal, keytab, nameRules) ; + Subject.doAs(sub, new PrivilegedAction<Void>() { + @Override + public Void run() { + try{ + LOG.info("Starting Server using kerberos crendential"); + server.start(); + server.getServer().await(); + shutdownServer(); + }catch (LifecycleException e) { + LOG.severe("Tomcat Server failed to start:" + e.toString()); + e.printStackTrace(); + }catch (Exception e) { + LOG.severe("Tomcat Server failed to start:" + e.toString()); + e.printStackTrace(); + } + return null; + } + }); + }catch(Exception e){ + LOG.severe("Tomcat Server failed to start:" + e.toString()); + e.printStackTrace(); + } + }else{ + try{ + server.start(); + server.getServer().await(); + shutdownServer(); + } catch (LifecycleException e) { + LOG.severe("Tomcat Server failed to start:" + e.toString()); + e.printStackTrace(); + } catch (Exception e) { + LOG.severe("Tomcat Server failed to start:" + e.toString()); + e.printStackTrace(); + } + } } private String getKeystoreFile() { @@ -310,8 +364,8 @@ public class EmbeddedServer { } - public void loadRangerSiteConfig() { - String path = getResourceFileName(configFile); + public void loadConfig(String configFileName) { + String path = getResourceFileName(configFileName); try { DocumentBuilderFactory xmlDocumentBuilderFactory = DocumentBuilderFactory .newInstance(); http://git-wip-us.apache.org/repos/asf/incubator-ranger/blob/8614032c/hdfs-agent/src/main/java/org/apache/ranger/services/hdfs/client/HdfsClient.java ---------------------------------------------------------------------- diff --git a/hdfs-agent/src/main/java/org/apache/ranger/services/hdfs/client/HdfsClient.java b/hdfs-agent/src/main/java/org/apache/ranger/services/hdfs/client/HdfsClient.java index bc4f05a..4d563a3 100644 --- a/hdfs-agent/src/main/java/org/apache/ranger/services/hdfs/client/HdfsClient.java +++ b/hdfs-agent/src/main/java/org/apache/ranger/services/hdfs/client/HdfsClient.java @@ -35,6 +35,8 @@ import org.apache.hadoop.conf.Configuration; import org.apache.hadoop.fs.FileStatus; import org.apache.hadoop.fs.FileSystem; import org.apache.hadoop.fs.Path; +import org.apache.commons.lang.StringUtils; +import org.apache.hadoop.security.SecureClientLogin; import org.apache.hadoop.security.UserGroupInformation; import org.apache.ranger.plugin.client.BaseClient; import org.apache.ranger.plugin.client.HadoopException; @@ -252,18 +254,26 @@ public class HdfsClient extends BaseClient { public static void validateConnectionConfigs(Map<String, String> configs) throws IllegalArgumentException { + String lookupPrincipal=null; + try{ + lookupPrincipal = SecureClientLogin.getPrincipal(configs.get("lookupprincipal"), java.net.InetAddress.getLocalHost().getCanonicalHostName()); + }catch(Exception e){ + //do nothing + } + String lookupKeytab = configs.get("lookupkeytab"); + if(StringUtils.isEmpty(lookupPrincipal) || StringUtils.isEmpty(lookupKeytab)){ + // username + String username = configs.get("username") ; + if ((username == null || username.isEmpty())) { + throw new IllegalArgumentException("Value for username not specified"); + } - // username - String username = configs.get("username") ; - if ((username == null || username.isEmpty())) { - throw new IllegalArgumentException("Value for username not specified"); - } - - // password - String password = configs.get("password") ; - if ((password == null || password.isEmpty())) { - throw new IllegalArgumentException("Value for password not specified"); - } + // password + String password = configs.get("password") ; + if ((password == null || password.isEmpty())) { + throw new IllegalArgumentException("Value for password not specified"); + } + } // hadoop.security.authentication String authentication = configs.get("hadoop.security.authentication") ; http://git-wip-us.apache.org/repos/asf/incubator-ranger/blob/8614032c/plugin-kms/src/main/java/org/apache/ranger/services/kms/client/KMSClient.java ---------------------------------------------------------------------- diff --git a/plugin-kms/src/main/java/org/apache/ranger/services/kms/client/KMSClient.java b/plugin-kms/src/main/java/org/apache/ranger/services/kms/client/KMSClient.java index 061f95c..6a79433 100755 --- a/plugin-kms/src/main/java/org/apache/ranger/services/kms/client/KMSClient.java +++ b/plugin-kms/src/main/java/org/apache/ranger/services/kms/client/KMSClient.java @@ -29,8 +29,10 @@ import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; + import javax.security.auth.Subject; +import org.apache.commons.lang.StringUtils; import org.apache.hadoop.fs.Path; import org.apache.hadoop.security.HadoopKerberosName; import org.apache.hadoop.security.ProviderUtils; @@ -64,11 +66,18 @@ public class KMSClient { String provider; String username; String password; + String lookupPrincipal; + String lookupKeytab; + String nameRules; - public KMSClient(String provider, String username, String password) { + public KMSClient(String provider, String username, String password, String lookupPrincipal, String lookupKeytab, String nameRules) { this.provider = provider; this.username = username; this.password = password; + this.lookupPrincipal = lookupPrincipal; + this.lookupKeytab = lookupKeytab; + this.nameRules = nameRules; + if (LOG.isDebugEnabled()) { LOG.debug("Kms Client is build with url [" + provider + "] user: [" + username + "]"); @@ -164,9 +173,18 @@ public class KMSClient { String shortName = new HadoopKerberosName(username).getShortName(); uri = uri.concat("?doAs="+shortName); Subject sub = new Subject(); - if (username.contains("@")) { + if(!StringUtils.isEmpty(lookupPrincipal) && !StringUtils.isEmpty(lookupKeytab) && lookupPrincipal.contains("@")){ + if(StringUtils.isEmpty(nameRules)){ + nameRules = "DEFAULT"; + } + LOG.info("Init Lookup Login: security enabled, using lookupPrincipal/lookupKeytab"); + sub = SecureClientLogin.loginUserFromKeytab(lookupPrincipal, lookupKeytab, nameRules); + } + else if (username.contains("@")) { + LOG.info("Init Login: using username/password"); sub = SecureClientLogin.loginUserWithPassword(username, password); } else { + LOG.info("Init Login: security not enabled, using username"); sub = SecureClientLogin.login(username); } final WebResource webResource = client.resource(uri); @@ -324,7 +342,11 @@ public class KMSClient { String kmsUrl = configs.get("provider"); String kmsUserName = configs.get("username"); String kmsPassWord = configs.get("password"); - kmsClient = new KMSClient(kmsUrl, kmsUserName, kmsPassWord); + String lookupPrincipal = configs.get("lookupprincipal"); + String lookupKeytab = configs.get("lookupkeytab"); + String nameRules = configs.get("namerules"); + + kmsClient = new KMSClient(kmsUrl, kmsUserName, kmsPassWord, lookupPrincipal, lookupKeytab, nameRules); } return kmsClient; http://git-wip-us.apache.org/repos/asf/incubator-ranger/blob/8614032c/plugin-kms/src/main/java/org/apache/ranger/services/kms/client/KMSConnectionMgr.java ---------------------------------------------------------------------- diff --git a/plugin-kms/src/main/java/org/apache/ranger/services/kms/client/KMSConnectionMgr.java b/plugin-kms/src/main/java/org/apache/ranger/services/kms/client/KMSConnectionMgr.java index 94eaba4..5e96a1c 100755 --- a/plugin-kms/src/main/java/org/apache/ranger/services/kms/client/KMSConnectionMgr.java +++ b/plugin-kms/src/main/java/org/apache/ranger/services/kms/client/KMSConnectionMgr.java @@ -19,6 +19,7 @@ package org.apache.ranger.services.kms.client; +import org.apache.commons.lang.StringUtils; import org.apache.log4j.Logger; @@ -26,16 +27,18 @@ public class KMSConnectionMgr { public static final Logger LOG = Logger.getLogger(KMSConnectionMgr.class); - public static KMSClient getKMSClient(final String kmsURL, String userName, String password) { + public static KMSClient getKMSClient(final String kmsURL, String userName, String password, String lookupPrincipal, String lookupKeytab, String nameRules) { KMSClient kmsClient = null; if (kmsURL == null || kmsURL.isEmpty()) { LOG.error("Can not create KMSClient: kmsURL is empty"); - } else if (userName == null || userName.isEmpty()) { - LOG.error("Can not create KMSClient: kmsuserName is empty"); - } else if (password == null || password.isEmpty()) { - LOG.error("Can not create KMSClient: kmsPassWord is empty"); + } else if(StringUtils.isEmpty(lookupPrincipal)){ + if(userName == null || userName.isEmpty()) { + LOG.error("Can not create KMSClient: kmsuserName is empty"); + } else if (password == null || password.isEmpty()) { + LOG.error("Can not create KMSClient: kmsPassWord is empty"); + } } else { - kmsClient = new KMSClient(kmsURL, userName, password); + kmsClient = new KMSClient(kmsURL, userName, password, lookupPrincipal, lookupKeytab, nameRules); } return kmsClient; } http://git-wip-us.apache.org/repos/asf/incubator-ranger/blob/8614032c/plugin-kms/src/main/java/org/apache/ranger/services/kms/client/KMSResourceMgr.java ---------------------------------------------------------------------- diff --git a/plugin-kms/src/main/java/org/apache/ranger/services/kms/client/KMSResourceMgr.java b/plugin-kms/src/main/java/org/apache/ranger/services/kms/client/KMSResourceMgr.java index 007b97b..6b96515 100755 --- a/plugin-kms/src/main/java/org/apache/ranger/services/kms/client/KMSResourceMgr.java +++ b/plugin-kms/src/main/java/org/apache/ranger/services/kms/client/KMSResourceMgr.java @@ -72,14 +72,17 @@ public class KMSResourceMgr { String url = configs.get("provider"); String username = configs.get("username"); String password = configs.get("password"); - resultList = getKMSResource(url, username, password,kmsKeyName,kmsKeyList) ; + String lookupPrincipal = configs.get("lookupprincipal"); + String lookupKeytab = configs.get("lookupkeytab"); + String nameRules = configs.get("namerules"); + resultList = getKMSResource(url, username, password, lookupPrincipal, lookupKeytab, nameRules, kmsKeyName,kmsKeyList) ; } return resultList ; } - public static List<String> getKMSResource(String url, String username, String password,String kmsKeyName, List<String> kmsKeyList) { + public static List<String> getKMSResource(String url, String username, String password, String lookupPrincipal, String lookupKeytab, String nameRules, String kmsKeyName, List<String> kmsKeyList) { List<String> topologyList = null; - final KMSClient KMSClient = KMSConnectionMgr.getKMSClient(url, username, password); + final KMSClient KMSClient = KMSConnectionMgr.getKMSClient(url, username, password, lookupPrincipal, lookupKeytab, nameRules); synchronized(KMSClient){ topologyList = KMSClient.getKeyList(kmsKeyName, kmsKeyList); } http://git-wip-us.apache.org/repos/asf/incubator-ranger/blob/8614032c/security-admin/scripts/install.properties ---------------------------------------------------------------------- diff --git a/security-admin/scripts/install.properties b/security-admin/scripts/install.properties index 4070259..3913254 100644 --- a/security-admin/scripts/install.properties +++ b/security-admin/scripts/install.properties @@ -155,6 +155,17 @@ xa_ldap_ad_bind_password= xa_ldap_ad_referral= xa_ldap_ad_userSearchFilter= +#------------ Kerberos Config ----------------- +spnego_principal= +spnego_keytab= +token_valid=30 +cookie_domain= +cookie_path=/ +admin_principal= +admin_keytab= +lookup_principal= +lookup_keytab= +hadoop_conf=/etc/hadoop/conf # #-------- SSO CONFIG - Start ------------------ # http://git-wip-us.apache.org/repos/asf/incubator-ranger/blob/8614032c/security-admin/scripts/setup.sh ---------------------------------------------------------------------- diff --git a/security-admin/scripts/setup.sh b/security-admin/scripts/setup.sh index 832932c..51daf6d 100755 --- a/security-admin/scripts/setup.sh +++ b/security-admin/scripts/setup.sh @@ -117,6 +117,17 @@ sso_cookiename=$(get_prop 'sso_cookiename' $PROPFILE) sso_query_param_originalurl=$(get_prop 'sso_query_param_originalurl' $PROPFILE) RANGER_ADMIN_LOG_DIR=$(eval echo "$(get_prop 'RANGER_ADMIN_LOG_DIR' $PROPFILE)") +spnego_principal=$(get_prop 'spnego_principal' $PROPFILE) +spnego_keytab=$(get_prop 'spnego_keytab' $PROPFILE) +token_valid=$(get_prop 'token_valid' $PROPFILE) +cookie_domain=$(get_prop 'cookie_domain' $PROPFILE) +cookie_path=$(get_prop 'cookie_path' $PROPFILE) +admin_principal=$(get_prop 'admin_principal' $PROPFILE) +admin_keytab=$(get_prop 'admin_keytab' $PROPFILE) +lookup_principal=$(get_prop 'lookup_principal' $PROPFILE) +lookup_keytab=$(get_prop 'lookup_keytab' $PROPFILE) +hadoop_conf=$(get_prop 'hadoop_conf' $PROPFILE) + DB_HOST="${db_host}" check_ret_status(){ @@ -356,6 +367,69 @@ update_properties() { log "[E] $to_file_default does not exists" ; exit 1; fi + if [ "${spnego_principal}" != "" ] + then + propertyName=ranger.spnego.kerberos.principal + newPropertyValue="${spnego_principal}" + updatePropertyToFilePy $propertyName $newPropertyValue $to_file_ranger + fi + + if [ "${spnego_keytab}" != "" ] + then + propertyName=ranger.spnego.kerberos.keytab + newPropertyValue="${spnego_keytab}" + updatePropertyToFilePy $propertyName $newPropertyValue $to_file_ranger + fi + + if [ "${token_valid}" != "" ] + then + propertyName=ranger.admin.kerberos.token.valid.seconds + newPropertyValue="${token_valid}" + updatePropertyToFilePy $propertyName $newPropertyValue $to_file_ranger + fi + + if [ "${cookie_domain}" != "" ] + then + propertyName=ranger.admin.kerberos.cookie.domain + newPropertyValue="${cookie_domain}" + updatePropertyToFilePy $propertyName $newPropertyValue $to_file_ranger + fi + + if [ "${cookie_path}" != "" ] + then + propertyName=ranger.admin.kerberos.cookie.path + newPropertyValue="${cookie_path}" + updatePropertyToFilePy $propertyName $newPropertyValue $to_file_ranger + fi + + if [ "${admin_principal}" != "" ] + then + propertyName=ranger.admin.kerberos.principal + newPropertyValue="${admin_principal}" + updatePropertyToFilePy $propertyName $newPropertyValue $to_file_ranger + fi + + if [ "${admin_keytab}" != "" ] + then + propertyName=ranger.admin.kerberos.keytab + newPropertyValue="${admin_keytab}" + updatePropertyToFilePy $propertyName $newPropertyValue $to_file_ranger + fi + + if [ "${lookup_principal}" != "" ] + then + propertyName=ranger.lookup.kerberos.principal + newPropertyValue="${lookup_principal}" + updatePropertyToFilePy $propertyName $newPropertyValue $to_file_ranger + fi + + if [ "${lookup_keytab}" != "" ] + then + propertyName=ranger.lookup.kerberos.keytab + newPropertyValue="${lookup_keytab}" + updatePropertyToFilePy $propertyName $newPropertyValue $to_file_ranger + fi + if [ "${DB_FLAVOR}" == "MYSQL" ] then propertyName=ranger.jpa.jdbc.url @@ -965,8 +1039,27 @@ setup_install_files(){ mkdir -p ${WEBAPP_ROOT}/WEB-INF/classes/conf cp ${WEBAPP_ROOT}/WEB-INF/classes/conf.dist/* ${WEBAPP_ROOT}/WEB-INF/classes/conf fi + + echo "export RANGER_HADOOP_CONF_DIR=${hadoop_conf}" > ${WEBAPP_ROOT}/WEB-INF/classes/conf/ranger-admin-env-hadoopconfdir.sh + chmod a+rx ${WEBAPP_ROOT}/WEB-INF/classes/conf/ranger-admin-env-hadoopconfdir.sh + + hadoop_conf_file=${hadoop_conf}/core-site.xml + ranger_hadoop_conf_file=${WEBAPP_ROOT}/WEB-INF/classes/conf/core-site.xml + if [ -d ${WEBAPP_ROOT}/WEB-INF/classes/conf ]; then chown -R ${unix_user} ${WEBAPP_ROOT}/WEB-INF/classes/conf + if [ "${hadoop_conf}" == "" ] + then + log "[WARN] Property hadoop_conf not found. Creating blank core-site.xml." + echo "<configuration></configuration>" > ${WEBAPP_ROOT}/WEB-INF/classes/conf/core-site.xml + else + if [ -f ${hadoop_conf_file} ]; then + ln -sf ${hadoop_conf_file} ${WEBAPP_ROOT}/WEB-INF/classes/conf/core-site.xml + else + log "[WARN] core-site.xml file not found in provided hadoop_conf path. Creating blank core-site.xml" + echo "<configuration></configuration>" > ${WEBAPP_ROOT}/WEB-INF/classes/conf/core-site.xml + fi + fi fi if [ ! -d ${WEBAPP_ROOT}/WEB-INF/classes/lib ]; then http://git-wip-us.apache.org/repos/asf/incubator-ranger/blob/8614032c/security-admin/src/main/java/org/apache/ranger/biz/KmsKeyMgr.java ---------------------------------------------------------------------- diff --git a/security-admin/src/main/java/org/apache/ranger/biz/KmsKeyMgr.java b/security-admin/src/main/java/org/apache/ranger/biz/KmsKeyMgr.java index 3647bb1..82dc190 100755 --- a/security-admin/src/main/java/org/apache/ranger/biz/KmsKeyMgr.java +++ b/security-admin/src/main/java/org/apache/ranger/biz/KmsKeyMgr.java @@ -49,6 +49,7 @@ import org.apache.log4j.Logger; import org.apache.ranger.common.ContextUtil; import org.apache.ranger.common.MessageEnums; import org.apache.ranger.common.PasswordUtils; +import org.apache.ranger.common.PropertiesUtil; import org.apache.ranger.common.RESTErrorUtil; import org.apache.ranger.common.RangerConfigUtil; import org.apache.ranger.common.SortField; @@ -87,6 +88,7 @@ public class KmsKeyMgr { private static final String KMS_USERNAME = "username"; private static Map<String, String> providerList = new HashMap<String, String>(); private static int nextProvider = 0; + static final String NAME_RULES = "hadoop.security.auth_to_local"; @Autowired ServiceDBStore svcStore; @@ -526,8 +528,11 @@ public class KmsKeyMgr { private Subject getSubjectForKerberos(String provider) throws Exception{ String userName = getKMSUserName(provider); String password = getKMSPassword(provider); - if (KerberosName.getRules() == null) { + String nameRules = PropertiesUtil.getProperty(NAME_RULES); + if (StringUtils.isEmpty(nameRules)) { KerberosName.setRules("DEFAULT") ; + }else{ + KerberosName.setRules(nameRules); } Subject sub = new Subject(); if (userName.contains("@")) { http://git-wip-us.apache.org/repos/asf/incubator-ranger/blob/8614032c/security-admin/src/main/java/org/apache/ranger/biz/RangerBizUtil.java ---------------------------------------------------------------------- diff --git a/security-admin/src/main/java/org/apache/ranger/biz/RangerBizUtil.java b/security-admin/src/main/java/org/apache/ranger/biz/RangerBizUtil.java index 2980e51..63c630e 100644 --- a/security-admin/src/main/java/org/apache/ranger/biz/RangerBizUtil.java +++ b/security-admin/src/main/java/org/apache/ranger/biz/RangerBizUtil.java @@ -56,6 +56,7 @@ import org.apache.ranger.entity.XXServiceDef; import org.apache.ranger.entity.XXTrxLog; import org.apache.ranger.entity.XXUser; import org.apache.ranger.plugin.model.RangerBaseModelObject; +import org.apache.ranger.plugin.model.RangerService; import org.apache.ranger.plugin.store.EmbeddedServiceDefsUtil; import org.apache.ranger.service.AbstractBaseResourceService; import org.apache.ranger.view.VXDataObject; @@ -1538,5 +1539,26 @@ public class RangerBizUtil { MessageEnums.OPER_NOT_ALLOWED_FOR_STATE); } } + + public boolean isUserAllowed(RangerService rangerService, String cfgNameAllowedUsers) { + Map<String, String> map = rangerService.getConfigs(); + String user = null; + UserSessionBase userSession = ContextUtil.getCurrentUserSession(); + if(userSession != null){ + user = userSession.getLoginId(); + } + if (map != null && map.containsKey(cfgNameAllowedUsers)) { + String userNames = map.get(cfgNameAllowedUsers); + String[] userList = userNames.split(","); + if(userList != null){ + for (String u : userList) { + if (u.equals("*") || (user != null && u.equalsIgnoreCase(user))) { + return true; + } + } + } + } + return false; + } } http://git-wip-us.apache.org/repos/asf/incubator-ranger/blob/8614032c/security-admin/src/main/java/org/apache/ranger/biz/ServiceDBStore.java ---------------------------------------------------------------------- diff --git a/security-admin/src/main/java/org/apache/ranger/biz/ServiceDBStore.java b/security-admin/src/main/java/org/apache/ranger/biz/ServiceDBStore.java index 21ed686..7ef950a 100644 --- a/security-admin/src/main/java/org/apache/ranger/biz/ServiceDBStore.java +++ b/security-admin/src/main/java/org/apache/ranger/biz/ServiceDBStore.java @@ -28,10 +28,13 @@ import java.text.SimpleDateFormat; import javax.annotation.PostConstruct; import javax.servlet.http.HttpServletResponse; + 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.hadoop.security.SecureClientLogin; +import org.apache.hadoop.security.authentication.util.KerberosName; import org.apache.ranger.authorization.hadoop.config.RangerConfiguration; import org.apache.ranger.common.*; import org.apache.ranger.db.*; @@ -96,6 +99,11 @@ import org.apache.poi.ss.usermodel.Workbook; public class ServiceDBStore extends AbstractServiceStore { private static final Log LOG = LogFactory.getLog(ServiceDBStore.class); public static final String RANGER_TAG_EXPIRY_CONDITION_NAME = "accessed-after-expiry"; + private static final String LOOKUP_PRINCIPAL = "ranger.lookup.kerberos.principal"; + private static final String LOOKUP_KEYTAB = "ranger.lookup.kerberos.keytab"; + static final String RANGER_AUTH_TYPE = "hadoop.security.authentication"; + + private static final String KERBEROS_TYPE = "kerberos"; @Autowired RangerServiceDefService serviceDefService; @@ -1267,7 +1275,7 @@ public class ServiceDBStore extends AbstractServiceStore { vXUser = xUserService.populateViewBean(xxUser); } else { UserSessionBase usb = ContextUtil.getCurrentUserSession(); - if (usb != null && !usb.isUserAdmin()) { + if (usb != null && !usb.isUserAdmin() && !usb.isSpnegoEnabled()) { throw restErrorUtil.createRESTException("User does not exist with given username: [" + userName + "] please use existing user", MessageEnums.OPER_NO_PERMISSION); } @@ -2273,6 +2281,14 @@ public class ServiceDBStore extends AbstractServiceStore { List<String> users = new ArrayList<String>(); users.add(vXUser.getName()); + VXUser vXLookupUser = getLookupUser(); + if(vXLookupUser != null){ + users.add(vXLookupUser.getName()); + } + UserSessionBase usb = ContextUtil.getCurrentUserSession(); + if (usb != null && usb.isSpnegoEnabled()) { + users.add(usb.getLoginId()); + } policyItem.setUsers(users); List<XXAccessTypeDef> accessTypeDefs = daoMgr.getXXAccessTypeDef().findByServiceDefId(createdService.getType()); @@ -2291,6 +2307,39 @@ public class ServiceDBStore extends AbstractServiceStore { } policy = createPolicy(policy); } + + private VXUser getLookupUser() { + VXUser vXUser = null; + String authType = PropertiesUtil.getProperty(RANGER_AUTH_TYPE); + String lookupPrincipal = PropertiesUtil.getProperty(LOOKUP_PRINCIPAL); + String lookupKeytab = PropertiesUtil.getProperty(LOOKUP_KEYTAB); + if(!StringUtils.isEmpty(authType) && authType.equalsIgnoreCase(KERBEROS_TYPE)){ + if(SecureClientLogin.isKerberosCredentialExists(lookupPrincipal, lookupKeytab)){ + KerberosName krbName = new KerberosName(lookupPrincipal); + String lookupUser=null; + try { + lookupUser = krbName.getShortName(); + } catch (IOException e) { + throw restErrorUtil.createRESTException("Please provide proper value of lookup user principal : "+ lookupPrincipal, MessageEnums.INVALID_INPUT_DATA); + } + + if(LOG.isDebugEnabled()){ + LOG.debug("Checking for Lookup User : "+lookupUser); + } + if(!StringUtils.isEmpty(lookupUser)){ + XXUser xxUser = daoMgr.getXXUser().findByUserName(lookupUser); + if (xxUser != null) { + vXUser = xUserService.populateViewBean(xxUser); + } else { + vXUser = xUserMgr.createServiceConfigUser(lookupUser); + LOG.info("Creating Lookup User : "+vXUser.getName()); + } + } + } + } + return vXUser; + } + Map<String, RangerPolicyResource> createDefaultPolicyResource(List<RangerResourceDef> resourceHierarchy) throws Exception { Map<String, RangerPolicyResource> resourceMap = new HashMap<>(); http://git-wip-us.apache.org/repos/asf/incubator-ranger/blob/8614032c/security-admin/src/main/java/org/apache/ranger/biz/ServiceMgr.java ---------------------------------------------------------------------- diff --git a/security-admin/src/main/java/org/apache/ranger/biz/ServiceMgr.java b/security-admin/src/main/java/org/apache/ranger/biz/ServiceMgr.java index 16b00cd..e0f22d2 100644 --- a/security-admin/src/main/java/org/apache/ranger/biz/ServiceMgr.java +++ b/security-admin/src/main/java/org/apache/ranger/biz/ServiceMgr.java @@ -33,8 +33,10 @@ import java.util.concurrent.TimeUnit; import org.apache.commons.lang.StringUtils; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; +import org.apache.hadoop.security.SecureClientLogin; import org.apache.ranger.common.PropertiesUtil; import org.apache.ranger.common.TimedExecutor; +import org.apache.ranger.plugin.client.HadoopConfigHolder; import org.apache.ranger.plugin.client.HadoopException; import org.apache.ranger.plugin.model.RangerService; import org.apache.ranger.plugin.model.RangerServiceDef; @@ -55,6 +57,13 @@ public class ServiceMgr { private static final Log LOG = LogFactory.getLog(ServiceMgr.class); + private static final String LOOKUP_PRINCIPAL = "ranger.lookup.kerberos.principal"; + private static final String LOOKUP_KEYTAB = "ranger.lookup.kerberos.keytab"; + private static final String AUTHENTICATION_TYPE = "hadoop.security.authentication"; + private static final String KERBEROS_TYPE = "kerberos"; + static final String NAME_RULES = "hadoop.security.auth_to_local"; + static final String HOST_NAME = "ranger.service.host"; + @Autowired RangerServiceService rangerSvcService; @@ -72,11 +81,24 @@ public class ServiceMgr { RangerService service = svcDBStore.getServiceByName(serviceName); + String authType = PropertiesUtil.getProperty(AUTHENTICATION_TYPE); + String lookupPrincipal = SecureClientLogin.getPrincipal(PropertiesUtil.getProperty(LOOKUP_PRINCIPAL), PropertiesUtil.getProperty(HOST_NAME)); + String lookupKeytab = PropertiesUtil.getProperty(LOOKUP_KEYTAB); + String nameRules = PropertiesUtil.getProperty(NAME_RULES); + + if(!StringUtils.isEmpty(authType) && authType.trim().equalsIgnoreCase(KERBEROS_TYPE) && SecureClientLogin.isKerberosCredentialExists(lookupPrincipal, lookupKeytab)){ + if(service != null && service.getConfigs() != null){ + service.getConfigs().put(HadoopConfigHolder.RANGER_LOOKUP_PRINCIPAL, lookupPrincipal); + service.getConfigs().put(HadoopConfigHolder.RANGER_LOOKUP_KEYTAB, lookupKeytab); + service.getConfigs().put(HadoopConfigHolder.RANGER_NAME_RULES, nameRules); + } + } + Map<String, String> newConfigs = rangerSvcService.getConfigsWithDecryptedPassword(service); service.setConfigs(newConfigs); RangerBaseService svc = getRangerServiceByService(service, svcStore); - + if(LOG.isDebugEnabled()) { LOG.debug("==> ServiceMgr.lookupResource for Service: (" + svc + "Context: " + context + ")"); } @@ -101,6 +123,19 @@ public class ServiceMgr { public VXResponse validateConfig(RangerService service, ServiceStore svcStore) throws Exception { VXResponse ret = new VXResponse(); + String authType = PropertiesUtil.getProperty(AUTHENTICATION_TYPE); + String lookupPrincipal = SecureClientLogin.getPrincipal(PropertiesUtil.getProperty(LOOKUP_PRINCIPAL), PropertiesUtil.getProperty(HOST_NAME)); + String lookupKeytab = PropertiesUtil.getProperty(LOOKUP_KEYTAB); + String nameRules = PropertiesUtil.getProperty(NAME_RULES); + + if(!StringUtils.isEmpty(authType) && authType.trim().equalsIgnoreCase(KERBEROS_TYPE) && SecureClientLogin.isKerberosCredentialExists(lookupPrincipal, lookupKeytab)){ + if(service != null && service.getConfigs() != null){ + service.getConfigs().put(HadoopConfigHolder.RANGER_LOOKUP_PRINCIPAL, lookupPrincipal); + service.getConfigs().put(HadoopConfigHolder.RANGER_LOOKUP_KEYTAB, lookupKeytab); + service.getConfigs().put(HadoopConfigHolder.RANGER_NAME_RULES, nameRules); + } + } + Map<String, String> newConfigs = rangerSvcService.getConfigsWithDecryptedPassword(service); service.setConfigs(newConfigs); http://git-wip-us.apache.org/repos/asf/incubator-ranger/blob/8614032c/security-admin/src/main/java/org/apache/ranger/biz/SessionMgr.java ---------------------------------------------------------------------- diff --git a/security-admin/src/main/java/org/apache/ranger/biz/SessionMgr.java b/security-admin/src/main/java/org/apache/ranger/biz/SessionMgr.java index c461e83..106d910 100644 --- a/security-admin/src/main/java/org/apache/ranger/biz/SessionMgr.java +++ b/security-admin/src/main/java/org/apache/ranger/biz/SessionMgr.java @@ -77,6 +77,9 @@ public class SessionMgr { RangerDaoManager daoManager; @Autowired + XUserMgr xUserMgr; + + @Autowired AuthSessionService authSessionService; @Autowired @@ -118,6 +121,8 @@ public class SessionMgr { } if (newSessionCreation) { + + getSpnegoAuthCheckForAPI(currentLoginId, httpRequest); // Need to build the UserSession XXPortalUser gjUser = daoManager.getXXPortalUser().findByLoginId(currentLoginId); if (gjUser == null) { @@ -157,6 +162,9 @@ public class SessionMgr { userSession = new UserSessionBase(); userSession.setXXPortalUser(gjUser); userSession.setXXAuthSession(gjAuthSession); + if(httpRequest.getAttribute("spnegoEnabled") != null && (boolean)httpRequest.getAttribute("spnegoEnabled")){ + userSession.setSpnegoEnabled(true); + } resetUserSessionForProfiles(userSession); resetUserModulePermission(userSession); @@ -180,6 +188,17 @@ public class SessionMgr { return userSession; } + private void getSpnegoAuthCheckForAPI(String currentLoginId, HttpServletRequest request) { + + XXPortalUser gjUser = daoManager.getXXPortalUser().findByLoginId(currentLoginId); + if (gjUser == null && request.getAttribute("spnegoEnabled") != null && (boolean)request.getAttribute("spnegoEnabled")) { + if(logger.isDebugEnabled()){ + logger.debug("User : "+currentLoginId+" doesn't exist in Ranger DB So creating user as it's spnego authenticated"); + } + xUserMgr.createServiceConfigUser(currentLoginId); + } + } + public void resetUserModulePermission(UserSessionBase userSession) { XXUser xUser = daoManager.getXXUser().findByUserName(userSession.getLoginId()); http://git-wip-us.apache.org/repos/asf/incubator-ranger/blob/8614032c/security-admin/src/main/java/org/apache/ranger/biz/XUserMgr.java ---------------------------------------------------------------------- diff --git a/security-admin/src/main/java/org/apache/ranger/biz/XUserMgr.java b/security-admin/src/main/java/org/apache/ranger/biz/XUserMgr.java index 96ddf3f..571947c 100644 --- a/security-admin/src/main/java/org/apache/ranger/biz/XUserMgr.java +++ b/security-admin/src/main/java/org/apache/ranger/biz/XUserMgr.java @@ -1813,7 +1813,7 @@ public class XUserMgr extends XUserMgrBase { } } - protected VXUser createServiceConfigUser(String userName){ + public VXUser createServiceConfigUser(String userName){ if (userName == null || "null".equalsIgnoreCase(userName) || userName.trim().isEmpty()) { logger.error("User Name: "+userName); throw restErrorUtil.createRESTException("Please provide a valid username.",MessageEnums.INVALID_INPUT_DATA); http://git-wip-us.apache.org/repos/asf/incubator-ranger/blob/8614032c/security-admin/src/main/java/org/apache/ranger/common/UserSessionBase.java ---------------------------------------------------------------------- diff --git a/security-admin/src/main/java/org/apache/ranger/common/UserSessionBase.java b/security-admin/src/main/java/org/apache/ranger/common/UserSessionBase.java index 144a408..520aa88 100644 --- a/security-admin/src/main/java/org/apache/ranger/common/UserSessionBase.java +++ b/security-admin/src/main/java/org/apache/ranger/common/UserSessionBase.java @@ -40,6 +40,7 @@ public class UserSessionBase implements Serializable { private RangerUserPermission rangerUserPermission; int clientTimeOffsetInMinute = 0; private Boolean isSSOEnabled; + private Boolean isSpnegoEnabled = false; public Long getUserId() { if (xXPortalUser != null) { @@ -137,6 +138,14 @@ public class UserSessionBase implements Serializable { this.isSSOEnabled = isSSOEnabled; } + public Boolean isSpnegoEnabled() { + return isSpnegoEnabled; + } + + public void setSpnegoEnabled(Boolean isSpnegoEnabled) { + this.isSpnegoEnabled = isSpnegoEnabled; + } + public static class RangerUserPermission implements Serializable { private static final long serialVersionUID = 1L; http://git-wip-us.apache.org/repos/asf/incubator-ranger/blob/8614032c/security-admin/src/main/java/org/apache/ranger/rest/PublicAPIsv2.java ---------------------------------------------------------------------- diff --git a/security-admin/src/main/java/org/apache/ranger/rest/PublicAPIsv2.java b/security-admin/src/main/java/org/apache/ranger/rest/PublicAPIsv2.java index b7c1b59..4432bac 100644 --- a/security-admin/src/main/java/org/apache/ranger/rest/PublicAPIsv2.java +++ b/security-admin/src/main/java/org/apache/ranger/rest/PublicAPIsv2.java @@ -38,6 +38,7 @@ import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import javax.ws.rs.*; import javax.ws.rs.core.Context; + import java.util.List; @Path("public/v2") @@ -187,15 +188,15 @@ public class PublicAPIsv2 { @GET @Path("/api/service/") - @PreAuthorize("hasRole('ROLE_SYS_ADMIN')") @Produces({ "application/json", "application/xml" }) + @PreAuthorize("@rangerPreAuthSecurityHandler.isAPISpnegoAccessible()") public List<RangerService> searchServices(@Context HttpServletRequest request) { return serviceREST.getServices(request).getServices(); } @POST @Path("/api/service/") - @PreAuthorize("hasRole('ROLE_SYS_ADMIN')") + @PreAuthorize("@rangerPreAuthSecurityHandler.isAPISpnegoAccessible()") @Produces({ "application/json", "application/xml" }) public RangerService createService(RangerService service) { return serviceREST.createService(service);
