in src/main/java/org/opensearch/security/privileges/PrivilegesEvaluator.java [201:485]
public PrivilegesEvaluatorResponse evaluate(final User user, String action0, final ActionRequest request,
Task task, final Set<String> injectedRoles) {
if (!isInitialized()) {
throw new OpenSearchSecurityException("OpenSearch Security is not initialized.");
}
if(action0.startsWith("internal:indices/admin/upgrade")) {
action0 = "indices:admin/upgrade";
}
if (AutoCreateAction.NAME.equals(action0)) {
action0 = CreateIndexAction.NAME;
}
if (AutoPutMappingAction.NAME.equals(action0)) {
action0 = PutMappingAction.NAME;
}
final PrivilegesEvaluatorResponse presponse = new PrivilegesEvaluatorResponse();
final TransportAddress caller = threadContext.getTransient(ConfigConstants.OPENDISTRO_SECURITY_REMOTE_ADDRESS);
Set<String> mappedRoles = (injectedRoles == null) ? mapRoles(user, caller) : injectedRoles;
final String injectedRolesValidationString = threadContext.getTransient(ConfigConstants.OPENDISTRO_SECURITY_INJECTED_ROLES_VALIDATION);
if(injectedRolesValidationString != null) {
HashSet<String> injectedRolesValidationSet = new HashSet<>(Arrays.asList(injectedRolesValidationString.split(",")));
if(!mappedRoles.containsAll(injectedRolesValidationSet)) {
presponse.allowed = false;
presponse.missingSecurityRoles.addAll(injectedRolesValidationSet);
log.info("Roles {} are not mapped to the user {}", injectedRolesValidationSet, user);
return presponse;
}
mappedRoles = ImmutableSet.copyOf(injectedRolesValidationSet);
}
presponse.resolvedSecurityRoles.addAll(mappedRoles);
final SecurityRoles securityRoles = getSecurityRoles(mappedRoles);
setUserInfoInThreadContext(user, mappedRoles);
final boolean isDebugEnabled = log.isDebugEnabled();
if (isDebugEnabled) {
log.debug("Evaluate permissions for {} on {}", user, clusterService.localNode().getName());
log.debug("Action: {} ({})", action0, request.getClass().getSimpleName());
log.debug("Mapped roles: {}", mappedRoles.toString());
}
if (request instanceof BulkRequest && (Strings.isNullOrEmpty(user.getRequestedTenant()))) {
// Shortcut for bulk actions. The details are checked on the lower level of the BulkShardRequests (Action indices:data/write/bulk[s]).
// This shortcut is only possible if the default tenant is selected, as we might need to rewrite the request for non-default tenants.
// No further access check for the default tenant is necessary, as access will be also checked on the TransportShardBulkAction level.
if (!securityRoles.impliesClusterPermissionPermission(action0)) {
presponse.missingPrivileges.add(action0);
presponse.allowed = false;
log.info("No cluster-level perm match for {} [Action [{}]] [RolesChecked {}]. No permissions for {}", user, action0,
securityRoles.getRoleNames(), presponse.missingPrivileges);
} else {
presponse.allowed = true;
}
return presponse;
}
final Resolved requestedResolved = irr.resolveRequest(request);
if (isDebugEnabled) {
log.debug("RequestedResolved : {}", requestedResolved);
}
// check dlsfls
if (dlsFlsEnabled
//&& (action0.startsWith("indices:data/read") || action0.equals(ClusterSearchShardsAction.NAME))
&& dlsFlsEvaluator.evaluate(request, clusterService, resolver, requestedResolved, user, securityRoles, presponse).isComplete()) {
return presponse;
}
// check snapshot/restore requests
if (snapshotRestoreEvaluator.evaluate(request, task, action0, clusterInfoHolder, presponse).isComplete()) {
return presponse;
}
// Security index access
if (securityIndexAccessEvaluator.evaluate(request, task, action0, requestedResolved, presponse).isComplete()) {
return presponse;
}
// Protected index access
if (protectedIndexAccessEvaluator.evaluate(request, task, action0, requestedResolved, presponse, securityRoles).isComplete()) {
return presponse;
}
final boolean dnfofEnabled = dcm.isDnfofEnabled();
final boolean isTraceEnabled = log.isTraceEnabled();
if (isTraceEnabled) {
log.trace("dnfof enabled? {}", dnfofEnabled);
}
if (isClusterPerm(action0)) {
if(!securityRoles.impliesClusterPermissionPermission(action0)) {
presponse.missingPrivileges.add(action0);
presponse.allowed = false;
log.info("No cluster-level perm match for {} {} [Action [{}]] [RolesChecked {}]. No permissions for {}", user, requestedResolved, action0,
securityRoles.getRoleNames(), presponse.missingPrivileges);
return presponse;
} else {
if(request instanceof RestoreSnapshotRequest && checkSnapshotRestoreWritePrivileges) {
if (isDebugEnabled) {
log.debug("Normally allowed but we need to apply some extra checks for a restore request.");
}
} else {
if(privilegesInterceptor.getClass() != PrivilegesInterceptor.class) {
final PrivilegesInterceptor.ReplaceResult replaceResult = privilegesInterceptor.replaceDashboardsIndex(request, action0, user, dcm, requestedResolved,
mapTenants(user, mappedRoles));
if (isDebugEnabled) {
log.debug("Result from privileges interceptor for cluster perm: {}", replaceResult);
}
if (!replaceResult.continueEvaluation) {
if (replaceResult.accessDenied) {
auditLog.logMissingPrivileges(action0, request, task);
} else {
presponse.allowed = true;
presponse.createIndexRequestBuilder = replaceResult.createIndexRequestBuilder;
}
return presponse;
}
}
if (dnfofEnabled
&& (action0.startsWith("indices:data/read/"))
&& !requestedResolved.getAllIndices().isEmpty()
) {
if(requestedResolved.getAllIndices().isEmpty()) {
presponse.missingPrivileges.clear();
presponse.allowed = true;
return presponse;
}
Set<String> reduced = securityRoles.reduce(requestedResolved, user, new String[]{action0}, resolver, clusterService);
if(reduced.isEmpty()) {
presponse.allowed = false;
return presponse;
}
if(irr.replace(request, true, reduced.toArray(new String[0]))) {
presponse.missingPrivileges.clear();
presponse.allowed = true;
return presponse;
}
}
if (isDebugEnabled) {
log.debug("Allowed because we have cluster permissions for {}", action0);
}
presponse.allowed = true;
return presponse;
}
}
}
// term aggregations
if (termsAggregationEvaluator.evaluate(requestedResolved, request, clusterService, user, securityRoles, resolver, presponse) .isComplete()) {
return presponse;
}
final Set<String> allIndexPermsRequired = evaluateAdditionalIndexPermissions(request, action0);
final String[] allIndexPermsRequiredA = allIndexPermsRequired.toArray(new String[0]);
if (isDebugEnabled) {
log.debug("Requested {} from {}", allIndexPermsRequired, caller);
}
presponse.missingPrivileges.clear();
presponse.missingPrivileges.addAll(allIndexPermsRequired);
if (isDebugEnabled) {
log.debug("Requested resolved index types: {}", requestedResolved);
log.debug("Security roles: {}", securityRoles.getRoleNames());
}
//TODO exclude Security index
if(privilegesInterceptor.getClass() != PrivilegesInterceptor.class) {
final PrivilegesInterceptor.ReplaceResult replaceResult = privilegesInterceptor.replaceDashboardsIndex(request, action0, user, dcm, requestedResolved, mapTenants(user, mappedRoles));
if (isDebugEnabled) {
log.debug("Result from privileges interceptor: {}", replaceResult);
}
if (!replaceResult.continueEvaluation) {
if (replaceResult.accessDenied) {
auditLog.logMissingPrivileges(action0, request, task);
} else {
presponse.allowed = true;
presponse.createIndexRequestBuilder = replaceResult.createIndexRequestBuilder;
}
return presponse;
}
}
if (dnfofEnabled && DNFOF_PATTERNS.matcher(action0).matches()) {
if(requestedResolved.getAllIndices().isEmpty()) {
presponse.missingPrivileges.clear();
presponse.allowed = true;
return presponse;
}
Set<String> reduced = securityRoles.reduce(requestedResolved, user, allIndexPermsRequiredA, resolver, clusterService);
if(reduced.isEmpty()) {
if(dcm.isDnfofForEmptyResultsEnabled() && request instanceof IndicesRequest.Replaceable) {
((IndicesRequest.Replaceable) request).indices(new String[0]);
presponse.missingPrivileges.clear();
presponse.allowed = true;
if(request instanceof SearchRequest) {
((SearchRequest) request).indicesOptions(ALLOW_EMPTY);
} else if(request instanceof ClusterSearchShardsRequest) {
((ClusterSearchShardsRequest) request).indicesOptions(ALLOW_EMPTY);
} else if(request instanceof GetFieldMappingsRequest) {
((GetFieldMappingsRequest) request).indicesOptions(ALLOW_EMPTY);
}
return presponse;
}
presponse.allowed = false;
return presponse;
}
if(irr.replace(request, true, reduced.toArray(new String[0]))) {
presponse.missingPrivileges.clear();
presponse.allowed = true;
return presponse;
}
}
//not bulk, mget, etc request here
boolean permGiven = false;
if (isDebugEnabled) {
log.debug("Security roles: {}", securityRoles.getRoleNames());
}
if (dcm.isMultiRolespanEnabled()) {
permGiven = securityRoles.impliesTypePermGlobal(requestedResolved, user, allIndexPermsRequiredA, resolver, clusterService);
} else {
permGiven = securityRoles.get(requestedResolved, user, allIndexPermsRequiredA, resolver, clusterService);
}
if (!permGiven) {
log.info("No {}-level perm match for {} {} [Action [{}]] [RolesChecked {}]", "index" , user, requestedResolved, action0,
securityRoles.getRoleNames());
log.info("No permissions for {}", presponse.missingPrivileges);
} else {
if(checkFilteredAliases(requestedResolved, action0, isDebugEnabled)) {
presponse.allowed=false;
return presponse;
}
if (isDebugEnabled) {
log.debug("Allowed because we have all indices permissions for {}", action0);
}
}
presponse.allowed = permGiven;
return presponse;
}