You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@ranger.apache.org by me...@apache.org on 2022/03/17 05:35:01 UTC
[ranger] branch master updated: RANGER-3628 : Support fine grain authorization for different solr objects
This is an automated email from the ASF dual-hosted git repository.
mehul pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/ranger.git
The following commit(s) were added to refs/heads/master by this push:
new 1f56fa1 RANGER-3628 : Support fine grain authorization for different solr objects
1f56fa1 is described below
commit 1f56fa1724cb83e142967b15b17a22ec01b65d00
Author: mateenmansoori <ma...@gmail.com>
AuthorDate: Thu Mar 10 16:43:08 2022 +0530
RANGER-3628 : Support fine grain authorization for different solr objects
Signed-off-by: Mehul Parikh <me...@apache.org>
---
.../service-defs/ranger-servicedef-solr.json | 87 +++++-
.../solr/authorizer/RangerSolrAuditHandler.java | 5 +-
.../solr/authorizer/RangerSolrAuthorizer.java | 304 +++++++++++----------
.../solr/authorizer/SolrAuthzUtil.java | 266 ++++++++++++++++++
.../ranger/services/solr/RangerServiceSolr.java | 2 +-
.../ranger/services/solr/RangerSolrConstants.java | 107 ++++++++
.../services/solr/client/ServiceSolrClient.java | 203 +++++++++++---
7 files changed, 788 insertions(+), 186 deletions(-)
diff --git a/agents-common/src/main/resources/service-defs/ranger-servicedef-solr.json b/agents-common/src/main/resources/service-defs/ranger-servicedef-solr.json
index dfaa2f7..4bbb6ff 100644
--- a/agents-common/src/main/resources/service-defs/ranger-servicedef-solr.json
+++ b/agents-common/src/main/resources/service-defs/ranger-servicedef-solr.json
@@ -26,6 +26,69 @@
"uiHint":"",
"label":"Solr Collection",
"description":"Solr Collection"
+ },
+ {
+ "itemId":101,
+ "name":"config",
+ "type":"string",
+ "level":10,
+ "parent":"",
+ "mandatory":true,
+ "lookupSupported":true,
+ "recursiveSupported":false,
+ "excludesSupported":true,
+ "matcher":"org.apache.ranger.plugin.resourcematcher.RangerDefaultResourceMatcher",
+ "matcherOptions":{
+ "wildCard":true,
+ "ignoreCase":true
+ },
+ "validationRegEx":"",
+ "validationMessage":"",
+ "uiHint":"",
+ "label":"Solr Config",
+ "description":"Solr Config"
+ },
+ {
+ "itemId":102,
+ "name":"schema",
+ "type":"string",
+ "level":10,
+ "parent":"",
+ "mandatory":true,
+ "lookupSupported":true,
+ "recursiveSupported":false,
+ "excludesSupported":true,
+ "matcher":"org.apache.ranger.plugin.resourcematcher.RangerDefaultResourceMatcher",
+ "matcherOptions":{
+ "wildCard":true,
+ "ignoreCase":true
+ },
+ "validationRegEx":"",
+ "validationMessage":"",
+ "uiHint":"",
+ "label":"Schema of a collection",
+ "description":"The schema of a collection"
+ },
+ {
+ "itemId":103,
+ "name":"admin",
+ "type":"string",
+ "level":10,
+ "parent":"",
+ "mandatory":true,
+ "lookupSupported":true,
+ "recursiveSupported":false,
+ "excludesSupported":true,
+ "matcher":"org.apache.ranger.plugin.resourcematcher.RangerDefaultResourceMatcher",
+ "matcherOptions":{
+ "wildCard":true,
+ "ignoreCase":true
+ },
+ "validationRegEx":"",
+ "validationMessage":"",
+ "uiHint":"",
+ "label":"Solr Admin",
+ "description":"Solr Admin"
}
],
@@ -39,19 +102,6 @@
"itemId":200,
"name":"update",
"label":"Update"
- },
- {
- "itemId":300,
- "name":"others",
- "label":"Others"
- },
- {
- "itemId":900,
- "name":"solr_admin",
- "label":"Solr Admin",
- "impliedGrants":[
- "query","update","others"
- ]
}
],
"configs":[
@@ -76,6 +126,17 @@
"label":"Password"
},
{
+ "itemId":300,
+ "name":"solr.zookeeper.quorum",
+ "type":"string",
+ "mandatory":false,
+ "defaultValue":"",
+ "validationRegEx":"",
+ "validationMessage":"",
+ "uiHint":"",
+ "label":"Solr Zookeeper Quorum"
+ },
+ {
"itemId":400,
"name":"solr.url",
"type":"string",
diff --git a/plugin-solr/src/main/java/org/apache/ranger/authorization/solr/authorizer/RangerSolrAuditHandler.java b/plugin-solr/src/main/java/org/apache/ranger/authorization/solr/authorizer/RangerSolrAuditHandler.java
index 359211c..a8f733f 100644
--- a/plugin-solr/src/main/java/org/apache/ranger/authorization/solr/authorizer/RangerSolrAuditHandler.java
+++ b/plugin-solr/src/main/java/org/apache/ranger/authorization/solr/authorizer/RangerSolrAuditHandler.java
@@ -24,6 +24,7 @@ import org.apache.ranger.plugin.audit.RangerMultiResourceAuditHandler;
import org.apache.ranger.plugin.policyengine.RangerAccessRequest;
import org.apache.ranger.plugin.policyengine.RangerAccessResourceImpl;
import org.apache.ranger.plugin.policyengine.RangerAccessResult;
+import org.apache.ranger.services.solr.RangerSolrConstants;
import java.util.Arrays;
import java.util.List;
@@ -45,7 +46,7 @@ public class RangerSolrAuditHandler extends RangerMultiResourceAuditHandler {
@Override
public void processResult(RangerAccessResult result) {
// We don't audit operation for user "solr" on collection "ranger_audits" to avoid recursive
- // loging due to updated of ranger_audits collection by solr plugin's audit creation.
+ // logging due to updated of ranger_audits collection by solr plugin's audit creation.
if (!isAuditingNeeded(result)) {
return;
}
@@ -57,7 +58,7 @@ public class RangerSolrAuditHandler extends RangerMultiResourceAuditHandler {
boolean ret = true;
RangerAccessRequest request = result.getAccessRequest();
RangerAccessResourceImpl resource = (RangerAccessResourceImpl) request.getResource();
- String resourceName = (String) resource.getValue(RangerSolrAuthorizer.KEY_COLLECTION);
+ String resourceName = (String) resource.getValue(RangerSolrConstants.COLLECTION_KEY);
String requestUser = request.getUser();
if (resourceName != null && resourceName.equals(RANGER_AUDIT_COLLECTION) && excludeUsers.contains(requestUser)) {
ret = false;
diff --git a/plugin-solr/src/main/java/org/apache/ranger/authorization/solr/authorizer/RangerSolrAuthorizer.java b/plugin-solr/src/main/java/org/apache/ranger/authorization/solr/authorizer/RangerSolrAuthorizer.java
index d4dd7b0..452287f 100644
--- a/plugin-solr/src/main/java/org/apache/ranger/authorization/solr/authorizer/RangerSolrAuthorizer.java
+++ b/plugin-solr/src/main/java/org/apache/ranger/authorization/solr/authorizer/RangerSolrAuthorizer.java
@@ -46,6 +46,7 @@ import org.apache.ranger.plugin.policyengine.RangerAccessResult;
import org.apache.ranger.plugin.service.RangerAuthContext;
import org.apache.ranger.plugin.service.RangerBasePlugin;
import org.apache.ranger.plugin.util.RangerPerfTracer;
+import org.apache.ranger.services.solr.RangerSolrConstants;
import org.apache.solr.common.SolrException;
import org.apache.solr.common.params.ModifiableSolrParams;
import org.apache.solr.common.params.SolrParams;
@@ -64,46 +65,11 @@ import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import javax.servlet.http.HttpServletRequest;
+import org.apache.solr.security.PermissionNameProvider;
public class RangerSolrAuthorizer extends SearchComponent implements AuthorizationPlugin {
private static final Logger logger = LoggerFactory
.getLogger(RangerSolrAuthorizer.class);
- private static final Logger PERF_SOLRAUTH_REQUEST_LOG = RangerPerfTracer.getPerfLogger("solrauth.request");
- public static final String SUPERUSER = System.getProperty("solr.authorization.superuser", "solr");
-
- public static final String AUTH_FIELD_PROP = "rangerAuthField";
- public static final String DEFAULT_AUTH_FIELD = "ranger_auth";
- public static final String ALL_ROLES_TOKEN_PROP = "allRolesToken";
- public static final String ENABLED_PROP = "enabled";
- public static final String MODE_PROP = "matchMode";
- public static final String DEFAULT_MODE_PROP = MatchType.DISJUNCTIVE.toString();
-
- public static final String ALLOW_MISSING_VAL_PROP = "allow_missing_val";
- public static final String TOKEN_COUNT_PROP = "tokenCountField";
- public static final String DEFAULT_TOKEN_COUNT_FIELD_PROP = "ranger_auth_count";
- public static final String QPARSER_PROP = "qParser";
-
- public static final String PROP_USE_PROXY_IP = "xasecure.solr.use_proxy_ip";
- public static final String PROP_PROXY_IP_HEADER = "xasecure.solr.proxy_ip_header";
- public static final String PROP_SOLR_APP_NAME = "xasecure.solr.app.name";
-
- public static final String KEY_COLLECTION = "collection";
-
- public static final String ACCESS_TYPE_CREATE = "create";
- public static final String ACCESS_TYPE_UPDATE = "update";
- public static final String ACCESS_TYPE_QUERY = "query";
- public static final String ACCESS_TYPE_OTHERS = "others";
- public static final String ACCESS_TYPE_ADMIN = "solr_admin";
-
- public static final String ATTRS_ENABLED_PROP = "attrs_enabled";
- public static final String FIELD_ATTR_MAPPINGS = "field_attr_mappings";
- public static final String FIELD_FILTER_TYPE = "filter_type";
- public static final String ATTR_NAMES = "attr_names";
- public static final String PERMIT_EMPTY_VALUES = "permit_empty";
- public static final String ALL_USERS_VALUE = "all_users_value";
- public static final String ATTRIBUTE_FILTER_REGEX = "value_filter_regex";
- public static final String AND_OP_QPARSER = "andQParser";
- public static final String EXTRA_OPTS = "extra_opts";
private List<FieldToAttributeMapping> fieldAttributeMappings = new LinkedList<>();
@@ -118,17 +84,12 @@ public class RangerSolrAuthorizer extends SearchComponent implements Authorizati
private String authField;
private String allRolesToken;
private boolean enabled;
- private MatchType matchMode;
+ private RangerSolrConstants.MatchType matchMode;
private String tokenCountField;
private boolean allowMissingValue;
private String qParserName;
private boolean attrsEnabled;
- private enum MatchType {
- DISJUNCTIVE,
- CONJUNCTIVE
- }
-
public RangerSolrAuthorizer() {
logger.info("RangerSolrAuthorizer()");
}
@@ -136,18 +97,18 @@ public class RangerSolrAuthorizer extends SearchComponent implements Authorizati
@Override
public void init(NamedList args) {
SolrParams params = args.toSolrParams();
- this.authField = params.get(AUTH_FIELD_PROP, DEFAULT_AUTH_FIELD);
- this.allRolesToken = params.get(ALL_ROLES_TOKEN_PROP, "");
- this.enabled = params.getBool(ENABLED_PROP, false);
- this.matchMode = MatchType.valueOf(params.get(MODE_PROP, DEFAULT_MODE_PROP).toUpperCase());
+ this.authField = params.get(RangerSolrConstants.AUTH_FIELD_PROP, RangerSolrConstants.DEFAULT_AUTH_FIELD);
+ this.allRolesToken = params.get(RangerSolrConstants.ALL_ROLES_TOKEN_PROP, "");
+ this.enabled = params.getBool(RangerSolrConstants.ENABLED_PROP, false);
+ this.matchMode = RangerSolrConstants.MatchType.valueOf(params.get(RangerSolrConstants.MODE_PROP, RangerSolrConstants.DEFAULT_MODE_PROP).toUpperCase());
- if (this.matchMode == MatchType.CONJUNCTIVE) {
- this.qParserName = params.get(QPARSER_PROP, "subset").trim();
- this.allowMissingValue = params.getBool(ALLOW_MISSING_VAL_PROP, false);
- this.tokenCountField = params.get(TOKEN_COUNT_PROP, DEFAULT_TOKEN_COUNT_FIELD_PROP);
+ if (this.matchMode == RangerSolrConstants.MatchType.CONJUNCTIVE) {
+ this.qParserName = params.get(RangerSolrConstants.QPARSER_PROP, "subset").trim();
+ this.allowMissingValue = params.getBool(RangerSolrConstants.ALLOW_MISSING_VAL_PROP, false);
+ this.tokenCountField = params.get(RangerSolrConstants.TOKEN_COUNT_PROP, RangerSolrConstants.DEFAULT_TOKEN_COUNT_FIELD_PROP);
}
- this.attrsEnabled = params.getBool(ATTRS_ENABLED_PROP, false);
+ this.attrsEnabled = params.getBool(RangerSolrConstants.ATTRS_ENABLED_PROP, false);
logger.info("RangerSolrAuthorizer.init(): authField={" + authField + "}, allRolesToken={" + allRolesToken +
"}, enabled={" + enabled + "}, matchType={" + matchMode + "}, qParserName={" + qParserName +
@@ -155,29 +116,29 @@ public class RangerSolrAuthorizer extends SearchComponent implements Authorizati
if (attrsEnabled) {
- if (params.get(FIELD_ATTR_MAPPINGS) != null) {
- logger.info("Solr params = " + params.get(FIELD_ATTR_MAPPINGS));
+ if (params.get(RangerSolrConstants.FIELD_ATTR_MAPPINGS) != null) {
+ logger.info("Solr params = " + params.get(RangerSolrConstants.FIELD_ATTR_MAPPINGS));
- NamedList mappings = checkAndGet(args, FIELD_ATTR_MAPPINGS);
+ NamedList mappings = checkAndGet(args, RangerSolrConstants.FIELD_ATTR_MAPPINGS);
Iterator<Map.Entry<String, NamedList>> iter = mappings.iterator();
while (iter.hasNext()) {
Map.Entry<String, NamedList> entry = iter.next();
String solrFieldName = entry.getKey();
- String attributeNames = checkAndGet(entry.getValue(), ATTR_NAMES);
- String filterType = checkAndGet(entry.getValue(), FIELD_FILTER_TYPE);
+ String attributeNames = checkAndGet(entry.getValue(), RangerSolrConstants.ATTR_NAMES);
+ String filterType = checkAndGet(entry.getValue(), RangerSolrConstants.FIELD_FILTER_TYPE);
boolean acceptEmpty = false;
- if (entry.getValue().getBooleanArg(PERMIT_EMPTY_VALUES) != null) {
- acceptEmpty = entry.getValue().getBooleanArg(PERMIT_EMPTY_VALUES);
+ if (entry.getValue().getBooleanArg(RangerSolrConstants.PERMIT_EMPTY_VALUES) != null) {
+ acceptEmpty = entry.getValue().getBooleanArg(RangerSolrConstants.PERMIT_EMPTY_VALUES);
}
- String allUsersValue = getWithDefault(entry.getValue(), ALL_USERS_VALUE, "");
- String regex = getWithDefault(entry.getValue(), ATTRIBUTE_FILTER_REGEX, "");
- String extraOpts = getWithDefault(entry.getValue(), EXTRA_OPTS, "");
+ String allUsersValue = getWithDefault(entry.getValue(), RangerSolrConstants.ALL_USERS_VALUE, "");
+ String regex = getWithDefault(entry.getValue(), RangerSolrConstants.ATTRIBUTE_FILTER_REGEX, "");
+ String extraOpts = getWithDefault(entry.getValue(), RangerSolrConstants.EXTRA_OPTS, "");
FieldToAttributeMapping mapping = new FieldToAttributeMapping(solrFieldName, attributeNames, filterType, acceptEmpty, allUsersValue, regex, extraOpts);
fieldAttributeMappings.add(mapping);
}
}
- this.andQParserName = this.<String>checkAndGet(args, AND_OP_QPARSER).trim();
+ this.andQParserName = this.<String>checkAndGet(args, RangerSolrConstants.AND_OP_QPARSER).trim();
}
}
@@ -208,15 +169,15 @@ public class RangerSolrAuthorizer extends SearchComponent implements Authorizati
}
useProxyIP = solrPlugin.getConfig().getBoolean(
- PROP_USE_PROXY_IP, useProxyIP);
+ RangerSolrConstants.PROP_USE_PROXY_IP, useProxyIP);
proxyIPHeader = solrPlugin.getConfig().get(
- PROP_PROXY_IP_HEADER, proxyIPHeader);
+ RangerSolrConstants.PROP_PROXY_IP_HEADER, proxyIPHeader);
// First get from the -D property
solrAppName = System.getProperty("solr.kerberos.jaas.appname",
solrAppName);
// Override if required from Ranger properties
solrAppName = solrPlugin.getConfig().get(
- PROP_SOLR_APP_NAME, solrAppName);
+ RangerSolrConstants.PROP_SOLR_APP_NAME, solrAppName);
logger.info("init(): useProxyIP=" + useProxyIP);
logger.info("init(): proxyIPHeader=" + proxyIPHeader);
@@ -264,15 +225,15 @@ public class RangerSolrAuthorizer extends SearchComponent implements Authorizati
try {
if (logger.isDebugEnabled()) {
logger.debug("==> RangerSolrAuthorizer.authorize()");
- logAuthorizationConext(context);
+ logAuthorizationContext(context);
}
RangerSolrAuditHandler auditHandler = new RangerSolrAuditHandler(solrPlugin.getConfig());
RangerPerfTracer perf = null;
- if(RangerPerfTracer.isPerfTraceEnabled(PERF_SOLRAUTH_REQUEST_LOG)) {
- perf = RangerPerfTracer.getPerfTracer(PERF_SOLRAUTH_REQUEST_LOG, "RangerSolrAuthorizer.authorize()");
+ if(RangerPerfTracer.isPerfTraceEnabled(RangerSolrConstants.PERF_SOLRAUTH_REQUEST_LOG)) {
+ perf = RangerPerfTracer.getPerfTracer(RangerSolrConstants.PERF_SOLRAUTH_REQUEST_LOG, "RangerSolrAuthorizer.authorize()");
}
String userName = getUserName(context);
@@ -291,38 +252,124 @@ public class RangerSolrAuthorizer extends SearchComponent implements Authorizati
ip = context.getRemoteAddr();
}
- // Create the list of requests for access check. Each field is
- // broken
- // into a request
+ // Create the list of requests for access check.
+ // We are going to build a list of ranger requests which represent the requested privileges.
+ // At the end will we iterate this list and invoke Ranger to check for privileges.
List<RangerAccessRequestImpl> rangerRequests = new ArrayList<RangerAccessRequestImpl>();
- List<CollectionRequest> collectionRequests = context.getCollectionRequests();
+ // The following logic is taken from Sentry See in SentrySolrPluginImpl.java.
+
+ if (context.getHandler() instanceof PermissionNameProvider) {
+ PermissionNameProvider.Name perm = ((PermissionNameProvider) context.getHandler()).getPermissionName(context);
+ switch (perm) {
+ case READ_PERM:
+ case UPDATE_PERM: {
+ RangerSolrConstants.ACCESS_TYPE accessType = (perm == PermissionNameProvider.Name.READ_PERM) ?
+ RangerSolrConstants.ACCESS_TYPE.QUERY : RangerSolrConstants.ACCESS_TYPE.UPDATE;
+ for (CollectionRequest req : context.getCollectionRequests()) {
+ rangerRequests.add(createRequest(userName, userGroups, ip, eventTime, context,
+ RangerSolrConstants.RESOURCE_TYPE.COLLECTION, req.collectionName, accessType));
+ }
+ break;
- if (CollectionUtils.isEmpty(collectionRequests)) {
- // if Collection is empty we set the collection to *. This happens when LIST is done.
- RangerAccessRequestImpl requestForCollection = createRequest(
- userName, userGroups, ip, eventTime, context,
- null);
- if (requestForCollection != null) {
- rangerRequests.add(requestForCollection);
- }
- } else {
- // Create the list of requests for access check. Each field is
- // broken
- // into a request
- for (CollectionRequest collectionRequest : context
- .getCollectionRequests()) {
-
- RangerAccessRequestImpl requestForCollection = createRequest(
- userName, userGroups, ip, eventTime, context,
- collectionRequest);
- if (requestForCollection != null) {
- rangerRequests.add(requestForCollection);
+ }
+ case SECURITY_EDIT_PERM: {
+ rangerRequests.add(createAdminRequest(userName, userGroups, ip, eventTime, context,
+ RangerSolrConstants.ADMIN_TYPE.SECURITY, RangerSolrConstants.ACCESS_TYPE.UPDATE));
+ break;
+ }
+ case SECURITY_READ_PERM: {
+ rangerRequests.add(createAdminRequest(userName, userGroups, ip, eventTime, context,
+ RangerSolrConstants.ADMIN_TYPE.SECURITY, RangerSolrConstants.ACCESS_TYPE.QUERY));
+ break;
+ }
+ case CORE_READ_PERM:
+ case CORE_EDIT_PERM:
+ case COLL_READ_PERM:
+ case COLL_EDIT_PERM: {
+ RangerSolrConstants.ADMIN_TYPE adminType = (perm == PermissionNameProvider.Name.COLL_READ_PERM
+ || perm == PermissionNameProvider.Name.COLL_EDIT_PERM)
+ ? RangerSolrConstants.ADMIN_TYPE.COLLECTIONS : RangerSolrConstants.ADMIN_TYPE.CORES;
+
+ RangerSolrConstants.ACCESS_TYPE accessType = (perm == PermissionNameProvider.Name.COLL_READ_PERM
+ || perm == PermissionNameProvider.Name.CORE_READ_PERM)
+ ? RangerSolrConstants.ACCESS_TYPE.QUERY : RangerSolrConstants.ACCESS_TYPE.UPDATE;
+
+ // add admin permissions to the ranger request list
+ rangerRequests.add(createAdminRequest(userName, userGroups, ip, eventTime, context,
+ adminType, accessType));
+
+ // add collection level permissions to the ranger request list
+ Map<String, RangerSolrConstants.ACCESS_TYPE> collectionsForAdminOpMap =
+ SolrAuthzUtil.getCollectionsForAdminOp(context);
+
+ String finalIp = ip;
+ collectionsForAdminOpMap.forEach((k, v) -> rangerRequests.add(createRequest(userName, userGroups,
+ finalIp, eventTime, context, RangerSolrConstants.RESOURCE_TYPE.COLLECTION, k, v)));
+ break;
+ }
+ case CONFIG_EDIT_PERM: {
+ for (String s: SolrAuthzUtil.getConfigAuthorizables(context)) {
+ rangerRequests.add(createRequest(userName, userGroups, ip, eventTime, context,
+ RangerSolrConstants.RESOURCE_TYPE.CONFIG, s, RangerSolrConstants.ACCESS_TYPE.UPDATE));
+ }
+ break;
+ }
+ case CONFIG_READ_PERM: {
+ for (String s: SolrAuthzUtil.getConfigAuthorizables(context)) {
+ rangerRequests.add(createRequest(userName, userGroups, ip, eventTime, context,
+ RangerSolrConstants.RESOURCE_TYPE.CONFIG, s, RangerSolrConstants.ACCESS_TYPE.QUERY));
+ }
+ break;
+ }
+ case SCHEMA_EDIT_PERM: {
+ for (String s: SolrAuthzUtil.getSchemaAuthorizables(context)) {
+ rangerRequests.add(createRequest(userName, userGroups, ip, eventTime, context,
+ RangerSolrConstants.RESOURCE_TYPE.SCHEMA, s, RangerSolrConstants.ACCESS_TYPE.UPDATE));
+ }
+ break;
+ }
+ case SCHEMA_READ_PERM: {
+ for (String s: SolrAuthzUtil.getSchemaAuthorizables(context)) {
+ rangerRequests.add(createRequest(userName, userGroups, ip, eventTime, context,
+ RangerSolrConstants.RESOURCE_TYPE.SCHEMA, s, RangerSolrConstants.ACCESS_TYPE.QUERY));
+ }
+ break;
+ }
+ case METRICS_HISTORY_READ_PERM:
+ case METRICS_READ_PERM: {
+ rangerRequests.add(createAdminRequest(userName, userGroups, ip, eventTime, context,
+ RangerSolrConstants.ADMIN_TYPE.METRICS, RangerSolrConstants.ACCESS_TYPE.QUERY));
+ break;
+ }
+ case AUTOSCALING_READ_PERM:
+ case AUTOSCALING_HISTORY_READ_PERM: {
+ rangerRequests.add(createAdminRequest(userName, userGroups, ip, eventTime, context,
+ RangerSolrConstants.ADMIN_TYPE.AUTOSCALING, RangerSolrConstants.ACCESS_TYPE.QUERY));
+ break;
+ }
+ case AUTOSCALING_WRITE_PERM: {
+ rangerRequests.add(createAdminRequest(userName, userGroups, ip, eventTime, context,
+ RangerSolrConstants.ADMIN_TYPE.AUTOSCALING, RangerSolrConstants.ACCESS_TYPE.UPDATE));
+ break;
+ }
+ case ALL: {
+ logger.debug("Not adding anything to the requested privileges, since permission is ALL");
}
}
-
+ } else {
+ logger.warn("Request Handler: " + context.getHandler().getClass().getName() + " is not an instance of PermissionNameProvider and so we are not able to" +
+ " authenticate the request. Check SOLR-11623 for more information.");
}
+ /*
+ * The switch-case statement above handles all possible permission types. Some of the request handlers
+ * in SOLR do not implement PermissionNameProvider interface and hence are incapable to providing the
+ * type of permission to be enforced for this request. This is a design limitation (or a bug) on the SOLR
+ * side. Until that issue is resolved, Solr/Sentry plugin needs to return OK for such requests.
+ * Ref: SOLR-11623
+ */
+
if (logger.isDebugEnabled()) {
logger.debug("rangerRequests.size()=" + rangerRequests.size());
}
@@ -371,7 +418,7 @@ public class RangerSolrAuthorizer extends SearchComponent implements Authorizati
}
String userName = getUserName(rb.req);
- if (SUPERUSER.equals(userName)) {
+ if (RangerSolrConstants.SUPERUSER.equals(userName)) {
return;
}
RangerSolrAuditHandler auditHandler = new RangerSolrAuditHandler(solrPlugin.getConfig());
@@ -408,7 +455,7 @@ public class RangerSolrAuthorizer extends SearchComponent implements Authorizati
Set<String> roles = getRolesForUser(userName);
if (roles != null && !roles.isEmpty()) {
String filterQuery;
- if (matchMode == MatchType.DISJUNCTIVE) {
+ if (matchMode == RangerSolrConstants.MatchType.DISJUNCTIVE) {
filterQuery = getDisjunctiveFilterQueryStr(roles);
} else {
filterQuery = getConjunctiveFilterQueryStr(roles);
@@ -495,7 +542,7 @@ public class RangerSolrAuthorizer extends SearchComponent implements Authorizati
/**
* @param context
*/
- private void logAuthorizationConext(AuthorizationContext context) {
+ private void logAuthorizationContext(AuthorizationContext context) {
try {
// Note: This method should be called with isDebugEnabled()
String collections = "";
@@ -545,14 +592,12 @@ public class RangerSolrAuthorizer extends SearchComponent implements Authorizati
//Exception ignored
}
RequestType requestType = context.getRequestType();
- String accessType = mapToRangerAccessType(context);
Principal principal = context.getUserPrincipal();
String contextString = new String("AuthorizationContext: ");
contextString = contextString + "context.getResource()= " + ((resource != null ) ? resource : "");
contextString = contextString + ", solarParams= " + (( solrParams != null ) ? solrParams : "");
contextString = contextString + ", requestType= " + (( requestType != null ) ? requestType : "");
- contextString = contextString + ", ranger.requestType= " + ((accessType != null ) ? accessType : "");
contextString = contextString + ", userPrincipal= " + ((principal != null ) ? principal : "");
contextString = contextString + ", userName= " + userName;
contextString = contextString + ", groups= " + groups;
@@ -573,41 +618,42 @@ public class RangerSolrAuthorizer extends SearchComponent implements Authorizati
* @param ip
* @param eventTime
* @param context
- * @param collectionRequest
+ * @param resourceType - the type of resource we are requesting permission to access (collection, config, field, etc.)
+ * @param resourceName - the name of the resource (e.g. collection) we are requesting permission to access
+ * @param accessType - the access type (QUERY, UPDATE, ALL (*)) we are requesting
* @return
*/
- private RangerAccessRequestImpl createRequest(String userName,
- Set<String> userGroups, String ip, Date eventTime,
- AuthorizationContext context, CollectionRequest collectionRequest) {
-
- String accessType = mapToRangerAccessType(context);
- String action = accessType;
+ private RangerAccessRequestImpl createRequest(String userName, Set<String> userGroups, String ip, Date eventTime, AuthorizationContext context, RangerSolrConstants.RESOURCE_TYPE resourceType,
+ String resourceName, RangerSolrConstants.ACCESS_TYPE accessType) {
+ String action = accessType.toString();
RangerAccessRequestImpl rangerRequest = createBaseRequest(userName,
userGroups, ip, eventTime);
RangerAccessResourceImpl rangerResource = new RangerAccessResourceImpl();
- if (collectionRequest == null) {
- rangerResource.setValue(KEY_COLLECTION, "*");
- } else {
- rangerResource.setValue(KEY_COLLECTION, collectionRequest.collectionName);
- }
+
+ rangerResource.setValue(resourceType.toString(), resourceName);
+
rangerRequest.setResource(rangerResource);
- rangerRequest.setAccessType(accessType);
+ rangerRequest.setAccessType(accessType.toString());
rangerRequest.setAction(action);
return rangerRequest;
}
- private RangerAccessRequestImpl createQueryRequest(String userName,
- Set<String> userGroups, String ip, Date eventTime,
- SolrQueryRequest queryRequest) {
- String accessType = ACCESS_TYPE_OTHERS;
- String action = ACCESS_TYPE_QUERY;
+ private RangerAccessRequestImpl createAdminRequest(String userName, Set<String> userGroups, String ip, Date eventTime, AuthorizationContext context, RangerSolrConstants.ADMIN_TYPE adminType,
+ RangerSolrConstants.ACCESS_TYPE accessType) {
+ return createRequest(userName, userGroups, ip, eventTime, context, RangerSolrConstants.RESOURCE_TYPE.ADMIN,
+ adminType.toString(), accessType);
+ }
+
+ private RangerAccessRequestImpl createQueryRequest(String userName, Set<String> userGroups, String ip, Date eventTime, SolrQueryRequest queryRequest) {
+ String accessType = RangerSolrConstants.ACCESS_TYPE.QUERY.toString();
+ String action = RangerSolrConstants.ACCESS_TYPE.QUERY.toString();
RangerAccessRequestImpl rangerRequest = createBaseRequest(userName,
userGroups, ip, eventTime);
RangerAccessResourceImpl rangerResource = new RangerAccessResourceImpl();
rangerResource.setServiceDef(solrPlugin.getServiceDef());
- rangerResource.setValue(KEY_COLLECTION, queryRequest.getCore().getCoreDescriptor().getCollectionName());
+ rangerResource.setValue(RangerSolrConstants.RESOURCE_TYPE.COLLECTION.toString(), queryRequest.getCore().getCoreDescriptor().getCollectionName());
rangerRequest.setResource(rangerResource);
rangerRequest.setAccessType(accessType);
rangerRequest.setAction(action);
@@ -649,27 +695,7 @@ public class RangerSolrAuthorizer extends SearchComponent implements Authorizati
return MiscUtil.getGroupsForRequestUser(name);
}
- String mapToRangerAccessType(AuthorizationContext context) {
- String accessType = ACCESS_TYPE_OTHERS;
-
- RequestType requestType = context.getRequestType();
- if (RequestType.ADMIN.equals(requestType)) {
- accessType = ACCESS_TYPE_ADMIN;
- } else if (RequestType.READ.equals(requestType)) {
- accessType = ACCESS_TYPE_QUERY;
- } else if (RequestType.WRITE.equals(requestType)) {
- accessType = ACCESS_TYPE_UPDATE;
- } else if (RequestType.UNKNOWN.equals(requestType)) {
- logger.info("UNKNOWN request type. Mapping it to " + accessType
- + ". Resource=" + context.getResource());
- accessType = ACCESS_TYPE_OTHERS;
- } else {
- logger.info("Request type is not supported. requestType="
- + requestType + ". Mapping it to " + accessType
- + ". Resource=" + context.getResource());
- }
- return accessType;
- }
+
private void addDisjunctiveRawClause(StringBuilder builder, String value) {
// requires a space before the first term, so the
@@ -724,7 +750,7 @@ public class RangerSolrAuthorizer extends SearchComponent implements Authorizati
// If a local request, treat it like a super user request; i.e. it is equivalent to an
// http request from the same process.
if (req instanceof LocalSolrQueryRequest) {
- return SUPERUSER;
+ return RangerSolrConstants.SUPERUSER;
}
SolrCore solrCore = req.getCore();
diff --git a/plugin-solr/src/main/java/org/apache/ranger/authorization/solr/authorizer/SolrAuthzUtil.java b/plugin-solr/src/main/java/org/apache/ranger/authorization/solr/authorizer/SolrAuthzUtil.java
new file mode 100644
index 0000000..ee910d5
--- /dev/null
+++ b/plugin-solr/src/main/java/org/apache/ranger/authorization/solr/authorizer/SolrAuthzUtil.java
@@ -0,0 +1,266 @@
+/*
+ * 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.authorization.solr.authorizer;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import org.apache.ranger.services.solr.RangerSolrConstants;
+import org.apache.solr.common.params.CollectionParams.CollectionAction;
+import org.apache.solr.common.params.CoreAdminParams.CoreAdminAction;
+import org.apache.solr.common.params.CollectionAdminParams;
+import org.apache.solr.common.params.CommonParams;
+import org.apache.solr.common.params.CoreAdminParams;
+import org.apache.solr.common.params.SolrParams;
+import org.apache.solr.handler.admin.ConfigSetsHandler;
+import org.apache.solr.security.AuthorizationContext;
+import org.apache.solr.security.AuthorizationContext.CollectionRequest;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Solr authorization framework does not currently support fine-grained authorization.
+ * Specifically it does not provide the resource names consistently. This utility class
+ * extracts the resource names for specific APIs by introspecting the {@linkplain SolrParams}
+ * passed as part of {@linkplain AuthorizationContext}. This class is taken from the Sentry implementation
+ * to provide consistent behavior between Sentry-Solr and Ranger-Solr implementations.
+ * It can possibly be removed once SOLR-11543 is available.
+ */
+class SolrAuthzUtil {
+ private static final Logger LOG = LoggerFactory.getLogger(SolrAuthzUtil.class);
+
+ /**
+ * This method returns a list of Strings containing a name of Solr Config entities associated with the current
+ * operation.
+ */
+ static List<String> getConfigAuthorizables (AuthorizationContext ctx) {
+ List<String> result = new ArrayList<>(1);
+ if (ctx.getHandler() instanceof ConfigSetsHandler) { // For Solr configset APIs
+ String name = ctx.getParams().get(CommonParams.NAME);
+ if (name != null) {
+ result.add(name);
+ }
+ } else { // For Solr config APIs
+ for (CollectionRequest r : ctx.getCollectionRequests()) {
+ result.add(r.collectionName);
+ }
+ }
+ if (result.isEmpty()) {
+ LOG.debug("Missing collection name for the config operation with authorization context {}."
+ + " Using * permissions for authorization check", toString(ctx));
+ result.add("*");
+ }
+
+ return result;
+ }
+
+ /**
+ * This method returns a List of Strings containing the names of schema entities associated with the current
+ * operation.
+ */
+ static List<String> getSchemaAuthorizables (AuthorizationContext ctx) {
+ List<String> result = new ArrayList<String>(1);
+ for (CollectionRequest r : ctx.getCollectionRequests()) {
+ result.add(r.collectionName);
+ }
+ if (result.isEmpty()) {
+ LOG.debug("Missing collection name for the schema operation with authorization context {}."
+ + " Using * permissions for authorization check", toString(ctx));
+ result.add("*");
+ }
+
+ return result;
+ }
+
+ /**
+ * This method extracts the Collection entity names
+ * associated with this admin request and return a mapping of entity_name -> expected_auth_action.
+ * This is used by Ranger-Solr authorization plugin to further restrict Solr admin operations.
+ */
+ static Map<String, RangerSolrConstants.ACCESS_TYPE> getCollectionsForAdminOp(AuthorizationContext ctx) {
+ String actionName = ctx.getParams().get(CoreAdminParams.ACTION);
+ CollectionAction action = CollectionAction.get(actionName);
+ if (action != null) {
+ switch (action) {
+ case LISTSNAPSHOTS:
+ case BACKUP: {
+ String name = ctx.getParams().get(CollectionAdminParams.COLLECTION);
+ return (name != null) ? Collections.singletonMap(name, RangerSolrConstants.ACCESS_TYPE.QUERY)
+ : Collections.emptyMap();
+ }
+
+ case MIGRATE: {
+ Map<String, RangerSolrConstants.ACCESS_TYPE> result = new HashMap<>();
+ String source = ctx.getParams().get(CollectionAdminParams.COLLECTION);
+ String target = ctx.getParams().get("target."+CollectionAdminParams.COLLECTION);
+ if (source != null) {
+ result.put (source,RangerSolrConstants.ACCESS_TYPE.QUERY);
+ }
+ if (target != null) {
+ result.put (source, RangerSolrConstants.ACCESS_TYPE.UPDATE);
+ }
+ return result;
+ }
+
+ case DELETE:
+ case CREATEALIAS:
+ case DELETEALIAS:
+ case CREATESHARD:
+ case DELETESHARD:
+ case SPLITSHARD:
+ case RELOAD:
+ case CREATE: {
+ String name = ctx.getParams().get(CommonParams.NAME);
+ return (name != null) ? Collections.singletonMap(name, RangerSolrConstants.ACCESS_TYPE.UPDATE)
+ : Collections.emptyMap();
+ }
+
+ case DELETESNAPSHOT:
+ case CREATESNAPSHOT:
+ case SYNCSHARD:
+ case MOVEREPLICA:
+ case RESTORE:
+ case MIGRATESTATEFORMAT:
+ case FORCELEADER:
+ case REBALANCELEADERS:
+ case BALANCESHARDUNIQUE:
+ case ADDREPLICAPROP:
+ case DELETEREPLICAPROP:
+ case ADDREPLICA:
+ case DELETEREPLICA:
+ case MODIFYCOLLECTION: {
+ String name = ctx.getParams().get(CollectionAdminParams.COLLECTION);
+ return (name != null) ? Collections.singletonMap(name, RangerSolrConstants.ACCESS_TYPE.UPDATE)
+ : Collections.emptyMap();
+ }
+
+ case MOCK_COLL_TASK:
+ case MOCK_REPLICA_TASK:
+ case MOCK_SHARD_TASK:
+ case REPLACENODE:
+ case DELETENODE:
+ case ADDROLE:
+ case REMOVEROLE:
+ case REQUESTSTATUS:
+ case DELETESTATUS:
+ case LIST:
+ case LISTALIASES:
+ case CLUSTERPROP:
+ case OVERSEERSTATUS:
+ case CLUSTERSTATUS: {
+ return Collections.emptyMap();
+ }
+ }
+ }
+
+ return Collections.emptyMap();
+ }
+
+ /**
+ * This method extracts the names of Solr Collection entities
+ * associated with this admin request and return a mapping of entity_name -> expected_auth_action.
+ * This is used by Ranger-Solr authorization plugin to further restrict Solr admin operations.
+ */
+ static Map<String, RangerSolrConstants.ACCESS_TYPE> getCoresForAdminOp(AuthorizationContext ctx) {
+ String actionName = ctx.getParams().get(CoreAdminParams.ACTION);
+ CoreAdminAction action = CoreAdminAction.get(actionName);
+ if (action != null) {
+ switch (action) {
+ case REQUESTBUFFERUPDATES:
+ case REQUESTAPPLYUPDATES:
+ case CREATE: {
+ String coreName = ctx.getParams().get(CoreAdminParams.NAME);
+ return (coreName != null) ? Collections.singletonMap(coreName, RangerSolrConstants.ACCESS_TYPE.UPDATE)
+ : Collections.emptyMap();
+ }
+
+ case REQUESTSTATUS:
+ case OVERSEEROP:
+ case INVOKE:
+ // TODO - is this correct ?
+ case DELETEALIAS: {
+ return Collections.emptyMap();
+ }
+
+ case REQUESTSYNCSHARD:
+ case REJOINLEADERELECTION:
+ case PREPRECOVERY:
+ case FORCEPREPAREFORLEADERSHIP:
+ case CREATESNAPSHOT:
+ case DELETESNAPSHOT:
+ case RESTORECORE:
+ case REQUESTRECOVERY:
+ case SPLIT:
+ case MERGEINDEXES:
+ case UNLOAD:
+ case RENAME:
+ case RELOAD: {
+ String coreName = ctx.getParams().get(CoreAdminParams.CORE);
+ return (coreName != null) ? Collections.singletonMap(coreName, RangerSolrConstants.ACCESS_TYPE.UPDATE)
+ : Collections.emptyMap();
+ }
+
+ case LISTSNAPSHOTS:
+ case BACKUPCORE:
+ case STATUS: {
+ String coreName = ctx.getParams().get(CoreAdminParams.CORE);
+ return (coreName != null) ? Collections.singletonMap(coreName, RangerSolrConstants.ACCESS_TYPE.QUERY)
+ : Collections.emptyMap();
+ }
+ case SWAP: {
+ Map<String, RangerSolrConstants.ACCESS_TYPE> result = new HashMap<>();
+ String core1 = ctx.getParams().get(CoreAdminParams.CORE);
+ String core2 = ctx.getParams().get("other");
+ if (core1 != null) {
+ result.put(core1, RangerSolrConstants.ACCESS_TYPE.UPDATE);
+ }
+ if (core2 != null) {
+ result.put(core2, RangerSolrConstants.ACCESS_TYPE.UPDATE);
+ }
+ return result;
+ }
+ }
+ }
+
+ return Collections.emptyMap();
+ }
+
+
+ static String toString(AuthorizationContext ctx) {
+ StringBuilder builder = new StringBuilder();
+ builder.append("AuthorizationContext {");
+ builder.append("userPrincipal : ");
+ builder.append(ctx.getUserPrincipal().getName());
+ // NOTE - comment out the code until SOLR-10814 is fixed.
+ //builder.append(", userName : ");
+ //builder.append(ctx.getUserName());
+ builder.append(", collections : ");
+ builder.append(ctx.getCollectionRequests());
+ builder.append(", handler : ");
+ builder.append(ctx.getHandler());
+ builder.append(", HTTP method : ");
+ builder.append(ctx.getHttpMethod());
+ builder.append("}");
+
+ return builder.toString();
+ }
+
+
+}
diff --git a/plugin-solr/src/main/java/org/apache/ranger/services/solr/RangerServiceSolr.java b/plugin-solr/src/main/java/org/apache/ranger/services/solr/RangerServiceSolr.java
index 97909ae..3a8f9b4 100644
--- a/plugin-solr/src/main/java/org/apache/ranger/services/solr/RangerServiceSolr.java
+++ b/plugin-solr/src/main/java/org/apache/ranger/services/solr/RangerServiceSolr.java
@@ -40,7 +40,7 @@ import org.slf4j.LoggerFactory;
public class RangerServiceSolr extends RangerBaseService {
private static final Logger LOG = LoggerFactory.getLogger(RangerServiceSolr.class);
- public static final String ACCESS_TYPE_QUERY = "query";
+ public static final String ACCESS_TYPE_QUERY = RangerSolrConstants.ACCESS_TYPE.QUERY.toString();
public RangerServiceSolr() {
super();
diff --git a/plugin-solr/src/main/java/org/apache/ranger/services/solr/RangerSolrConstants.java b/plugin-solr/src/main/java/org/apache/ranger/services/solr/RangerSolrConstants.java
new file mode 100644
index 0000000..818cb82
--- /dev/null
+++ b/plugin-solr/src/main/java/org/apache/ranger/services/solr/RangerSolrConstants.java
@@ -0,0 +1,107 @@
+/*
+ * 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.services.solr;
+
+import org.apache.ranger.plugin.util.RangerPerfTracer;
+import org.slf4j.Logger;
+
+import java.util.List;
+import java.util.stream.Collectors;
+import java.util.stream.Stream;
+
+public class RangerSolrConstants {
+
+ // Constants from RangerSolrAuthorizer
+ public static final Logger PERF_SOLRAUTH_REQUEST_LOG = RangerPerfTracer.getPerfLogger("solrauth.request");
+ public static final String SUPERUSER = System.getProperty("solr.authorization.superuser", "solr");
+
+ public static final String AUTH_FIELD_PROP = "rangerAuthField";
+ public static final String DEFAULT_AUTH_FIELD = "ranger_auth";
+ public static final String ALL_ROLES_TOKEN_PROP = "allRolesToken";
+ public static final String ENABLED_PROP = "enabled";
+ public static final String MODE_PROP = "matchMode";
+ public static final String DEFAULT_MODE_PROP = MatchType.DISJUNCTIVE.toString();
+
+ public static final String ALLOW_MISSING_VAL_PROP = "allow_missing_val";
+ public static final String TOKEN_COUNT_PROP = "tokenCountField";
+ public static final String DEFAULT_TOKEN_COUNT_FIELD_PROP = "ranger_auth_count";
+ public static final String QPARSER_PROP = "qParser";
+
+ public static final String PROP_USE_PROXY_IP = "xasecure.solr.use_proxy_ip";
+ public static final String PROP_PROXY_IP_HEADER = "xasecure.solr.proxy_ip_header";
+ public static final String PROP_SOLR_APP_NAME = "xasecure.solr.app.name";
+
+ public static final String ATTRS_ENABLED_PROP = "attrs_enabled";
+ public static final String FIELD_ATTR_MAPPINGS = "field_attr_mappings";
+ public static final String FIELD_FILTER_TYPE = "filter_type";
+ public static final String ATTR_NAMES = "attr_names";
+ public static final String PERMIT_EMPTY_VALUES = "permit_empty";
+ public static final String ALL_USERS_VALUE = "all_users_value";
+ public static final String ATTRIBUTE_FILTER_REGEX = "value_filter_regex";
+ public static final String AND_OP_QPARSER = "andQParser";
+ public static final String EXTRA_OPTS = "extra_opts";
+
+ public enum MatchType {
+ DISJUNCTIVE,
+ CONJUNCTIVE
+ }
+
+ // Constants from ServiceSolrClient
+ public enum RESOURCE_TYPE {
+ COLLECTION, FIELD, CONFIG, ADMIN, SCHEMA;
+
+ public String toString() {
+ return name().toLowerCase();
+ }
+ }
+
+ public enum ADMIN_TYPE {
+ COLLECTIONS, CORES, METRICS, SECURITY, AUTOSCALING;
+
+ public static final List<String> VALUE_LIST = Stream.of(ADMIN_TYPE.values())
+ .map(Enum::toString)
+ .collect(Collectors.toList());
+
+ @Override
+ public String toString() {
+ return name().toLowerCase();
+ }
+ }
+
+ public enum ACCESS_TYPE {
+ QUERY, UPDATE;
+
+ @Override
+ public String toString() {
+ return name().toLowerCase();
+ }
+ }
+
+ public static final String errMessage = " You can still save the repository and start creating "
+ + "policies, but you would not be able to use autocomplete for "
+ + "resource names. Check server logs for more info.";
+
+ public static final String COLLECTION_KEY = "collection";
+ public static final String FIELD_KEY = "field";
+ public static final String CONFIG_KEY = "config";
+ public static final String ADMIN_KEY = "admin";
+ public static final String SCHEMA_KEY = "schema";
+ public static final long LOOKUP_TIMEOUT_SEC = 5;
+}
diff --git a/plugin-solr/src/main/java/org/apache/ranger/services/solr/client/ServiceSolrClient.java b/plugin-solr/src/main/java/org/apache/ranger/services/solr/client/ServiceSolrClient.java
index 5f7b9b9..c3e7d08 100644
--- a/plugin-solr/src/main/java/org/apache/ranger/services/solr/client/ServiceSolrClient.java
+++ b/plugin-solr/src/main/java/org/apache/ranger/services/solr/client/ServiceSolrClient.java
@@ -43,6 +43,7 @@ import org.apache.ranger.plugin.client.HadoopException;
import org.apache.ranger.plugin.service.ResourceLookupContext;
import org.apache.ranger.plugin.util.PasswordUtils;
import org.apache.ranger.plugin.util.TimedEventUtil;
+import org.apache.ranger.services.solr.RangerSolrConstants;
import org.apache.solr.client.solrj.SolrClient;
import org.apache.solr.client.solrj.SolrQuery;
import org.apache.solr.client.solrj.SolrResponse;
@@ -52,6 +53,7 @@ import org.apache.solr.client.solrj.impl.HttpSolrClient;
import org.apache.solr.client.solrj.impl.Krb5HttpClientBuilder;
import org.apache.solr.client.solrj.impl.SolrHttpClientBuilder;
import org.apache.solr.client.solrj.request.CollectionAdminRequest;
+import org.apache.solr.client.solrj.request.ConfigSetAdminRequest;
import org.apache.solr.client.solrj.request.CoreAdminRequest;
import org.apache.solr.client.solrj.request.QueryRequest;
import org.apache.solr.client.solrj.response.CoreAdminResponse;
@@ -64,18 +66,6 @@ import org.slf4j.LoggerFactory;
public class ServiceSolrClient {
private static final Logger LOG = LoggerFactory.getLogger(ServiceSolrClient.class);
- enum RESOURCE_TYPE {
- COLLECTION, FIELD
- }
-
- private static final String errMessage = " You can still save the repository and start creating "
- + "policies, but you would not be able to use autocomplete for "
- + "resource names. Check server logs for more info.";
-
- private static final String COLLECTION_KEY = "collection";
- private static final String FIELD_KEY = "field";
- private static final long LOOKUP_TIMEOUT_SEC = 5;
-
private String username;
private String password;
private String serviceName;
@@ -125,10 +115,14 @@ public class ServiceSolrClient {
} catch (Exception e) {
LOG.error("Error connecting to Solr. solrClient=" + solrClient, e);
String failureMsg = "Unable to connect to Solr instance." + e.getMessage();
- BaseClient.generateResponseDataMap(false, failureMsg, failureMsg + errMessage, null, null, responseData);
+ BaseClient.generateResponseDataMap(false, failureMsg, failureMsg + RangerSolrConstants.errMessage, null, null, responseData);
}
}
+ private List<String> getSchemaList(List<String> ignoreSchemaList) throws Exception {
+ return getCollectionList(ignoreSchemaList);
+ }
+
private List<String> getCollectionList(List<String> ignoreCollectionList)
throws Exception {
if (!isSolrCloud) {
@@ -230,6 +224,31 @@ public class ServiceSolrClient {
return new ArrayList<String>(fieldSet);
}
+
+ private List<String> getConfigList(List<String> ignoreConfigList)
+ throws Exception {
+
+ ConfigSetAdminRequest request = new ConfigSetAdminRequest.List();
+
+ String decPassword = getDecryptedPassword();
+ if (!this.isKerberosAuth && username != null && decPassword != null) {
+ request.setBasicAuthCredentials(username, decPassword);
+ }
+ SolrResponse response = request.process(solrClient);
+ List<String> list = new ArrayList<String>();
+ List<String> responseConfigSetList = (ArrayList<String>)response.getResponse().get("configSets");
+ if(CollectionUtils.isEmpty(responseConfigSetList)) {
+ return list;
+ }
+ for (String responseConfigSet : responseConfigSetList) {
+ if (ignoreConfigList == null
+ || !ignoreConfigList.contains(responseConfigSet)) {
+ list.add(responseConfigSet);
+ }
+ }
+ return list;
+ }
+
public List<String> getResources(ResourceLookupContext context) {
String userInput = context.getUserInput();
@@ -238,8 +257,10 @@ public class ServiceSolrClient {
List<String> resultList = null;
List<String> collectionList = null;
List<String> fieldList = null;
+ List<String> configList = null;
+ List<String> schemaList = null;
- RESOURCE_TYPE lookupResource = RESOURCE_TYPE.COLLECTION;
+ RangerSolrConstants.RESOURCE_TYPE lookupResource = RangerSolrConstants.RESOURCE_TYPE.COLLECTION;
if (LOG.isDebugEnabled()) {
LOG.debug("<== getResources() UserInput: \""
@@ -249,16 +270,26 @@ public class ServiceSolrClient {
if (userInput != null && resource != null) {
if (resourceMap != null && !resourceMap.isEmpty()) {
- collectionList = resourceMap.get(COLLECTION_KEY);
- fieldList = resourceMap.get(FIELD_KEY);
+ collectionList = resourceMap.get(RangerSolrConstants.COLLECTION_KEY);
+ fieldList = resourceMap.get(RangerSolrConstants.FIELD_KEY);
+ configList = resourceMap.get(RangerSolrConstants.CONFIG_KEY);
+ schemaList = resourceMap.get(RangerSolrConstants.SCHEMA_KEY);
}
switch (resource.trim().toLowerCase()) {
- case COLLECTION_KEY:
- lookupResource = RESOURCE_TYPE.COLLECTION;
+ case RangerSolrConstants.COLLECTION_KEY:
+ lookupResource = RangerSolrConstants.RESOURCE_TYPE.COLLECTION;
break;
- case FIELD_KEY:
- lookupResource = RESOURCE_TYPE.FIELD;
+ case RangerSolrConstants.FIELD_KEY:
+ lookupResource = RangerSolrConstants.RESOURCE_TYPE.FIELD;
break;
+ case RangerSolrConstants.CONFIG_KEY:
+ lookupResource = RangerSolrConstants.RESOURCE_TYPE.CONFIG;
+ break;
+ case RangerSolrConstants.ADMIN_KEY:
+ lookupResource = RangerSolrConstants.RESOURCE_TYPE.ADMIN;
+ break;
+ case RangerSolrConstants.SCHEMA_KEY:
+ lookupResource = RangerSolrConstants.RESOURCE_TYPE.SCHEMA;
default:
break;
}
@@ -270,8 +301,10 @@ public class ServiceSolrClient {
final List<String> finalCollectionList = collectionList;
final List<String> finalFieldList = fieldList;
+ final List<String> finalConfigList = configList;
+ final List<String> finalSchemaList = schemaList;
- if (lookupResource == RESOURCE_TYPE.COLLECTION) {
+ if (lookupResource == RangerSolrConstants.RESOURCE_TYPE.COLLECTION) {
// get the collection list for given Input
callableObj = new Callable<List<String>>() {
@Override
@@ -287,7 +320,8 @@ public class ServiceSolrClient {
try {
ret = getCollectionList(finalCollectionList);
} catch (Exception e) {
- LOG.error("Unable to get collections, Error : " + e.getMessage(), new Throwable(e));
+ LOG.error("Unable to get collections, Error : " + e.getMessage(),
+ new Throwable(e));
}
return ret;
}
@@ -306,12 +340,12 @@ public class ServiceSolrClient {
retList.addAll(list);
}
} catch (Exception ex) {
- LOG.error("Error getting collection.", ex);
+ LOG.error("Error getting collections.", ex);
}
return retList;
};
};
- } else if (lookupResource == RESOURCE_TYPE.FIELD) {
+ } else if (lookupResource == RangerSolrConstants.RESOURCE_TYPE.FIELD) {
callableObj = new Callable<List<String>>() {
@Override
public List<String> call() {
@@ -326,7 +360,8 @@ public class ServiceSolrClient {
try {
ret = getFieldList(finalCollectionList, finalFieldList);
} catch (Exception e) {
- LOG.error("Unable to get field list, Error : " + e.getMessage(), new Throwable(e));
+ LOG.error("Unable to get field list, Error : " + e.getMessage(),
+ new Throwable(e));
}
return ret;
}
@@ -345,7 +380,112 @@ public class ServiceSolrClient {
retList.addAll(list);
}
} catch (Exception ex) {
- LOG.error("Error getting collection.", ex);
+ LOG.error("Error getting collections.", ex);
+ }
+ return retList;
+ };
+ };
+ } else if (lookupResource == RangerSolrConstants.RESOURCE_TYPE.CONFIG) {
+ // get the config list for given Input
+ callableObj = new Callable<List<String>>() {
+ @Override
+ public List<String> call() {
+ List<String> retList = new ArrayList<String>();
+ try {
+ List<String> list = null;
+ if (isKerberosAuth) {
+ list = Subject.doAs(loginSubject, new PrivilegedAction<List<String>>() {
+ @Override
+ public List<String> run() {
+ List<String> ret = null;
+ try {
+ ret = getConfigList(finalConfigList);
+ } catch (Exception e) {
+ LOG.error("Unable to get Solr configs, Error : " + e.getMessage(),
+ new Throwable(e));
+ }
+ return ret;
+ }
+ });
+ } else {
+ list = getConfigList(finalConfigList);
+ }
+ if (userInputFinal != null
+ && !userInputFinal.isEmpty()) {
+ for (String value : list) {
+ if (value.startsWith(userInputFinal)) {
+ retList.add(value);
+ }
+ }
+ } else {
+ retList.addAll(list);
+ }
+ } catch (Exception ex) {
+ LOG.error("Error getting Solr configs.", ex);
+ }
+ return retList;
+ }
+
+ ;
+ } ;
+ } else if (lookupResource == RangerSolrConstants.RESOURCE_TYPE.ADMIN) {
+ List<String> retList = new ArrayList<String>();
+ try {
+ List<String> list = RangerSolrConstants.ADMIN_TYPE.VALUE_LIST;
+
+ if (userInputFinal != null
+ && !userInputFinal.isEmpty()) {
+ for (String value : list) {
+ if (value.startsWith(userInputFinal)) {
+ retList.add(value);
+ }
+ }
+ } else {
+ retList.addAll(list);
+ }
+ } catch (Exception ex) {
+ LOG.error("Error getting Solr admin resources.", ex);
+ }
+ resultList = retList;
+
+ } else if (lookupResource == RangerSolrConstants.RESOURCE_TYPE.SCHEMA) {
+ // get the collection list for given Input, since there is no way of getting a list of the available
+ // schemas
+ callableObj = new Callable<List<String>>() {
+ @Override
+ public List<String> call() {
+ List<String> retList = new ArrayList<String>();
+ try {
+ List<String> list = null;
+ if (isKerberosAuth) {
+ list = Subject.doAs(loginSubject, new PrivilegedAction<List<String>>() {
+ @Override
+ public List<String> run() {
+ List<String> ret = null;
+ try {
+ ret = getSchemaList(finalSchemaList);
+ } catch (Exception e) {
+ LOG.error("Unable to get collections for schema listing, Error : "
+ + e.getMessage(), new Throwable(e));
+ }
+ return ret;
+ }
+ });
+ } else {
+ list = getSchemaList(finalSchemaList);
+ }
+ if (userInputFinal != null
+ && !userInputFinal.isEmpty()) {
+ for (String value : list) {
+ if (value.startsWith(userInputFinal)) {
+ retList.add(value);
+ }
+ }
+ } else {
+ retList.addAll(list);
+ }
+ } catch (Exception ex) {
+ LOG.error("Error getting collections for schema listing.", ex);
}
return retList;
};
@@ -355,13 +495,14 @@ public class ServiceSolrClient {
if (callableObj != null) {
synchronized (this) {
resultList = TimedEventUtil.timedTask(callableObj,
- LOOKUP_TIMEOUT_SEC, TimeUnit.SECONDS);
+ RangerSolrConstants.LOOKUP_TIMEOUT_SEC, TimeUnit.SECONDS);
}
}
} catch (Exception e) {
- LOG.error("Unable to get solr resources.", e);
+ LOG.error("Unable to get Solr resources.", e);
}
- }
+
+ } // end if userinput != null
return resultList;
}
@@ -471,8 +612,8 @@ public class ServiceSolrClient {
private HadoopException createException(String msgDesc, Exception exp) {
HadoopException hdpException = new HadoopException(msgDesc, exp);
final String fullDescription = exp != null ? BaseClient.getMessage(exp) : msgDesc;
- hdpException.generateResponseDataMap(false, fullDescription + errMessage,
- msgDesc + errMessage, null, null);
+ hdpException.generateResponseDataMap(false, fullDescription + RangerSolrConstants.errMessage,
+ msgDesc + RangerSolrConstants.errMessage, null, null);
return hdpException;
}