Augment audit authz event with role names data (elastic/x-pack-elasticsearch#3100)

Audit authz events (accessGranted, accessDenied, runAsGranted
and runAsDenied) include role names.

Original commit: elastic/x-pack-elasticsearch@6a94f65962
This commit is contained in:
Albert Zaharovits 2017-11-30 15:56:00 +02:00 committed by GitHub
parent 4262b29188
commit 3ea5a6df91
22 changed files with 409 additions and 333 deletions

View File

@ -6,19 +6,20 @@
package org.elasticsearch.xpack.security.action.user;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import org.apache.logging.log4j.message.ParameterizedMessage;
import org.apache.lucene.util.automaton.Automaton;
import org.apache.lucene.util.automaton.Operations;
import org.elasticsearch.action.ActionListener;
import org.elasticsearch.action.support.ActionFilters;
import org.elasticsearch.action.support.HandledTransportAction;
import org.elasticsearch.cluster.metadata.IndexNameExpressionResolver;
import org.elasticsearch.common.Strings;
import org.elasticsearch.common.inject.Inject;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.threadpool.ThreadPool;
@ -68,10 +69,9 @@ public class TransportHasPrivilegesAction extends HandledTransportAction<HasPriv
private void checkPrivileges(HasPrivilegesRequest request, Role userRole,
ActionListener<HasPrivilegesResponse> listener) {
if (logger.isDebugEnabled()) {
logger.debug("Check whether role [{}] has privileges cluster=[{}] index=[{}]", userRole.name(),
Arrays.toString(request.clusterPrivileges()), Arrays.toString(request.indexPrivileges()));
}
logger.debug(() -> new ParameterizedMessage("Check whether role [{}] has privileges cluster=[{}] index=[{}]",
Strings.arrayToCommaDelimitedString(userRole.names()), Strings.arrayToCommaDelimitedString(request.clusterPrivileges()),
Strings.arrayToCommaDelimitedString(request.indexPrivileges())));
Map<String, Boolean> cluster = new HashMap<>();
for (String checkAction : request.clusterPrivileges()) {
@ -93,10 +93,12 @@ public class TransportHasPrivilegesAction extends HandledTransportAction<HasPriv
}
for (String privilege : check.getPrivileges()) {
if (testIndexMatch(index, privilege, userRole, predicateCache)) {
logger.debug("Role [{}] has [{}] on [{}]", userRole.name(), privilege, index);
logger.debug(() -> new ParameterizedMessage("Role [{}] has [{}] on [{}]",
Strings.arrayToCommaDelimitedString(userRole.names()), privilege, index));
privileges.put(privilege, true);
} else {
logger.debug("Role [{}] does not have [{}] on [{}]", userRole.name(), privilege, index);
logger.debug(() -> new ParameterizedMessage("Role [{}] does not have [{}] on [{}]",
Strings.arrayToCommaDelimitedString(userRole.names()), privilege, index));
privileges.put(privilege, false);
allMatch = false;
}

View File

@ -37,9 +37,9 @@ public interface AuditTrail {
void authenticationFailed(String realm, AuthenticationToken token, RestRequest request);
void accessGranted(User user, String action, TransportMessage message);
void accessGranted(User user, String action, TransportMessage message, String[] roleNames);
void accessDenied(User user, String action, TransportMessage message);
void accessDenied(User user, String action, TransportMessage message, String[] roleNames);
void tamperedRequest(RestRequest request);
@ -51,9 +51,9 @@ public interface AuditTrail {
void connectionDenied(InetAddress inetAddress, String profile, SecurityIpFilterRule rule);
void runAsGranted(User user, String action, TransportMessage message);
void runAsGranted(User user, String action, TransportMessage message, String[] roleNames);
void runAsDenied(User user, String action, TransportMessage message);
void runAsDenied(User user, String action, TransportMessage message, String[] roleNames);
void runAsDenied(User user, RestRequest request);
void runAsDenied(User user, RestRequest request, String[] roleNames);
}

View File

@ -130,19 +130,19 @@ public class AuditTrailService extends AbstractComponent implements AuditTrail {
}
@Override
public void accessGranted(User user, String action, TransportMessage message) {
public void accessGranted(User user, String action, TransportMessage message, String[] roleNames) {
if (licenseState.isAuditingAllowed()) {
for (AuditTrail auditTrail : auditTrails) {
auditTrail.accessGranted(user, action, message);
auditTrail.accessGranted(user, action, message, roleNames);
}
}
}
@Override
public void accessDenied(User user, String action, TransportMessage message) {
public void accessDenied(User user, String action, TransportMessage message, String[] roleNames) {
if (licenseState.isAuditingAllowed()) {
for (AuditTrail auditTrail : auditTrails) {
auditTrail.accessDenied(user, action, message);
auditTrail.accessDenied(user, action, message, roleNames);
}
}
}
@ -191,28 +191,28 @@ public class AuditTrailService extends AbstractComponent implements AuditTrail {
}
@Override
public void runAsGranted(User user, String action, TransportMessage message) {
public void runAsGranted(User user, String action, TransportMessage message, String[] roleNames) {
if (licenseState.isAuditingAllowed()) {
for (AuditTrail auditTrail : auditTrails) {
auditTrail.runAsGranted(user, action, message);
auditTrail.runAsGranted(user, action, message, roleNames);
}
}
}
@Override
public void runAsDenied(User user, String action, TransportMessage message) {
public void runAsDenied(User user, String action, TransportMessage message, String[] roleNames) {
if (licenseState.isAuditingAllowed()) {
for (AuditTrail auditTrail : auditTrails) {
auditTrail.runAsDenied(user, action, message);
auditTrail.runAsDenied(user, action, message, roleNames);
}
}
}
@Override
public void runAsDenied(User user, RestRequest request) {
public void runAsDenied(User user, RestRequest request, String[] roleNames) {
if (licenseState.isAuditingAllowed()) {
for (AuditTrail auditTrail : auditTrails) {
auditTrail.runAsDenied(user, request);
auditTrail.runAsDenied(user, request, roleNames);
}
}
}

View File

@ -48,7 +48,6 @@ import org.elasticsearch.xpack.XPackPlugin;
import org.elasticsearch.xpack.security.audit.AuditLevel;
import org.elasticsearch.xpack.security.audit.AuditTrail;
import org.elasticsearch.xpack.security.authc.AuthenticationToken;
import org.elasticsearch.xpack.security.authz.privilege.SystemPrivilege;
import org.elasticsearch.xpack.security.rest.RemoteHostHeader;
import org.elasticsearch.xpack.security.support.IndexLifecycleManager;
import org.elasticsearch.xpack.security.transport.filter.SecurityIpFilterRule;
@ -356,7 +355,7 @@ public class IndexAuditTrail extends AbstractComponent implements AuditTrail {
public void authenticationSuccess(String realm, User user, RestRequest request) {
if (events.contains(AUTHENTICATION_SUCCESS)) {
try {
enqueue(message("authentication_success", realm, user, request), "authentication_success");
enqueue(message("authentication_success", realm, user, null, request), "authentication_success");
} catch (Exception e) {
logger.warn("failed to index audit event: [authentication_success]", e);
}
@ -367,7 +366,7 @@ public class IndexAuditTrail extends AbstractComponent implements AuditTrail {
public void authenticationSuccess(String realm, User user, String action, TransportMessage message) {
if (events.contains(AUTHENTICATION_SUCCESS)) {
try {
enqueue(message("authentication_success", action, user, realm, null, message), "authentication_success");
enqueue(message("authentication_success", action, user, null, realm, null, message), "authentication_success");
} catch (Exception e) {
logger.warn("failed to index audit event: [authentication_success]", e);
}
@ -378,7 +377,7 @@ public class IndexAuditTrail extends AbstractComponent implements AuditTrail {
public void anonymousAccessDenied(String action, TransportMessage message) {
if (events.contains(ANONYMOUS_ACCESS_DENIED)) {
try {
enqueue(message("anonymous_access_denied", action, (User) null, null, indices(message), message),
enqueue(message("anonymous_access_denied", action, (User) null, null, null, indices(message), message),
"anonymous_access_denied");
} catch (Exception e) {
logger.warn("failed to index audit event: [anonymous_access_denied]", e);
@ -401,7 +400,8 @@ public class IndexAuditTrail extends AbstractComponent implements AuditTrail {
public void authenticationFailed(String action, TransportMessage message) {
if (events.contains(AUTHENTICATION_FAILED)) {
try {
enqueue(message("authentication_failed", action, (User) null, null, indices(message), message), "authentication_failed");
enqueue(message("authentication_failed", action, (User) null, null, null, indices(message), message),
"authentication_failed");
} catch (Exception e) {
logger.warn("failed to index audit event: [authentication_failed]", e);
}
@ -473,19 +473,13 @@ public class IndexAuditTrail extends AbstractComponent implements AuditTrail {
}
@Override
public void accessGranted(User user, String action, TransportMessage message) {
// special treatment for internal system actions - only log if explicitly told to
if ((SystemUser.is(user) && SystemPrivilege.INSTANCE.predicate().test(action))) {
if (events.contains(SYSTEM_ACCESS_GRANTED)) {
try {
enqueue(message("access_granted", action, user, null, indices(message), message), "access_granted");
} catch (Exception e) {
logger.warn("failed to index audit event: [access_granted]", e);
}
}
} else if (events.contains(ACCESS_GRANTED) && XPackUser.is(user) == false) {
public void accessGranted(User user, String action, TransportMessage message, String[] roleNames) {
final boolean isSystem = SystemUser.is(user) || XPackUser.is(user);
final boolean logSystemAccessGranted = isSystem && events.contains(SYSTEM_ACCESS_GRANTED);
final boolean shouldLog = logSystemAccessGranted || (isSystem == false && events.contains(ACCESS_GRANTED));
if (shouldLog) {
try {
enqueue(message("access_granted", action, user, null, indices(message), message), "access_granted");
enqueue(message("access_granted", action, user, roleNames, null, indices(message), message), "access_granted");
} catch (Exception e) {
logger.warn("failed to index audit event: [access_granted]", e);
}
@ -493,10 +487,10 @@ public class IndexAuditTrail extends AbstractComponent implements AuditTrail {
}
@Override
public void accessDenied(User user, String action, TransportMessage message) {
public void accessDenied(User user, String action, TransportMessage message, String[] roleNames) {
if (events.contains(ACCESS_DENIED) && XPackUser.is(user) == false) {
try {
enqueue(message("access_denied", action, user, null, indices(message), message), "access_denied");
enqueue(message("access_denied", action, user, roleNames, null, indices(message), message), "access_denied");
} catch (Exception e) {
logger.warn("failed to index audit event: [access_denied]", e);
}
@ -518,7 +512,7 @@ public class IndexAuditTrail extends AbstractComponent implements AuditTrail {
public void tamperedRequest(String action, TransportMessage message) {
if (events.contains(TAMPERED_REQUEST)) {
try {
enqueue(message("tampered_request", action, (User) null, null, indices(message), message), "tampered_request");
enqueue(message("tampered_request", action, (User) null, null, null, indices(message), message), "tampered_request");
} catch (Exception e) {
logger.warn("failed to index audit event: [tampered_request]", e);
}
@ -529,7 +523,7 @@ public class IndexAuditTrail extends AbstractComponent implements AuditTrail {
public void tamperedRequest(User user, String action, TransportMessage request) {
if (events.contains(TAMPERED_REQUEST) && XPackUser.is(user) == false) {
try {
enqueue(message("tampered_request", action, user, null, indices(request), request), "tampered_request");
enqueue(message("tampered_request", action, user, null, null, indices(request), request), "tampered_request");
} catch (Exception e) {
logger.warn("failed to index audit event: [tampered_request]", e);
}
@ -559,10 +553,10 @@ public class IndexAuditTrail extends AbstractComponent implements AuditTrail {
}
@Override
public void runAsGranted(User user, String action, TransportMessage message) {
public void runAsGranted(User user, String action, TransportMessage message, String[] roleNames) {
if (events.contains(RUN_AS_GRANTED)) {
try {
enqueue(message("run_as_granted", action, user, null, null, message), "run_as_granted");
enqueue(message("run_as_granted", action, user, roleNames, null, null, message), "run_as_granted");
} catch (Exception e) {
logger.warn("failed to index audit event: [run_as_granted]", e);
}
@ -570,10 +564,10 @@ public class IndexAuditTrail extends AbstractComponent implements AuditTrail {
}
@Override
public void runAsDenied(User user, String action, TransportMessage message) {
public void runAsDenied(User user, String action, TransportMessage message, String[] roleNames) {
if (events.contains(RUN_AS_DENIED)) {
try {
enqueue(message("run_as_denied", action, user, null, null, message), "run_as_denied");
enqueue(message("run_as_denied", action, user, roleNames, null, null, message), "run_as_denied");
} catch (Exception e) {
logger.warn("failed to index audit event: [run_as_denied]", e);
}
@ -581,17 +575,17 @@ public class IndexAuditTrail extends AbstractComponent implements AuditTrail {
}
@Override
public void runAsDenied(User user, RestRequest request) {
public void runAsDenied(User user, RestRequest request, String[] roleNames) {
if (events.contains(RUN_AS_DENIED)) {
try {
enqueue(message("run_as_denied", null, user, request), "run_as_denied");
enqueue(message("run_as_denied", null, user, roleNames, request), "run_as_denied");
} catch (Exception e) {
logger.warn("failed to index audit event: [run_as_denied]", e);
}
}
}
private Message message(String type, @Nullable String action, @Nullable User user, @Nullable String realm,
private Message message(String type, @Nullable String action, @Nullable User user, @Nullable String[] roleNames, @Nullable String realm,
@Nullable Set<String> indices, TransportMessage message) throws Exception {
Message msg = new Message().start();
@ -614,6 +608,9 @@ public class IndexAuditTrail extends AbstractComponent implements AuditTrail {
} else {
msg.builder.field(Field.PRINCIPAL, user.principal());
}
if (roleNames != null) {
msg.builder.array(Field.ROLE_NAMES, roleNames);
}
}
if (indices != null) {
msg.builder.array(Field.INDICES, indices.toArray(Strings.EMPTY_ARRAY));
@ -686,7 +683,8 @@ public class IndexAuditTrail extends AbstractComponent implements AuditTrail {
return msg.end();
}
private Message message(String type, String realm, User user, RestRequest request) throws Exception {
private Message message(String type, @Nullable String realm, @Nullable User user, @Nullable String[] roleNames, RestRequest request)
throws Exception {
Message msg = new Message().start();
common("rest", type, msg.builder);
@ -698,6 +696,9 @@ public class IndexAuditTrail extends AbstractComponent implements AuditTrail {
} else {
msg.builder.field(Field.PRINCIPAL, user.principal());
}
if (roleNames != null) {
msg.builder.array(Field.ROLE_NAMES, roleNames);
}
}
if (realm != null) {
msg.builder.field(Field.REALM, realm);
@ -1051,6 +1052,7 @@ public class IndexAuditTrail extends AbstractComponent implements AuditTrail {
String ORIGIN_ADDRESS = "origin_address";
String ORIGIN_TYPE = "origin_type";
String PRINCIPAL = "principal";
String ROLE_NAMES = "roles";
String RUN_AS_PRINCIPAL = "run_as_principal";
String RUN_BY_PRINCIPAL = "run_by_principal";
String ACTION = "action";

View File

@ -25,7 +25,6 @@ import org.elasticsearch.transport.TransportMessage;
import org.elasticsearch.xpack.security.audit.AuditLevel;
import org.elasticsearch.xpack.security.audit.AuditTrail;
import org.elasticsearch.xpack.security.authc.AuthenticationToken;
import org.elasticsearch.xpack.security.authz.privilege.SystemPrivilege;
import org.elasticsearch.xpack.security.rest.RemoteHostHeader;
import org.elasticsearch.xpack.security.transport.filter.SecurityIpFilterRule;
import org.elasticsearch.xpack.security.user.SystemUser;
@ -44,6 +43,7 @@ import java.util.Set;
import java.util.function.Function;
import static org.elasticsearch.common.Strings.collectionToCommaDelimitedString;
import static org.elasticsearch.common.Strings.arrayToCommaDelimitedString;
import static org.elasticsearch.xpack.security.Security.setting;
import static org.elasticsearch.xpack.security.audit.AuditLevel.ACCESS_DENIED;
import static org.elasticsearch.xpack.security.audit.AuditLevel.ACCESS_GRANTED;
@ -255,38 +255,38 @@ public class LoggingAuditTrail extends AbstractComponent implements AuditTrail,
}
@Override
public void accessGranted(User user, String action, TransportMessage message) {
final boolean isSystem = (SystemUser.is(user) && SystemPrivilege.INSTANCE.predicate().test(action)) || XPackUser.is(user);
public void accessGranted(User user, String action, TransportMessage message, String[] roleNames) {
final boolean isSystem = SystemUser.is(user) || XPackUser.is(user);
final boolean logSystemAccessGranted = isSystem && events.contains(SYSTEM_ACCESS_GRANTED);
final boolean shouldLog = logSystemAccessGranted || (isSystem == false && events.contains(ACCESS_GRANTED));
if (shouldLog) {
String indices = indicesString(message);
final LocalNodeInfo localNodeInfo = this.localNodeInfo;
if (indices != null) {
logger.info("{}[transport] [access_granted]\t{}, {}, action=[{}], indices=[{}], request=[{}]", localNodeInfo.prefix,
originAttributes(threadContext, message, localNodeInfo), principal(user), action, indices,
message.getClass().getSimpleName());
logger.info("{}[transport] [access_granted]\t{}, {}, roles=[{}], action=[{}], indices=[{}], request=[{}]",
localNodeInfo.prefix, originAttributes(threadContext, message, localNodeInfo), principal(user),
arrayToCommaDelimitedString(roleNames), action, indices, message.getClass().getSimpleName());
} else {
logger.info("{}[transport] [access_granted]\t{}, {}, action=[{}], request=[{}]", localNodeInfo.prefix,
originAttributes(threadContext, message, localNodeInfo), principal(user), action,
message.getClass().getSimpleName());
logger.info("{}[transport] [access_granted]\t{}, {}, roles=[{}], action=[{}], request=[{}]", localNodeInfo.prefix,
originAttributes(threadContext, message, localNodeInfo), principal(user), arrayToCommaDelimitedString(roleNames),
action, message.getClass().getSimpleName());
}
}
}
@Override
public void accessDenied(User user, String action, TransportMessage message) {
public void accessDenied(User user, String action, TransportMessage message, String[] roleNames) {
if (events.contains(ACCESS_DENIED)) {
String indices = indicesString(message);
final LocalNodeInfo localNodeInfo = this.localNodeInfo;
if (indices != null) {
logger.info("{}[transport] [access_denied]\t{}, {}, action=[{}], indices=[{}], request=[{}]", localNodeInfo.prefix,
originAttributes(threadContext, message, localNodeInfo), principal(user), action, indices,
message.getClass().getSimpleName());
logger.info("{}[transport] [access_denied]\t{}, {}, roles=[{}], action=[{}], indices=[{}], request=[{}]",
localNodeInfo.prefix, originAttributes(threadContext, message, localNodeInfo), principal(user),
arrayToCommaDelimitedString(roleNames), action, indices, message.getClass().getSimpleName());
} else {
logger.info("{}[transport] [access_denied]\t{}, {}, action=[{}], request=[{}]", localNodeInfo.prefix,
originAttributes(threadContext, message, localNodeInfo), principal(user), action,
message.getClass().getSimpleName());
logger.info("{}[transport] [access_denied]\t{}, {}, roles=[{}], action=[{}], request=[{}]", localNodeInfo.prefix,
originAttributes(threadContext, message, localNodeInfo), principal(user), arrayToCommaDelimitedString(roleNames),
action, message.getClass().getSimpleName());
}
}
}
@ -352,34 +352,35 @@ public class LoggingAuditTrail extends AbstractComponent implements AuditTrail,
}
@Override
public void runAsGranted(User user, String action, TransportMessage message) {
public void runAsGranted(User user, String action, TransportMessage message, String[] roleNames) {
if (events.contains(RUN_AS_GRANTED)) {
final LocalNodeInfo localNodeInfo = this.localNodeInfo;
logger.info("{}[transport] [run_as_granted]\t{}, principal=[{}], run_as_principal=[{}], action=[{}], request=[{}]",
logger.info("{}[transport] [run_as_granted]\t{}, principal=[{}], run_as_principal=[{}], roles=[{}], action=[{}], request=[{}]",
localNodeInfo.prefix, originAttributes(threadContext, message, localNodeInfo), user.authenticatedUser().principal(),
user.principal(), action, message.getClass().getSimpleName());
user.principal(), arrayToCommaDelimitedString(roleNames), action, message.getClass().getSimpleName());
}
}
@Override
public void runAsDenied(User user, String action, TransportMessage message) {
public void runAsDenied(User user, String action, TransportMessage message, String[] roleNames) {
if (events.contains(RUN_AS_DENIED)) {
final LocalNodeInfo localNodeInfo = this.localNodeInfo;
logger.info("{}[transport] [run_as_denied]\t{}, principal=[{}], run_as_principal=[{}], action=[{}], request=[{}]",
logger.info("{}[transport] [run_as_denied]\t{}, principal=[{}], run_as_principal=[{}], roles=[{}], action=[{}], request=[{}]",
localNodeInfo.prefix, originAttributes(threadContext, message, localNodeInfo), user.authenticatedUser().principal(),
user.principal(), action, message.getClass().getSimpleName());
user.principal(), arrayToCommaDelimitedString(roleNames), action, message.getClass().getSimpleName());
}
}
@Override
public void runAsDenied(User user, RestRequest request) {
public void runAsDenied(User user, RestRequest request, String[] roleNames) {
if (events.contains(RUN_AS_DENIED)) {
if (includeRequestBody) {
logger.info("{}[rest] [run_as_denied]\t{}, principal=[{}], uri=[{}], request_body=[{}]", localNodeInfo.prefix,
hostAttributes(request), user.principal(), request.uri(), restRequestContent(request));
logger.info("{}[rest] [run_as_denied]\t{}, principal=[{}], roles=[{}], uri=[{}], request_body=[{}]", localNodeInfo.prefix,
hostAttributes(request), user.principal(), arrayToCommaDelimitedString(roleNames), request.uri(),
restRequestContent(request));
} else {
logger.info("{}[rest] [run_as_denied]\t{}, principal=[{}], uri=[{}]", localNodeInfo.prefix, hostAttributes(request),
user.principal(), request.uri());
logger.info("{}[rest] [run_as_denied]\t{}, principal=[{}], roles=[{}], uri=[{}]", localNodeInfo.prefix,
hostAttributes(request), user.principal(), arrayToCommaDelimitedString(roleNames), request.uri());
}
}
}

View File

@ -34,6 +34,7 @@ import org.elasticsearch.xpack.security.audit.AuditTrail;
import org.elasticsearch.xpack.security.audit.AuditTrailService;
import org.elasticsearch.xpack.security.authc.Authentication.RealmRef;
import org.elasticsearch.xpack.security.authc.support.UsernamePasswordToken;
import org.elasticsearch.xpack.security.authz.permission.Role;
import org.elasticsearch.xpack.security.support.Exceptions;
import org.elasticsearch.xpack.security.user.AnonymousUser;
import org.elasticsearch.xpack.security.user.User;
@ -531,7 +532,7 @@ public class AuthenticationService extends AbstractComponent {
@Override
ElasticsearchSecurityException runAsDenied(User user, AuthenticationToken token) {
auditTrail.runAsDenied(user, action, message);
auditTrail.runAsDenied(user, action, message, Role.EMPTY.names());
return failureHandler.failedAuthentication(message, token, action, threadContext);
}
@ -593,7 +594,7 @@ public class AuthenticationService extends AbstractComponent {
@Override
ElasticsearchSecurityException runAsDenied(User user, AuthenticationToken token) {
auditTrail.runAsDenied(user, request);
auditTrail.runAsDenied(user, request, Role.EMPTY.names());
return failureHandler.failedAuthentication(request, token, threadContext);
}

View File

@ -83,6 +83,7 @@ public class AuthorizationService extends AbstractComponent {
Setting.boolSetting(setting("authc.anonymous.authz_exception"), true, Property.NodeScope);
public static final String INDICES_PERMISSIONS_KEY = "_indices_permissions";
public static final String ORIGINATING_ACTION_KEY = "_originating_action_name";
public static final String ROLE_NAMES_KEY = "_effective_role_names";
private static final Predicate<String> MONITOR_INDEX_PREDICATE = IndexPrivilege.MONITOR.predicate();
private static final Predicate<String> SAME_USER_PRIVILEGE = Automatons.predicate(
@ -148,12 +149,13 @@ public class AuthorizationService extends AbstractComponent {
// first we need to check if the user is the system. If it is, we'll just authorize the system access
if (SystemUser.is(authentication.getUser())) {
if (SystemUser.isAuthorized(action) && SystemUser.is(authentication.getUser())) {
setIndicesAccessControl(IndicesAccessControl.ALLOW_ALL);
grant(authentication, action, request);
if (SystemUser.isAuthorized(action)) {
putTransientIfNonExisting(INDICES_PERMISSIONS_KEY, IndicesAccessControl.ALLOW_ALL);
putTransientIfNonExisting(ROLE_NAMES_KEY, new String[] { SystemUser.ROLE_NAME });
grant(authentication, action, request, new String[] { SystemUser.ROLE_NAME });
return;
}
throw denial(authentication, action, request);
throw denial(authentication, action, request, new String[] { SystemUser.ROLE_NAME });
}
// get the roles of the authenticated user, which may be different than the effective
@ -165,29 +167,30 @@ public class AuthorizationService extends AbstractComponent {
// if we are running as a user we looked up then the authentication must contain a lookedUpBy. If it doesn't then this user
// doesn't really exist but the authc service allowed it through to avoid leaking users that exist in the system
if (authentication.getLookedUpBy() == null) {
throw denyRunAs(authentication, action, request);
throw denyRunAs(authentication, action, request, permission.names());
} else if (permission.runAs().check(authentication.getUser().principal())) {
grantRunAs(authentication, action, request);
grantRunAs(authentication, action, request, permission.names());
permission = runAsRole;
} else {
throw denyRunAs(authentication, action, request);
throw denyRunAs(authentication, action, request, permission.names());
}
}
putTransientIfNonExisting(ROLE_NAMES_KEY, permission.names());
// first, we'll check if the action is a cluster action. If it is, we'll only check it against the cluster permissions
if (ClusterPrivilege.ACTION_MATCHER.test(action)) {
ClusterPermission cluster = permission.cluster();
if (cluster.check(action) || checkSameUserPermissions(action, request, authentication)) {
setIndicesAccessControl(IndicesAccessControl.ALLOW_ALL);
grant(authentication, action, request);
putTransientIfNonExisting(INDICES_PERMISSIONS_KEY, IndicesAccessControl.ALLOW_ALL);
grant(authentication, action, request, permission.names());
return;
}
throw denial(authentication, action, request);
throw denial(authentication, action, request, permission.names());
}
// ok... this is not a cluster action, let's verify it's an indices action
if (!IndexPrivilege.ACTION_MATCHER.test(action)) {
throw denial(authentication, action, request);
throw denial(authentication, action, request, permission.names());
}
//composite actions are explicitly listed and will be authorized at the sub-request / shard level
@ -198,10 +201,10 @@ public class AuthorizationService extends AbstractComponent {
}
// we check if the user can execute the action, without looking at indices, which will be authorized at the shard level
if (permission.indices().check(action)) {
grant(authentication, action, request);
grant(authentication, action, request, permission.names());
return;
}
throw denial(authentication, action, request);
throw denial(authentication, action, request, permission.names());
} else if (isTranslatedToBulkAction(action)) {
if (request instanceof CompositeIndicesRequest == false) {
throw new IllegalStateException("Bulk translated actions must implement " + CompositeIndicesRequest.class.getSimpleName()
@ -209,10 +212,10 @@ public class AuthorizationService extends AbstractComponent {
}
// we check if the user can execute the action, without looking at indices, which will be authorized at the shard level
if (permission.indices().check(action)) {
grant(authentication, action, request);
grant(authentication, action, request, permission.names());
return;
}
throw denial(authentication, action, request);
throw denial(authentication, action, request, permission.names());
} else if (TransportActionProxy.isProxyAction(action)) {
// we authorize proxied actions once they are "unwrapped" on the next node
if (TransportActionProxy.isProxyRequest(originalRequest) == false) {
@ -220,12 +223,12 @@ public class AuthorizationService extends AbstractComponent {
+ action + "] is a proxy action");
}
if (permission.indices().check(action)) {
grant(authentication, action, request);
grant(authentication, action, request, permission.names());
return;
} else {
// we do this here in addition to the denial below since we might run into an assertion on scroll requrest below if we
// don't have permission to read cross cluster but wrap a scroll request.
throw denial(authentication, action, request);
throw denial(authentication, action, request, permission.names());
}
}
@ -244,18 +247,18 @@ public class AuthorizationService extends AbstractComponent {
// index and if they cannot, we can fail the request early before we allow the execution of the action and in
// turn the shard actions
if (SearchScrollAction.NAME.equals(action) && permission.indices().check(action) == false) {
throw denial(authentication, action, request);
throw denial(authentication, action, request, permission.names());
} else {
// we store the request as a transient in the ThreadContext in case of a authorization failure at the shard
// level. If authorization fails we will audit a access_denied message and will use the request to retrieve
// information such as the index and the incoming address of the request
grant(authentication, action, request);
grant(authentication, action, request, permission.names());
return;
}
} else {
assert false :
"only scroll related requests are known indices api that don't support retrieving the indices they relate to";
throw denial(authentication, action, request);
throw denial(authentication, action, request, permission.names());
}
}
@ -265,33 +268,33 @@ public class AuthorizationService extends AbstractComponent {
// If this request does not allow remote indices
// then the user must have permission to perform this action on at least 1 local index
if (allowsRemoteIndices == false && permission.indices().check(action) == false) {
throw denial(authentication, action, request);
throw denial(authentication, action, request, permission.names());
}
final MetaData metaData = clusterService.state().metaData();
final AuthorizedIndices authorizedIndices = new AuthorizedIndices(authentication.getUser(), permission, action, metaData);
final ResolvedIndices resolvedIndices = resolveIndexNames(authentication, action, request, metaData, authorizedIndices);
final ResolvedIndices resolvedIndices = resolveIndexNames(authentication, action, request, metaData, authorizedIndices, permission);
assert !resolvedIndices.isEmpty()
: "every indices request needs to have its indices set thus the resolved indices must not be empty";
// If this request does reference any remote indices
// then the user must have permission to perform this action on at least 1 local index
if (resolvedIndices.getRemote().isEmpty() && permission.indices().check(action) == false) {
throw denial(authentication, action, request);
throw denial(authentication, action, request, permission.names());
}
//all wildcard expressions have been resolved and only the security plugin could have set '-*' here.
//'-*' matches no indices so we allow the request to go through, which will yield an empty response
if (resolvedIndices.isNoIndicesPlaceholder()) {
setIndicesAccessControl(IndicesAccessControl.ALLOW_NO_INDICES);
grant(authentication, action, request);
putTransientIfNonExisting(INDICES_PERMISSIONS_KEY, IndicesAccessControl.ALLOW_NO_INDICES);
grant(authentication, action, request, permission.names());
return;
}
final Set<String> localIndices = new HashSet<>(resolvedIndices.getLocal());
IndicesAccessControl indicesAccessControl = permission.authorize(action, localIndices, metaData, fieldPermissionsCache);
if (!indicesAccessControl.isGranted()) {
throw denial(authentication, action, request);
throw denial(authentication, action, request, permission.names());
} else if (hasSecurityIndexAccess(indicesAccessControl)
&& MONITOR_INDEX_PREDICATE.test(action) == false
&& isSuperuser(authentication.getUser()) == false) {
@ -299,9 +302,9 @@ public class AuthorizationService extends AbstractComponent {
// purposes. These monitor requests also sometimes resolve indices concretely and then requests them
logger.debug("user [{}] attempted to directly perform [{}] against the security index [{}]",
authentication.getUser().principal(), action, SecurityLifecycleService.SECURITY_INDEX_NAME);
throw denial(authentication, action, request);
throw denial(authentication, action, request, permission.names());
} else {
setIndicesAccessControl(indicesAccessControl);
putTransientIfNonExisting(INDICES_PERMISSIONS_KEY, indicesAccessControl);
}
//if we are creating an index we need to authorize potential aliases created at the same time
@ -315,7 +318,7 @@ public class AuthorizationService extends AbstractComponent {
}
indicesAccessControl = permission.authorize("indices:admin/aliases", aliasesAndIndices, metaData, fieldPermissionsCache);
if (!indicesAccessControl.isGranted()) {
throw denial(authentication, "indices:admin/aliases", request);
throw denial(authentication, "indices:admin/aliases", request, permission.names());
}
// no need to re-add the indicesAccessControl in the context,
// because the create index call doesn't do anything FLS or DLS
@ -330,7 +333,7 @@ public class AuthorizationService extends AbstractComponent {
authorizeBulkItems(authentication, (BulkShardRequest) request, permission, metaData, localIndices, authorizedIndices);
}
grant(authentication, action, originalRequest);
grant(authentication, action, originalRequest, permission.names());
}
private boolean hasSecurityIndexAccess(IndicesAccessControl indicesAccessControl) {
@ -345,13 +348,17 @@ public class AuthorizationService extends AbstractComponent {
/**
* Performs authorization checks on the items within a {@link BulkShardRequest}.
* This inspects the {@link BulkItemRequest items} within the request, computes an <em>implied</em> action for each item's
* {@link DocWriteRequest#opType()}, and then checks whether that action is allowed on the targeted index.
* Items that fail this checks are {@link BulkItemRequest#abort(String, Exception) aborted}, with an
* {@link #denial(Authentication, String, TransportRequest) access denied} exception.
* Because a shard level request is for exactly 1 index, and there are a small number of possible item
* {@link DocWriteRequest.OpType types}, the number of distinct authorization checks that need to be performed is very small, but the
* results must be cached, to avoid adding a high overhead to each bulk request.
* This inspects the {@link BulkItemRequest items} within the request, computes
* an <em>implied</em> action for each item's {@link DocWriteRequest#opType()},
* and then checks whether that action is allowed on the targeted index. Items
* that fail this checks are {@link BulkItemRequest#abort(String, Exception)
* aborted}, with an
* {@link #denial(Authentication, String, TransportRequest, String[]) access
* denied} exception. Because a shard level request is for exactly 1 index, and
* there are a small number of possible item {@link DocWriteRequest.OpType
* types}, the number of distinct authorization checks that need to be performed
* is very small, but the results must be cached, to avoid adding a high
* overhead to each bulk request.
*/
private void authorizeBulkItems(Authentication authentication, BulkShardRequest request, Role permission,
MetaData metaData, Set<String> indices, AuthorizedIndices authorizedIndices) {
@ -385,7 +392,7 @@ public class AuthorizationService extends AbstractComponent {
return itemAccessControl.isGranted();
});
if (granted == false) {
item.abort(resolvedIndex, denial(authentication, itemAction, request));
item.abort(resolvedIndex, denial(authentication, itemAction, request, permission.names()));
}
}
}
@ -410,21 +417,15 @@ public class AuthorizationService extends AbstractComponent {
}
private ResolvedIndices resolveIndexNames(Authentication authentication, String action, TransportRequest request, MetaData metaData,
AuthorizedIndices authorizedIndices) {
AuthorizedIndices authorizedIndices, Role permission) {
try {
return indicesAndAliasesResolver.resolve(request, metaData, authorizedIndices);
} catch (Exception e) {
auditTrail.accessDenied(authentication.getUser(), action, request);
auditTrail.accessDenied(authentication.getUser(), action, request, permission.names());
throw e;
}
}
private void setIndicesAccessControl(IndicesAccessControl accessControl) {
if (threadContext.getTransient(INDICES_PERMISSIONS_KEY) == null) {
threadContext.putTransient(INDICES_PERMISSIONS_KEY, accessControl);
}
}
private void putTransientIfNonExisting(String key, Object value) {
Object existing = threadContext.getTransient(key);
if (existing == null) {
@ -462,7 +463,7 @@ public class AuthorizationService extends AbstractComponent {
if (roleNames.isEmpty()) {
roleActionListener.onResponse(Role.EMPTY);
} else if (roleNames.contains(ReservedRolesStore.SUPERUSER_ROLE.name())) {
} else if (roleNames.contains(ReservedRolesStore.SUPERUSER_ROLE_DESCRIPTOR.getName())) {
roleActionListener.onResponse(ReservedRolesStore.SUPERUSER_ROLE);
} else {
rolesStore.roles(roleNames, fieldPermissionsCache, roleActionListener);
@ -543,22 +544,23 @@ public class AuthorizationService extends AbstractComponent {
return ReservedRealm.TYPE.equals(realmType) || NativeRealm.TYPE.equals(realmType);
}
ElasticsearchSecurityException denial(Authentication authentication, String action, TransportRequest request) {
auditTrail.accessDenied(authentication.getUser(), action, request);
ElasticsearchSecurityException denial(Authentication authentication, String action, TransportRequest request, String[] roleNames) {
auditTrail.accessDenied(authentication.getUser(), action, request, roleNames);
return denialException(authentication, action);
}
private ElasticsearchSecurityException denyRunAs(Authentication authentication, String action, TransportRequest request) {
auditTrail.runAsDenied(authentication.getUser(), action, request);
private ElasticsearchSecurityException denyRunAs(Authentication authentication, String action, TransportRequest request,
String[] roleNames) {
auditTrail.runAsDenied(authentication.getUser(), action, request, roleNames);
return denialException(authentication, action);
}
private void grant(Authentication authentication, String action, TransportRequest request) {
auditTrail.accessGranted(authentication.getUser(), action, request);
private void grant(Authentication authentication, String action, TransportRequest request, String[] roleNames) {
auditTrail.accessGranted(authentication.getUser(), action, request, roleNames);
}
private void grantRunAs(Authentication authentication, String action, TransportRequest request) {
auditTrail.runAsGranted(authentication.getUser(), action, request);
private void grantRunAs(Authentication authentication, String action, TransportRequest request, String[] roleNames) {
auditTrail.runAsGranted(authentication.getUser(), action, request, roleNames);
}
private ElasticsearchSecurityException denialException(Authentication authentication, String action) {
@ -579,7 +581,7 @@ public class AuthorizationService extends AbstractComponent {
static boolean isSuperuser(User user) {
return Arrays.stream(user.roles())
.anyMatch(ReservedRolesStore.SUPERUSER_ROLE.name()::equals);
.anyMatch(ReservedRolesStore.SUPERUSER_ROLE_DESCRIPTOR.getName()::equals);
}
public static void addSettings(List<Setting<?>> settings) {

View File

@ -16,6 +16,7 @@ import org.elasticsearch.xpack.security.audit.AuditTrailService;
import org.elasticsearch.xpack.security.authc.Authentication;
import static org.elasticsearch.xpack.security.authz.AuthorizationService.ORIGINATING_ACTION_KEY;
import static org.elasticsearch.xpack.security.authz.AuthorizationService.ROLE_NAMES_KEY;
/**
* A {@link SearchOperationListener} that is used to provide authorization for scroll requests.
@ -59,7 +60,8 @@ public final class SecuritySearchOperationListener implements SearchOperationLis
final Authentication originalAuth = searchContext.scrollContext().getFromContext(Authentication.AUTHENTICATION_KEY);
final Authentication current = Authentication.getAuthentication(threadContext);
final String action = threadContext.getTransient(ORIGINATING_ACTION_KEY);
ensureAuthenticatedUserIsSame(originalAuth, current, auditTrailService, searchContext.id(), action, request);
ensureAuthenticatedUserIsSame(originalAuth, current, auditTrailService, searchContext.id(), action, request,
threadContext.getTransient(ROLE_NAMES_KEY));
}
}
}
@ -71,7 +73,7 @@ public final class SecuritySearchOperationListener implements SearchOperationLis
* (or lookup) realm. To work around this we compare the username and the originating realm type.
*/
static void ensureAuthenticatedUserIsSame(Authentication original, Authentication current, AuditTrailService auditTrailService,
long id, String action, TransportRequest request) {
long id, String action, TransportRequest request, String[] roleNames) {
// this is really a best effort attempt since we cannot guarantee principal uniqueness
// and realm names can change between nodes.
final boolean samePrincipal = original.getUser().principal().equals(current.getUser().principal());
@ -90,7 +92,7 @@ public final class SecuritySearchOperationListener implements SearchOperationLis
final boolean sameUser = samePrincipal && sameRealmType;
if (sameUser == false) {
auditTrailService.accessDenied(current.getUser(), action, request);
auditTrailService.accessDenied(current.getUser(), action, request, roleNames);
throw new SearchContextMissingException(id);
}
}

View File

@ -27,20 +27,20 @@ public final class Role {
public static final Role EMPTY = Role.builder("__empty").build();
private final String name;
private final String[] names;
private final ClusterPermission cluster;
private final IndicesPermission indices;
private final RunAsPermission runAs;
Role(String name, ClusterPermission cluster, IndicesPermission indices, RunAsPermission runAs) {
this.name = name;
Role(String[] names, ClusterPermission cluster, IndicesPermission indices, RunAsPermission runAs) {
this.names = names;
this.cluster = Objects.requireNonNull(cluster);
this.indices = Objects.requireNonNull(indices);
this.runAs = Objects.requireNonNull(runAs);
}
public String name() {
return name;
public String[] names() {
return names;
}
public ClusterPermission cluster() {
@ -55,12 +55,12 @@ public final class Role {
return runAs;
}
public static Builder builder(String name) {
return new Builder(name, null);
public static Builder builder(String... names) {
return new Builder(names, null);
}
public static Builder builder(String name, FieldPermissionsCache fieldPermissionsCache) {
return new Builder(name, fieldPermissionsCache);
public static Builder builder(String[] names, FieldPermissionsCache fieldPermissionsCache) {
return new Builder(names, fieldPermissionsCache);
}
public static Builder builder(RoleDescriptor rd, FieldPermissionsCache fieldPermissionsCache) {
@ -91,19 +91,19 @@ public final class Role {
public static class Builder {
private final String name;
private final String[] names;
private ClusterPermission cluster = ClusterPermission.NONE;
private RunAsPermission runAs = RunAsPermission.NONE;
private List<IndicesPermission.Group> groups = new ArrayList<>();
private FieldPermissionsCache fieldPermissionsCache = null;
private Builder(String name, FieldPermissionsCache fieldPermissionsCache) {
this.name = name;
private Builder(String[] names, FieldPermissionsCache fieldPermissionsCache) {
this.names = names;
this.fieldPermissionsCache = fieldPermissionsCache;
}
private Builder(RoleDescriptor rd, @Nullable FieldPermissionsCache fieldPermissionsCache) {
this.name = rd.getName();
this.names = new String[] { rd.getName() };
this.fieldPermissionsCache = fieldPermissionsCache;
if (rd.getClusterPrivileges().length == 0) {
cluster = ClusterPermission.NONE;
@ -140,7 +140,7 @@ public final class Role {
public Role build() {
IndicesPermission indices = groups.isEmpty() ? IndicesPermission.NONE :
new IndicesPermission(groups.toArray(new IndicesPermission.Group[groups.size()]));
return new Role(name, cluster, indices, runAs);
return new Role(names, cluster, indices, runAs);
}
static List<IndicesPermission.Group> convertFromIndicesPrivileges(RoleDescriptor.IndicesPrivileges[] indicesPrivileges,

View File

@ -5,6 +5,7 @@
*/
package org.elasticsearch.xpack.security.authz.store;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
@ -239,13 +240,12 @@ public class CompositeRolesStore extends AbstractComponent {
if (roleDescriptors.isEmpty()) {
return Role.EMPTY;
}
StringBuilder nameBuilder = new StringBuilder();
Set<String> clusterPrivileges = new HashSet<>();
Set<String> runAs = new HashSet<>();
Map<Set<String>, MergeableIndicesPrivilege> indicesPrivilegesMap = new HashMap<>();
List<String> roleNames = new ArrayList<>(roleDescriptors.size());
for (RoleDescriptor descriptor : roleDescriptors) {
nameBuilder.append(descriptor.getName());
nameBuilder.append('_');
roleNames.add(descriptor.getName());
if (descriptor.getClusterPrivileges() != null) {
clusterPrivileges.addAll(Arrays.asList(descriptor.getClusterPrivileges()));
}
@ -276,7 +276,7 @@ public class CompositeRolesStore extends AbstractComponent {
final Set<String> clusterPrivs = clusterPrivileges.isEmpty() ? null : clusterPrivileges;
final Privilege runAsPrivilege = runAs.isEmpty() ? Privilege.NONE : new Privilege(runAs, runAs.toArray(Strings.EMPTY_ARRAY));
Role.Builder builder = Role.builder(nameBuilder.toString(), fieldPermissionsCache)
Role.Builder builder = Role.builder(roleNames.toArray(new String[roleNames.size()]), fieldPermissionsCache)
.cluster(ClusterPrivilege.get(clusterPrivs))
.runAs(runAsPrivilege);
indicesPrivilegesMap.entrySet().forEach((entry) -> {

View File

@ -7,8 +7,6 @@ package org.elasticsearch.xpack.security.user;
import org.elasticsearch.xpack.security.support.MetadataUtils;
import java.util.HashMap;
import java.util.Map;
/**
* The reserved {@code elastic} superuser. Has full permission/access to the cluster/indices and can
@ -17,7 +15,8 @@ import java.util.Map;
public class ElasticUser extends User {
public static final String NAME = "elastic";
private static final String ROLE_NAME = "superuser";
// used for testing in a different package
public static final String ROLE_NAME = "superuser";
public ElasticUser(boolean enabled) {
super(NAME, new String[] { ROLE_NAME }, null, null, MetadataUtils.DEFAULT_RESERVED_METADATA, enabled);

View File

@ -40,6 +40,9 @@
"principal": {
"type": "keyword"
},
"roles": {
"type": "keyword"
},
"run_by_principal": {
"type": "keyword"
},

View File

@ -138,11 +138,12 @@ public class AuditTrailServiceTests extends ESTestCase {
public void testAccessGranted() throws Exception {
User user = new User("_username", "r1");
service.accessGranted(user, "_action", message);
String[] roles = new String[] { randomAlphaOfLengthBetween(1, 6) };
service.accessGranted(user, "_action", message, roles);
verify(licenseState).isAuditingAllowed();
if (isAuditingAllowed) {
for (AuditTrail auditTrail : auditTrails) {
verify(auditTrail).accessGranted(user, "_action", message);
verify(auditTrail).accessGranted(user, "_action", message, roles);
}
} else {
verifyZeroInteractions(auditTrails.toArray((Object[]) new AuditTrail[auditTrails.size()]));
@ -151,11 +152,12 @@ public class AuditTrailServiceTests extends ESTestCase {
public void testAccessDenied() throws Exception {
User user = new User("_username", "r1");
service.accessDenied(user, "_action", message);
String[] roles = new String[] { randomAlphaOfLengthBetween(1, 6) };
service.accessDenied(user, "_action", message, roles);
verify(licenseState).isAuditingAllowed();
if (isAuditingAllowed) {
for (AuditTrail auditTrail : auditTrails) {
verify(auditTrail).accessDenied(user, "_action", message);
verify(auditTrail).accessDenied(user, "_action", message, roles);
}
} else {
verifyZeroInteractions(auditTrails.toArray((Object[]) new AuditTrail[auditTrails.size()]));

View File

@ -173,7 +173,7 @@ public class IndexAuditTrailMutedTests extends ESTestCase {
createAuditTrail(new String[] { "access_granted" });
TransportMessage message = mock(TransportMessage.class);
User user = mock(User.class);
auditTrail.accessGranted(user, randomAlphaOfLengthBetween(6, 40), message);
auditTrail.accessGranted(user, randomAlphaOfLengthBetween(6, 40), message, new String[] { "role" });
assertThat(messageEnqueued.get(), is(false));
assertThat(clientCalled.get(), is(false));
@ -184,7 +184,7 @@ public class IndexAuditTrailMutedTests extends ESTestCase {
createAuditTrail(randomFrom(new String[] { "access_granted" }, null));
TransportMessage message = mock(TransportMessage.class);
User user = SystemUser.INSTANCE;
auditTrail.accessGranted(user, "internal:foo", message);
auditTrail.accessGranted(user, "internal:foo", message, new String[] { "role" });
assertThat(messageEnqueued.get(), is(false));
assertThat(clientCalled.get(), is(false));
@ -195,7 +195,7 @@ public class IndexAuditTrailMutedTests extends ESTestCase {
createAuditTrail(new String[] { "access_denied" });
TransportMessage message = mock(TransportMessage.class);
User user = mock(User.class);
auditTrail.accessDenied(user, randomAlphaOfLengthBetween(6, 40), message);
auditTrail.accessDenied(user, randomAlphaOfLengthBetween(6, 40), message, new String[] { "role" });
assertThat(messageEnqueued.get(), is(false));
assertThat(clientCalled.get(), is(false));
@ -249,7 +249,7 @@ public class IndexAuditTrailMutedTests extends ESTestCase {
TransportMessage message = mock(TransportMessage.class);
User user = mock(User.class);
auditTrail.runAsGranted(user, randomAlphaOfLengthBetween(6, 40), message);
auditTrail.runAsGranted(user, randomAlphaOfLengthBetween(6, 40), message, new String[] { "role" });
assertThat(messageEnqueued.get(), is(false));
assertThat(clientCalled.get(), is(false));
@ -261,7 +261,7 @@ public class IndexAuditTrailMutedTests extends ESTestCase {
TransportMessage message = mock(TransportMessage.class);
User user = mock(User.class);
auditTrail.runAsDenied(user, randomAlphaOfLengthBetween(6, 40), message);
auditTrail.runAsDenied(user, randomAlphaOfLengthBetween(6, 40), message, new String[] { "role" });
assertThat(messageEnqueued.get(), is(false));
assertThat(clientCalled.get(), is(false));

View File

@ -477,7 +477,7 @@ public class IndexAuditTrailTests extends SecurityIntegTestCase {
assertEquals("_realm", sourceMap.get("realm"));
if (message instanceof IndicesRequest) {
List<Object> indices = (List<Object>) sourceMap.get("indices");
assertThat(indices, containsInAnyOrder((Object[]) ((IndicesRequest)message).indices()));
assertThat(indices, containsInAnyOrder((Object[]) ((IndicesRequest) message).indices()));
}
assertEquals(sourceMap.get("request"), message.getClass().getSimpleName());
}
@ -507,7 +507,8 @@ public class IndexAuditTrailTests extends SecurityIntegTestCase {
} else {
user = new User("_username", new String[]{"r1"});
}
auditor.accessGranted(user, "_action", message);
String role = randomAlphaOfLengthBetween(1, 6);
auditor.accessGranted(user, "_action", message, new String[] { role });
SearchHit hit = getIndexedAuditMessage(enqueuedMessage.get());
assertAuditMessage(hit, "transport", "access_granted");
@ -520,9 +521,10 @@ public class IndexAuditTrailTests extends SecurityIntegTestCase {
assertEquals("_username", sourceMap.get("principal"));
}
assertEquals("_action", sourceMap.get("action"));
assertThat((Iterable<String>) sourceMap.get(IndexAuditTrail.Field.ROLE_NAMES), containsInAnyOrder(role));
if (message instanceof IndicesRequest) {
List<Object> indices = (List<Object>) sourceMap.get("indices");
assertThat(indices, containsInAnyOrder((Object[]) ((IndicesRequest)message).indices()));
assertThat(indices, containsInAnyOrder((Object[]) ((IndicesRequest) message).indices()));
}
assertEquals(sourceMap.get("request"), message.getClass().getSimpleName());
}
@ -530,7 +532,8 @@ public class IndexAuditTrailTests extends SecurityIntegTestCase {
public void testSystemAccessGranted() throws Exception {
initialize(new String[] { "system_access_granted" }, null);
TransportMessage message = randomBoolean() ? new RemoteHostMockMessage() : new LocalHostMockMessage();
auditor.accessGranted(SystemUser.INSTANCE, "internal:_action", message);
String role = randomAlphaOfLengthBetween(1, 6);
auditor.accessGranted(SystemUser.INSTANCE, "internal:_action", message, new String[] { role });
SearchHit hit = getIndexedAuditMessage(enqueuedMessage.get());
assertAuditMessage(hit, "transport", "access_granted");
@ -538,6 +541,7 @@ public class IndexAuditTrailTests extends SecurityIntegTestCase {
assertEquals("transport", sourceMap.get("origin_type"));
assertEquals(SystemUser.INSTANCE.principal(), sourceMap.get("principal"));
assertEquals("internal:_action", sourceMap.get("action"));
assertThat((Iterable<String>) sourceMap.get(IndexAuditTrail.Field.ROLE_NAMES), containsInAnyOrder(role));
assertEquals(sourceMap.get("request"), message.getClass().getSimpleName());
}
@ -551,7 +555,8 @@ public class IndexAuditTrailTests extends SecurityIntegTestCase {
} else {
user = new User("_username", new String[]{"r1"});
}
auditor.accessDenied(user, "_action", message);
String role = randomAlphaOfLengthBetween(1, 6);
auditor.accessDenied(user, "_action", message, new String[] { role });
SearchHit hit = getIndexedAuditMessage(enqueuedMessage.get());
Map<String, Object> sourceMap = hit.getSourceAsMap();
@ -566,9 +571,10 @@ public class IndexAuditTrailTests extends SecurityIntegTestCase {
assertEquals("_action", sourceMap.get("action"));
if (message instanceof IndicesRequest) {
List<Object> indices = (List<Object>) sourceMap.get("indices");
assertThat(indices, containsInAnyOrder((Object[]) ((IndicesRequest)message).indices()));
assertThat(indices, containsInAnyOrder((Object[]) ((IndicesRequest) message).indices()));
}
assertEquals(sourceMap.get("request"), message.getClass().getSimpleName());
assertThat((Iterable<String>) sourceMap.get(IndexAuditTrail.Field.ROLE_NAMES), containsInAnyOrder(role));
}
public void testTamperedRequestRest() throws Exception {
@ -659,7 +665,8 @@ public class IndexAuditTrailTests extends SecurityIntegTestCase {
initialize();
TransportMessage message = randomFrom(new RemoteHostMockMessage(), new LocalHostMockMessage(), new MockIndicesTransportMessage());
User user = new User("running as", new String[]{"r2"}, new User("_username", new String[] {"r1"}));
auditor.runAsGranted(user, "_action", message);
String role = randomAlphaOfLengthBetween(1, 6);
auditor.runAsGranted(user, "_action", message, new String[] { role });
SearchHit hit = getIndexedAuditMessage(enqueuedMessage.get());
assertAuditMessage(hit, "transport", "run_as_granted");
@ -667,6 +674,7 @@ public class IndexAuditTrailTests extends SecurityIntegTestCase {
assertEquals("transport", sourceMap.get("origin_type"));
assertThat(sourceMap.get("principal"), is("_username"));
assertThat(sourceMap.get("run_as_principal"), is("running as"));
assertThat((Iterable<String>) sourceMap.get(IndexAuditTrail.Field.ROLE_NAMES), containsInAnyOrder(role));
assertEquals("_action", sourceMap.get("action"));
assertEquals(sourceMap.get("request"), message.getClass().getSimpleName());
}
@ -675,7 +683,7 @@ public class IndexAuditTrailTests extends SecurityIntegTestCase {
initialize();
TransportMessage message = randomFrom(new RemoteHostMockMessage(), new LocalHostMockMessage(), new MockIndicesTransportMessage());
User user = new User("running as", new String[]{"r2"}, new User("_username", new String[] {"r1"}));
auditor.runAsDenied(user, "_action", message);
auditor.runAsDenied(user, "_action", message, new String[] { "r1" });
SearchHit hit = getIndexedAuditMessage(enqueuedMessage.get());
assertAuditMessage(hit, "transport", "run_as_denied");

View File

@ -337,8 +337,10 @@ public class LoggingAuditTrailTests extends ESTestCase {
} else {
user = new User("_username", new String[]{"r1"});
}
String userInfo = runAs ? "principal=[running as], run_by_principal=[_username]" : "principal=[_username]";
auditTrail.accessGranted(user, "_action", message);
String role = randomAlphaOfLengthBetween(1, 6);
auditTrail.accessGranted(user, "_action", message, new String[] { role });
String userInfo = (runAs ? "principal=[running as], run_by_principal=[_username]" : "principal=[_username]") +
", roles=[" + role + "]";
if (message instanceof IndicesRequest) {
assertMsg(logger, Level.INFO, prefix + "[transport] [access_granted]\t" + origins + ", " + userInfo +
", action=[_action], indices=[" + indices(message) + "], request=[MockIndicesRequest]");
@ -351,7 +353,7 @@ public class LoggingAuditTrailTests extends ESTestCase {
CapturingLogger.output(logger.getName(), Level.INFO).clear();
settings = Settings.builder().put(settings).put("xpack.security.audit.logfile.events.exclude", "access_granted").build();
auditTrail = new LoggingAuditTrail(settings, clusterService, logger, threadContext);
auditTrail.accessGranted(user, "_action", message);
auditTrail.accessGranted(user, "_action", message, new String[] { role });
assertEmptyLog(logger);
}
@ -359,21 +361,23 @@ public class LoggingAuditTrailTests extends ESTestCase {
Logger logger = CapturingLogger.newCapturingLogger(Level.INFO);
LoggingAuditTrail auditTrail = new LoggingAuditTrail(settings, clusterService, logger, threadContext);
TransportMessage message = randomBoolean() ? new MockMessage(threadContext) : new MockIndicesRequest(threadContext);
auditTrail.accessGranted(SystemUser.INSTANCE, "internal:_action", message);
String role = randomAlphaOfLengthBetween(1, 6);
auditTrail.accessGranted(SystemUser.INSTANCE, "internal:_action", message, new String[] { role });
assertEmptyLog(logger);
// test enabled
settings = Settings.builder().put(settings).put("xpack.security.audit.logfile.events.include", "system_access_granted").build();
auditTrail = new LoggingAuditTrail(settings, clusterService, logger, threadContext);
String origins = LoggingAuditTrail.originAttributes(threadContext, message, auditTrail.localNodeInfo);
auditTrail.accessGranted(SystemUser.INSTANCE, "internal:_action", message);
auditTrail.accessGranted(SystemUser.INSTANCE, "internal:_action", message, new String[] { role });
if (message instanceof IndicesRequest) {
assertMsg(logger, Level.INFO, prefix + "[transport] [access_granted]\t" + origins + ", principal=[" +
SystemUser.INSTANCE.principal()
+ "], action=[internal:_action], indices=[" + indices(message) + "], request=[MockIndicesRequest]");
+ "], roles=[" + role + "], action=[internal:_action], indices=[" + indices(message)
+ "], request=[MockIndicesRequest]");
} else {
assertMsg(logger, Level.INFO, prefix + "[transport] [access_granted]\t" + origins + ", principal=[" +
SystemUser.INSTANCE.principal() + "], action=[internal:_action], request=[MockMessage]");
SystemUser.INSTANCE.principal() + "], roles=[" + role + "], action=[internal:_action], request=[MockMessage]");
}
}
@ -389,8 +393,10 @@ public class LoggingAuditTrailTests extends ESTestCase {
} else {
user = new User("_username", new String[]{"r1"});
}
String userInfo = runAs ? "principal=[running as], run_by_principal=[_username]" : "principal=[_username]";
auditTrail.accessGranted(user, "internal:_action", message);
String role = randomAlphaOfLengthBetween(1, 6);
auditTrail.accessGranted(user, "internal:_action", message, new String[] { role });
String userInfo = (runAs ? "principal=[running as], run_by_principal=[_username]" : "principal=[_username]") +
", roles=[" + role + "]";
if (message instanceof IndicesRequest) {
assertMsg(logger, Level.INFO, prefix + "[transport] [access_granted]\t" + origins + ", " + userInfo +
", action=[internal:_action], indices=[" + indices(message) + "], request=[MockIndicesRequest]");
@ -403,7 +409,7 @@ public class LoggingAuditTrailTests extends ESTestCase {
CapturingLogger.output(logger.getName(), Level.INFO).clear();
settings = Settings.builder().put(settings).put("xpack.security.audit.logfile.events.exclude", "access_granted").build();
auditTrail = new LoggingAuditTrail(settings, clusterService, logger, threadContext);
auditTrail.accessGranted(user, "internal:_action", message);
auditTrail.accessGranted(user, "internal:_action", message, new String[] { role });
assertEmptyLog(logger);
}
@ -419,8 +425,10 @@ public class LoggingAuditTrailTests extends ESTestCase {
} else {
user = new User("_username", new String[]{"r1"});
}
String userInfo = runAs ? "principal=[running as], run_by_principal=[_username]" : "principal=[_username]";
auditTrail.accessDenied(user, "_action", message);
String role = randomAlphaOfLengthBetween(1, 6);
auditTrail.accessDenied(user, "_action", message, new String[] { role });
String userInfo = (runAs ? "principal=[running as], run_by_principal=[_username]" : "principal=[_username]") +
", roles=[" + role + "]";
if (message instanceof IndicesRequest) {
assertMsg(logger, Level.INFO, prefix + "[transport] [access_denied]\t" + origins + ", " + userInfo +
", action=[_action], indices=[" + indices(message) + "], request=[MockIndicesRequest]");
@ -433,7 +441,7 @@ public class LoggingAuditTrailTests extends ESTestCase {
CapturingLogger.output(logger.getName(), Level.INFO).clear();
settings = Settings.builder().put(settings).put("xpack.security.audit.logfile.events.exclude", "access_denied").build();
auditTrail = new LoggingAuditTrail(settings, clusterService, logger, threadContext);
auditTrail.accessDenied(user, "_action", message);
auditTrail.accessDenied(user, "_action", message, new String[] { role });
assertEmptyLog(logger);
}
@ -552,15 +560,16 @@ public class LoggingAuditTrailTests extends ESTestCase {
TransportMessage message = new MockMessage(threadContext);
String origins = LoggingAuditTrail.originAttributes(threadContext, message, auditTrail.localNodeInfo);
User user = new User("running as", new String[]{"r2"}, new User("_username", new String[] {"r1"}));
auditTrail.runAsGranted(user, "_action", message);
String role = randomAlphaOfLengthBetween(1, 6);
auditTrail.runAsGranted(user, "_action", message, new String[] { role });
assertMsg(logger, Level.INFO, prefix + "[transport] [run_as_granted]\t" + origins +
", principal=[_username], run_as_principal=[running as], action=[_action], request=[MockMessage]");
", principal=[_username], run_as_principal=[running as], roles=[" + role + "], action=[_action], request=[MockMessage]");
// test disabled
CapturingLogger.output(logger.getName(), Level.INFO).clear();
settings = Settings.builder().put(settings).put("xpack.security.audit.logfile.events.exclude", "run_as_granted").build();
auditTrail = new LoggingAuditTrail(settings, clusterService, logger, threadContext);
auditTrail.runAsGranted(user, "_action", message);
auditTrail.runAsGranted(user, "_action", message, new String[] { role });
assertEmptyLog(logger);
}
@ -570,15 +579,16 @@ public class LoggingAuditTrailTests extends ESTestCase {
TransportMessage message = new MockMessage(threadContext);
String origins = LoggingAuditTrail.originAttributes(threadContext, message, auditTrail.localNodeInfo);
User user = new User("running as", new String[]{"r2"}, new User("_username", new String[] {"r1"}));
auditTrail.runAsDenied(user, "_action", message);
String role = randomAlphaOfLengthBetween(1, 6);
auditTrail.runAsDenied(user, "_action", message, new String[] { role });
assertMsg(logger, Level.INFO, prefix + "[transport] [run_as_denied]\t" + origins +
", principal=[_username], run_as_principal=[running as], action=[_action], request=[MockMessage]");
", principal=[_username], run_as_principal=[running as], roles=[" + role + "], action=[_action], request=[MockMessage]");
// test disabled
CapturingLogger.output(logger.getName(), Level.INFO).clear();
settings = Settings.builder().put(settings).put("xpack.security.audit.logfile.events.exclude", "run_as_denied").build();
auditTrail = new LoggingAuditTrail(settings, clusterService, logger, threadContext);
auditTrail.runAsDenied(user, "_action", message);
auditTrail.runAsDenied(user, "_action", message, new String[] { role });
assertEmptyLog(logger);
}

View File

@ -44,6 +44,7 @@ import org.elasticsearch.xpack.security.authc.AuthenticationService.Authenticato
import org.elasticsearch.xpack.security.authc.Realm.Factory;
import org.elasticsearch.xpack.security.authc.esnative.ReservedRealm;
import org.elasticsearch.xpack.security.authc.support.UsernamePasswordToken;
import org.elasticsearch.xpack.security.authz.permission.Role;
import org.elasticsearch.xpack.security.user.AnonymousUser;
import org.elasticsearch.xpack.security.user.SystemUser;
import org.elasticsearch.xpack.security.user.User;
@ -738,7 +739,7 @@ public class AuthenticationServiceTests extends ESTestCase {
authenticateBlocking(restRequest);
fail("exception should be thrown");
} catch (ElasticsearchException e) {
verify(auditTrail).runAsDenied(any(User.class), eq(restRequest));
verify(auditTrail).runAsDenied(any(User.class), eq(restRequest), eq(Role.EMPTY.names()));
verifyNoMoreInteractions(auditTrail);
}
}
@ -755,7 +756,7 @@ public class AuthenticationServiceTests extends ESTestCase {
authenticateBlocking("_action", message, null);
fail("exception should be thrown");
} catch (ElasticsearchException e) {
verify(auditTrail).runAsDenied(any(User.class), eq("_action"), eq(message));
verify(auditTrail).runAsDenied(any(User.class), eq("_action"), eq(message), eq(Role.EMPTY.names()));
verifyNoMoreInteractions(auditTrail);
}
}

View File

@ -139,6 +139,7 @@ import static org.hamcrest.Matchers.arrayContaining;
import static org.hamcrest.Matchers.containsString;
import static org.hamcrest.Matchers.endsWith;
import static org.hamcrest.Matchers.equalTo;
import static org.hamcrest.Matchers.hasItem;
import static org.hamcrest.Matchers.instanceOf;
import static org.hamcrest.Matchers.is;
import static org.hamcrest.Matchers.notNullValue;
@ -216,10 +217,10 @@ public class AuthorizationServiceTests extends ESTestCase {
// A failure would throw an exception
authorize(createAuthentication(SystemUser.INSTANCE), "indices:monitor/whatever", request);
verify(auditTrail).accessGranted(SystemUser.INSTANCE, "indices:monitor/whatever", request);
verify(auditTrail).accessGranted(SystemUser.INSTANCE, "indices:monitor/whatever", request, new String[] { SystemUser.ROLE_NAME });
authorize(createAuthentication(SystemUser.INSTANCE), "internal:whatever", request);
verify(auditTrail).accessGranted(SystemUser.INSTANCE, "internal:whatever", request);
verify(auditTrail).accessGranted(SystemUser.INSTANCE, "internal:whatever", request, new String[] { SystemUser.ROLE_NAME });
verifyNoMoreInteractions(auditTrail);
}
@ -228,7 +229,7 @@ public class AuthorizationServiceTests extends ESTestCase {
assertThrowsAuthorizationException(
() -> authorize(createAuthentication(SystemUser.INSTANCE), "indices:", request),
"indices:", SystemUser.INSTANCE.principal());
verify(auditTrail).accessDenied(SystemUser.INSTANCE, "indices:", request);
verify(auditTrail).accessDenied(SystemUser.INSTANCE, "indices:", request, new String[] { SystemUser.ROLE_NAME });
verifyNoMoreInteractions(auditTrail);
}
@ -237,7 +238,7 @@ public class AuthorizationServiceTests extends ESTestCase {
assertThrowsAuthorizationException(
() -> authorize(createAuthentication(SystemUser.INSTANCE), "cluster:admin/whatever", request),
"cluster:admin/whatever", SystemUser.INSTANCE.principal());
verify(auditTrail).accessDenied(SystemUser.INSTANCE, "cluster:admin/whatever", request);
verify(auditTrail).accessDenied(SystemUser.INSTANCE, "cluster:admin/whatever", request, new String[] { SystemUser.ROLE_NAME });
verifyNoMoreInteractions(auditTrail);
}
@ -246,7 +247,8 @@ public class AuthorizationServiceTests extends ESTestCase {
assertThrowsAuthorizationException(
() -> authorize(createAuthentication(SystemUser.INSTANCE), "cluster:admin/snapshot/status", request),
"cluster:admin/snapshot/status", SystemUser.INSTANCE.principal());
verify(auditTrail).accessDenied(SystemUser.INSTANCE, "cluster:admin/snapshot/status", request);
verify(auditTrail).accessDenied(SystemUser.INSTANCE, "cluster:admin/snapshot/status", request,
new String[] { SystemUser.ROLE_NAME });
verifyNoMoreInteractions(auditTrail);
}
@ -257,7 +259,7 @@ public class AuthorizationServiceTests extends ESTestCase {
assertThrowsAuthorizationException(
() -> authorize(createAuthentication(user), "indices:a", request),
"indices:a", "test user");
verify(auditTrail).accessDenied(user, "indices:a", request);
verify(auditTrail).accessDenied(user, "indices:a", request, Role.EMPTY.names());
verifyNoMoreInteractions(auditTrail);
}
@ -267,7 +269,7 @@ public class AuthorizationServiceTests extends ESTestCase {
User user = new User("test user");
mockEmptyMetaData();
authorize(createAuthentication(user), SearchAction.NAME, request);
verify(auditTrail).accessGranted(user, SearchAction.NAME, request);
verify(auditTrail).accessGranted(user, SearchAction.NAME, request, Role.EMPTY.names());
verifyNoMoreInteractions(auditTrail);
}
@ -284,7 +286,7 @@ public class AuthorizationServiceTests extends ESTestCase {
assertThrowsAuthorizationException(
() -> authorize(createAuthentication(user), SearchAction.NAME, request),
SearchAction.NAME, "test user");
verify(auditTrail).accessDenied(user, SearchAction.NAME, request);
verify(auditTrail).accessDenied(user, SearchAction.NAME, request, Role.EMPTY.names());
verifyNoMoreInteractions(auditTrail);
}
@ -300,7 +302,7 @@ public class AuthorizationServiceTests extends ESTestCase {
assertThrowsAuthorizationException(
() -> authorize(createAuthentication(user), SearchAction.NAME, request),
SearchAction.NAME, "test user");
verify(auditTrail).accessDenied(user, SearchAction.NAME, request);
verify(auditTrail).accessDenied(user, SearchAction.NAME, request, Role.EMPTY.names());
verifyNoMoreInteractions(auditTrail);
}
@ -316,7 +318,7 @@ public class AuthorizationServiceTests extends ESTestCase {
assertThrowsAuthorizationException(
() -> authorize(createAuthentication(user), DeleteIndexAction.NAME, request),
DeleteIndexAction.NAME, "test user");
verify(auditTrail).accessDenied(user, DeleteIndexAction.NAME, request);
verify(auditTrail).accessDenied(user, DeleteIndexAction.NAME, request, Role.EMPTY.names());
verifyNoMoreInteractions(auditTrail);
}
@ -327,33 +329,35 @@ public class AuthorizationServiceTests extends ESTestCase {
assertThrowsAuthorizationException(
() -> authorize(createAuthentication(user), "indices:a", request),
"indices:a", "test user");
verify(auditTrail).accessDenied(user, "indices:a", request);
verify(auditTrail).accessDenied(user, "indices:a", request, Role.EMPTY.names());
verifyNoMoreInteractions(auditTrail);
}
public void testThatNonIndicesAndNonClusterActionIsDenied() {
TransportRequest request = mock(TransportRequest.class);
User user = new User("test user", "a_all");
roleMap.put("a_all", new RoleDescriptor("a_role", null,
new IndicesPrivileges[] { IndicesPrivileges.builder().indices("a").privileges("all").build() }, null));
RoleDescriptor role = new RoleDescriptor("a_role", null,
new IndicesPrivileges[] { IndicesPrivileges.builder().indices("a").privileges("all").build() }, null);
roleMap.put("a_all", role);
assertThrowsAuthorizationException(
() -> authorize(createAuthentication(user), "whatever", request),
"whatever", "test user");
verify(auditTrail).accessDenied(user, "whatever", request);
verify(auditTrail).accessDenied(user, "whatever", request, new String[] { role.getName() });
verifyNoMoreInteractions(auditTrail);
}
public void testThatRoleWithNoIndicesIsDenied() {
TransportRequest request = new IndicesExistsRequest("a");
User user = new User("test user", "no_indices");
roleMap.put("no_indices", new RoleDescriptor("a_role", null, null, null));
RoleDescriptor role = new RoleDescriptor("a_role", null, null, null);
roleMap.put("no_indices", role);
mockEmptyMetaData();
assertThrowsAuthorizationException(
() -> authorize(createAuthentication(user), "indices:a", request),
"indices:a", "test user");
verify(auditTrail).accessDenied(user, "indices:a", request);
verify(auditTrail).accessDenied(user, "indices:a", request, new String[] { role.getName() });
verifyNoMoreInteractions(auditTrail);
}
@ -362,13 +366,14 @@ public class AuthorizationServiceTests extends ESTestCase {
Tuple<String, TransportRequest> request = randomCompositeRequest();
authorize(createAuthentication(user), request.v1(), request.v2());
verify(auditTrail).accessGranted(user, request.v1(), request.v2());
verify(auditTrail).accessGranted(user, request.v1(), request.v2(), new String[] { ElasticUser.ROLE_NAME });
}
public void testSearchAgainstEmptyCluster() {
RoleDescriptor role = new RoleDescriptor("a_role", null,
new IndicesPrivileges[] { IndicesPrivileges.builder().indices("a").privileges("all").build() }, null);
User user = new User("test user", "a_all");
roleMap.put("a_all", new RoleDescriptor("a_role", null,
new IndicesPrivileges[] { IndicesPrivileges.builder().indices("a").privileges("all").build() }, null));
roleMap.put("a_all", role);
mockEmptyMetaData();
{
@ -379,7 +384,7 @@ public class AuthorizationServiceTests extends ESTestCase {
assertThrowsAuthorizationException(
() -> authorize(createAuthentication(user), SearchAction.NAME, searchRequest),
SearchAction.NAME, "test user");
verify(auditTrail).accessDenied(user, SearchAction.NAME, searchRequest);
verify(auditTrail).accessDenied(user, SearchAction.NAME, searchRequest, new String[] { role.getName() });
verifyNoMoreInteractions(auditTrail);
}
@ -388,7 +393,7 @@ public class AuthorizationServiceTests extends ESTestCase {
SearchRequest searchRequest = new SearchRequest("does_not_exist")
.indicesOptions(IndicesOptions.fromOptions(true, true, true, false));
authorize(createAuthentication(user), SearchAction.NAME, searchRequest);
verify(auditTrail).accessGranted(user, SearchAction.NAME, searchRequest);
verify(auditTrail).accessGranted(user, SearchAction.NAME, searchRequest, new String[] { role.getName() });
IndicesAccessControl indicesAccessControl = threadContext.getTransient(AuthorizationService.INDICES_PERMISSIONS_KEY);
IndicesAccessControl.IndexAccessControl indexAccessControl =
indicesAccessControl.getIndexPermissions(IndicesAndAliasesResolver.NO_INDEX_PLACEHOLDER);
@ -398,49 +403,55 @@ public class AuthorizationServiceTests extends ESTestCase {
}
public void testScrollRelatedRequestsAllowed() {
RoleDescriptor role = new RoleDescriptor("a_role", null,
new IndicesPrivileges[] { IndicesPrivileges.builder().indices("a").privileges("all").build() }, null);
User user = new User("test user", "a_all");
roleMap.put("a_all", new RoleDescriptor("a_role", null,
new IndicesPrivileges[] { IndicesPrivileges.builder().indices("a").privileges("all").build() }, null));
roleMap.put("a_all", role);
mockEmptyMetaData();
ClearScrollRequest clearScrollRequest = new ClearScrollRequest();
authorize(createAuthentication(user), ClearScrollAction.NAME, clearScrollRequest);
verify(auditTrail).accessGranted(user, ClearScrollAction.NAME, clearScrollRequest);
verify(auditTrail).accessGranted(user, ClearScrollAction.NAME, clearScrollRequest, new String[] { role.getName() });
SearchScrollRequest searchScrollRequest = new SearchScrollRequest();
authorize(createAuthentication(user), SearchScrollAction.NAME, searchScrollRequest);
verify(auditTrail).accessGranted(user, SearchScrollAction.NAME, searchScrollRequest);
verify(auditTrail).accessGranted(user, SearchScrollAction.NAME, searchScrollRequest, new String[] { role.getName() });
// We have to use a mock request for other Scroll actions as the actual requests are package private to SearchTransportService
TransportRequest request = mock(TransportRequest.class);
authorize(createAuthentication(user), SearchTransportService.CLEAR_SCROLL_CONTEXTS_ACTION_NAME, request);
verify(auditTrail).accessGranted(user, SearchTransportService.CLEAR_SCROLL_CONTEXTS_ACTION_NAME, request);
verify(auditTrail).accessGranted(user, SearchTransportService.CLEAR_SCROLL_CONTEXTS_ACTION_NAME, request,
new String[] { role.getName() });
authorize(createAuthentication(user), SearchTransportService.FETCH_ID_SCROLL_ACTION_NAME, request);
verify(auditTrail).accessGranted(user, SearchTransportService.FETCH_ID_SCROLL_ACTION_NAME, request);
verify(auditTrail).accessGranted(user, SearchTransportService.FETCH_ID_SCROLL_ACTION_NAME, request,
new String[] { role.getName() });
authorize(createAuthentication(user), SearchTransportService.QUERY_FETCH_SCROLL_ACTION_NAME, request);
verify(auditTrail).accessGranted(user, SearchTransportService.QUERY_FETCH_SCROLL_ACTION_NAME, request);
verify(auditTrail).accessGranted(user, SearchTransportService.QUERY_FETCH_SCROLL_ACTION_NAME, request,
new String[] { role.getName() });
authorize(createAuthentication(user), SearchTransportService.QUERY_SCROLL_ACTION_NAME, request);
verify(auditTrail).accessGranted(user, SearchTransportService.QUERY_SCROLL_ACTION_NAME, request);
verify(auditTrail).accessGranted(user, SearchTransportService.QUERY_SCROLL_ACTION_NAME, request, new String[] { role.getName() });
authorize(createAuthentication(user), SearchTransportService.FREE_CONTEXT_SCROLL_ACTION_NAME, request);
verify(auditTrail).accessGranted(user, SearchTransportService.FREE_CONTEXT_SCROLL_ACTION_NAME, request);
verify(auditTrail).accessGranted(user, SearchTransportService.FREE_CONTEXT_SCROLL_ACTION_NAME, request,
new String[] { role.getName() });
verifyNoMoreInteractions(auditTrail);
}
public void testAuthorizeIndicesFailures() {
TransportRequest request = new GetIndexRequest().indices("b");
ClusterState state = mockEmptyMetaData();
RoleDescriptor role = new RoleDescriptor("a_role", null,
new IndicesPrivileges[] { IndicesPrivileges.builder().indices("a").privileges("all").build() }, null);
User user = new User("test user", "a_all");
roleMap.put("a_all", new RoleDescriptor("a_role", null,
new IndicesPrivileges[] { IndicesPrivileges.builder().indices("a").privileges("all").build() }, null));
roleMap.put("a_all", role);
assertThrowsAuthorizationException(
() -> authorize(createAuthentication(user), "indices:a", request),
"indices:a", "test user");
verify(auditTrail).accessDenied(user, "indices:a", request);
verify(auditTrail).accessDenied(user, "indices:a", request, new String[] { role.getName() });
verifyNoMoreInteractions(auditTrail);
verify(clusterService, times(1)).state();
verify(state, times(1)).metaData();
@ -450,14 +461,15 @@ public class AuthorizationServiceTests extends ESTestCase {
CreateIndexRequest request = new CreateIndexRequest("a");
request.alias(new Alias("a2"));
ClusterState state = mockEmptyMetaData();
RoleDescriptor role = new RoleDescriptor("a_role", null,
new IndicesPrivileges[] { IndicesPrivileges.builder().indices("a").privileges("all").build() }, null);
User user = new User("test user", "a_all");
roleMap.put("a_all", new RoleDescriptor("a_role", null,
new IndicesPrivileges[] { IndicesPrivileges.builder().indices("a").privileges("all").build() }, null));
roleMap.put("a_all", role);
assertThrowsAuthorizationException(
() -> authorize(createAuthentication(user), CreateIndexAction.NAME, request),
IndicesAliasesAction.NAME, "test user");
verify(auditTrail).accessDenied(user, IndicesAliasesAction.NAME, request);
verify(auditTrail).accessDenied(user, IndicesAliasesAction.NAME, request, new String[] { role.getName() });
verifyNoMoreInteractions(auditTrail);
verify(clusterService).state();
verify(state, times(1)).metaData();
@ -467,13 +479,14 @@ public class AuthorizationServiceTests extends ESTestCase {
CreateIndexRequest request = new CreateIndexRequest("a");
request.alias(new Alias("a2"));
ClusterState state = mockEmptyMetaData();
RoleDescriptor role = new RoleDescriptor("a_all", null,
new IndicesPrivileges[] { IndicesPrivileges.builder().indices("a", "a2").privileges("all").build() }, null);
User user = new User("test user", "a_all");
roleMap.put("a_all", new RoleDescriptor("a_all", null,
new IndicesPrivileges[] { IndicesPrivileges.builder().indices("a", "a2").privileges("all").build() }, null));
roleMap.put("a_all", role);
authorize(createAuthentication(user), CreateIndexAction.NAME, request);
verify(auditTrail).accessGranted(user, CreateIndexAction.NAME, request);
verify(auditTrail).accessGranted(user, CreateIndexAction.NAME, request, new String[] { role.getName()});
verifyNoMoreInteractions(auditTrail);
verify(clusterService).state();
verify(state, times(1)).metaData();
@ -487,13 +500,14 @@ public class AuthorizationServiceTests extends ESTestCase {
authorizationService = new AuthorizationService(settings, rolesStore, clusterService, auditTrail,
new DefaultAuthenticationFailureHandler(), threadPool, anonymousUser);
roleMap.put("a_all", new RoleDescriptor("a_all", null,
new IndicesPrivileges[] { IndicesPrivileges.builder().indices("a").privileges("all").build() }, null));
RoleDescriptor role = new RoleDescriptor("a_all", null,
new IndicesPrivileges[] { IndicesPrivileges.builder().indices("a").privileges("all").build() }, null);
roleMap.put("a_all", role);
assertThrowsAuthorizationException(
() -> authorize(createAuthentication(anonymousUser), "indices:a", request),
"indices:a", anonymousUser.principal());
verify(auditTrail).accessDenied(anonymousUser, "indices:a", request);
verify(auditTrail).accessDenied(anonymousUser, "indices:a", request, new String[] { role.getName() });
verifyNoMoreInteractions(auditTrail);
verify(clusterService, times(1)).state();
verify(state, times(1)).metaData();
@ -510,13 +524,14 @@ public class AuthorizationServiceTests extends ESTestCase {
authorizationService = new AuthorizationService(settings, rolesStore, clusterService, auditTrail,
new DefaultAuthenticationFailureHandler(), threadPool, new AnonymousUser(settings));
roleMap.put("a_all", new RoleDescriptor("a_all", null,
new IndicesPrivileges[] { IndicesPrivileges.builder().indices("a").privileges("all").build() }, null));
RoleDescriptor role = new RoleDescriptor("a_all", null,
new IndicesPrivileges[] { IndicesPrivileges.builder().indices("a").privileges("all").build() }, null);
roleMap.put("a_all", role);
ElasticsearchSecurityException securityException = expectThrows(ElasticsearchSecurityException.class,
() -> authorize(createAuthentication(anonymousUser), "indices:a", request));
assertAuthenticationException(securityException, containsString("action [indices:a] requires authentication"));
verify(auditTrail).accessDenied(anonymousUser, "indices:a", request);
verify(auditTrail).accessDenied(anonymousUser, "indices:a", request, new String[] { role.getName() });
verifyNoMoreInteractions(auditTrail);
verify(clusterService, times(1)).state();
verify(state, times(1)).metaData();
@ -526,16 +541,17 @@ public class AuthorizationServiceTests extends ESTestCase {
IndicesOptions options = IndicesOptions.fromOptions(false, false, true, true);
TransportRequest request = new GetIndexRequest().indices("not-an-index-*").indicesOptions(options);
ClusterState state = mockEmptyMetaData();
RoleDescriptor role = new RoleDescriptor("a_all", null,
new IndicesPrivileges[] { IndicesPrivileges.builder().indices("a").privileges("all").build() }, null);
User user = new User("test user", "a_all");
roleMap.put("a_all", new RoleDescriptor("a_all", null,
new IndicesPrivileges[] { IndicesPrivileges.builder().indices("a").privileges("all").build() }, null));
roleMap.put("a_all", role);
final IndexNotFoundException nfe = expectThrows(
IndexNotFoundException.class,
() -> authorize(createAuthentication(user), GetIndexAction.NAME, request));
assertThat(nfe.getIndex(), is(notNullValue()));
assertThat(nfe.getIndex().getName(), is("not-an-index-*"));
verify(auditTrail).accessDenied(user, GetIndexAction.NAME, request);
verify(auditTrail).accessDenied(user, GetIndexAction.NAME, request, new String[] { role.getName() });
verifyNoMoreInteractions(auditTrail);
verify(clusterService).state();
verify(state, times(1)).metaData();
@ -548,7 +564,7 @@ public class AuthorizationServiceTests extends ESTestCase {
assertThrowsAuthorizationExceptionRunAs(
() -> authorize(createAuthentication(user), "indices:a", request),
"indices:a", "test user", "run as me"); // run as [run as me]
verify(auditTrail).runAsDenied(user, "indices:a", request);
verify(auditTrail).runAsDenied(user, "indices:a", request, Role.EMPTY.names());
verifyNoMoreInteractions(auditTrail);
}
@ -561,7 +577,8 @@ public class AuthorizationServiceTests extends ESTestCase {
assertThrowsAuthorizationExceptionRunAs(
() -> authorize(authentication, AuthenticateAction.NAME, request),
AuthenticateAction.NAME, "test user", "run as me"); // run as [run as me]
verify(auditTrail).runAsDenied(user, AuthenticateAction.NAME, request);
verify(auditTrail).runAsDenied(user, AuthenticateAction.NAME, request,
new String[] { ReservedRolesStore.SUPERUSER_ROLE_DESCRIPTOR.getName() });
verifyNoMoreInteractions(auditTrail);
}
@ -569,26 +586,32 @@ public class AuthorizationServiceTests extends ESTestCase {
TransportRequest request = mock(TransportRequest.class);
User user = new User("run as me", new String[] { "doesn't exist" }, new User("test user", "can run as"));
assertNotEquals(user.authenticatedUser(), user);
roleMap.put("can run as", new RoleDescriptor("can run as", null,
RoleDescriptor role = new RoleDescriptor("can run as", null,
new IndicesPrivileges[] { IndicesPrivileges.builder().indices("a").privileges("all").build() },
new String[] { "not the right user" }));
new String[] { "not the right user" });
roleMap.put("can run as", role);
assertThrowsAuthorizationExceptionRunAs(
() -> authorize(createAuthentication(user), "indices:a", request),
"indices:a", "test user", "run as me");
verify(auditTrail).runAsDenied(user, "indices:a", request);
verify(auditTrail).runAsDenied(user, "indices:a", request, new String[] { role.getName() });
verifyNoMoreInteractions(auditTrail);
}
public void testRunAsRequestWithRunAsUserWithoutPermission() {
TransportRequest request = new GetIndexRequest().indices("a");
User user = new User("run as me", new String[] { "b" }, new User("test user", "can run as"));
User authenticatedUser = new User("test user", "can run as");
User user = new User("run as me", new String[] { "b" }, authenticatedUser);
assertNotEquals(user.authenticatedUser(), user);
roleMap.put("can run as", new RoleDescriptor("can run as", null,
RoleDescriptor runAsRole = new RoleDescriptor("can run as", null,
new IndicesPrivileges[] { IndicesPrivileges.builder().indices("a").privileges("all").build() },
new String[] { "run as me" }));
new String[] { "run as me" });
roleMap.put("can run as", runAsRole);
if (randomBoolean()) {
RoleDescriptor bRole = new RoleDescriptor("b", null,
new IndicesPrivileges[] { IndicesPrivileges.builder().indices("b").privileges("all").build() }, null);
boolean indexExists = randomBoolean();
if (indexExists) {
ClusterState state = mock(ClusterState.class);
when(clusterService.state()).thenReturn(state);
when(state.metaData()).thenReturn(MetaData.builder()
@ -596,8 +619,7 @@ public class AuthorizationServiceTests extends ESTestCase {
.settings(Settings.builder().put("index.version.created", Version.CURRENT).build())
.numberOfShards(1).numberOfReplicas(0).build(), true)
.build());
roleMap.put("b", new RoleDescriptor("b", null,
new IndicesPrivileges[] { IndicesPrivileges.builder().indices("b").privileges("all").build() }, null));
roleMap.put("b", bRole);
} else {
mockEmptyMetaData();
}
@ -605,18 +627,24 @@ public class AuthorizationServiceTests extends ESTestCase {
assertThrowsAuthorizationExceptionRunAs(
() -> authorize(createAuthentication(user), "indices:a", request),
"indices:a", "test user", "run as me");
verify(auditTrail).runAsGranted(user, "indices:a", request);
verify(auditTrail).accessDenied(user, "indices:a", request);
verify(auditTrail).runAsGranted(user, "indices:a", request, new String[] { runAsRole.getName() });
if (indexExists) {
verify(auditTrail).accessDenied(user, "indices:a", request, new String[] { bRole.getName() });
} else {
verify(auditTrail).accessDenied(user, "indices:a", request, Role.EMPTY.names());
}
verifyNoMoreInteractions(auditTrail);
}
public void testRunAsRequestWithValidPermissions() {
TransportRequest request = new GetIndexRequest().indices("b");
User user = new User("run as me", new String[] { "b" }, new User("test user", new String[] { "can run as" }));
User authenticatedUser = new User("test user", new String[] { "can run as" });
User user = new User("run as me", new String[] { "b" }, authenticatedUser);
assertNotEquals(user.authenticatedUser(), user);
roleMap.put("can run as", new RoleDescriptor("can run as", null,
RoleDescriptor runAsRole = new RoleDescriptor("can run as", null,
new IndicesPrivileges[] { IndicesPrivileges.builder().indices("a").privileges("all").build() },
new String[] { "run as me" }));
new String[] { "run as me" });
roleMap.put("can run as", runAsRole);
ClusterState state = mock(ClusterState.class);
when(clusterService.state()).thenReturn(state);
when(state.metaData()).thenReturn(MetaData.builder()
@ -624,19 +652,21 @@ public class AuthorizationServiceTests extends ESTestCase {
.settings(Settings.builder().put("index.version.created", Version.CURRENT).build())
.numberOfShards(1).numberOfReplicas(0).build(), true)
.build());
roleMap.put("b", new RoleDescriptor("b", null,
new IndicesPrivileges[] { IndicesPrivileges.builder().indices("b").privileges("all").build() }, null));
RoleDescriptor bRole = new RoleDescriptor("b", null,
new IndicesPrivileges[] { IndicesPrivileges.builder().indices("b").privileges("all").build() }, null);
roleMap.put("b", bRole);
authorize(createAuthentication(user), "indices:a", request);
verify(auditTrail).runAsGranted(user, "indices:a", request);
verify(auditTrail).accessGranted(user, "indices:a", request);
verify(auditTrail).runAsGranted(user, "indices:a", request, new String[] { runAsRole.getName() });
verify(auditTrail).accessGranted(user, "indices:a", request, new String[] { bRole.getName() });
verifyNoMoreInteractions(auditTrail);
}
public void testNonXPackUserCannotExecuteOperationAgainstSecurityIndex() {
RoleDescriptor role = new RoleDescriptor("all access", new String[] { "all" },
new IndicesPrivileges[] { IndicesPrivileges.builder().indices("*").privileges("all").build() }, null);
User user = new User("all_access_user", "all_access");
roleMap.put("all_access", new RoleDescriptor("all access", new String[] { "all" },
new IndicesPrivileges[] { IndicesPrivileges.builder().indices("*").privileges("all").build() }, null));
roleMap.put("all_access", role);
ClusterState state = mock(ClusterState.class);
when(clusterService.state()).thenReturn(state);
when(state.metaData()).thenReturn(MetaData.builder()
@ -666,19 +696,19 @@ public class AuthorizationServiceTests extends ESTestCase {
assertThrowsAuthorizationException(
() -> authorize(createAuthentication(user), action, request),
action, "all_access_user");
verify(auditTrail).accessDenied(user, action, request);
verify(auditTrail).accessDenied(user, action, request, new String[] { role.getName() });
verifyNoMoreInteractions(auditTrail);
}
// we should allow waiting for the health of the index or any index if the user has this permission
ClusterHealthRequest request = new ClusterHealthRequest(SecurityLifecycleService.SECURITY_INDEX_NAME);
authorize(createAuthentication(user), ClusterHealthAction.NAME, request);
verify(auditTrail).accessGranted(user, ClusterHealthAction.NAME, request);
verify(auditTrail).accessGranted(user, ClusterHealthAction.NAME, request, new String[] { role.getName() });
// multiple indices
request = new ClusterHealthRequest(SecurityLifecycleService.SECURITY_INDEX_NAME, "foo", "bar");
authorize(createAuthentication(user), ClusterHealthAction.NAME, request);
verify(auditTrail).accessGranted(user, ClusterHealthAction.NAME, request);
verify(auditTrail).accessGranted(user, ClusterHealthAction.NAME, request, new String[] { role.getName() });
SearchRequest searchRequest = new SearchRequest("_all");
authorize(createAuthentication(user), SearchAction.NAME, searchRequest);
@ -687,9 +717,10 @@ public class AuthorizationServiceTests extends ESTestCase {
}
public void testGrantedNonXPackUserCanExecuteMonitoringOperationsAgainstSecurityIndex() {
RoleDescriptor role = new RoleDescriptor("all access", new String[] { "all" },
new IndicesPrivileges[] { IndicesPrivileges.builder().indices("*").privileges("all").build() }, null);
User user = new User("all_access_user", "all_access");
roleMap.put("all_access", new RoleDescriptor("all access", new String[] { "all" },
new IndicesPrivileges[] { IndicesPrivileges.builder().indices("*").privileges("all").build() }, null));
roleMap.put("all_access", role);
ClusterState state = mock(ClusterState.class);
when(clusterService.state()).thenReturn(state);
when(state.metaData()).thenReturn(MetaData.builder()
@ -713,7 +744,7 @@ public class AuthorizationServiceTests extends ESTestCase {
String action = requestTuple.v1();
TransportRequest request = requestTuple.v2();
authorize(createAuthentication(user), action, request);
verify(auditTrail).accessGranted(user, action, request);
verify(auditTrail).accessGranted(user, action, request, new String[] { role.getName() });
}
}
@ -752,7 +783,7 @@ public class AuthorizationServiceTests extends ESTestCase {
String action = requestTuple.v1();
TransportRequest request = requestTuple.v2();
authorize(createAuthentication(superuser), action, request);
verify(auditTrail).accessGranted(superuser, action, request);
verify(auditTrail).accessGranted(superuser, action, request, superuser.roles());
}
}
@ -770,7 +801,7 @@ public class AuthorizationServiceTests extends ESTestCase {
String action = SearchAction.NAME;
SearchRequest request = new SearchRequest("_all");
authorize(createAuthentication(superuser), action, request);
verify(auditTrail).accessGranted(superuser, action, request);
verify(auditTrail).accessGranted(superuser, action, request, superuser.roles());
assertThat(request.indices(), arrayContaining(".security"));
}
@ -812,7 +843,7 @@ public class AuthorizationServiceTests extends ESTestCase {
PlainActionFuture<Role> rolesFuture = new PlainActionFuture<>();
authorizationService.roles(new User("no role user"), rolesFuture);
final Role roles = rolesFuture.actionGet();
assertThat(roles.name(), containsString("anonymous_user_role"));
assertThat(Arrays.asList(roles.names()), hasItem("anonymous_user_role"));
}
public void testCompositeActionsAreImmediatelyRejected() {
@ -821,10 +852,11 @@ public class AuthorizationServiceTests extends ESTestCase {
String action = compositeRequest.v1();
TransportRequest request = compositeRequest.v2();
User user = new User("test user", "no_indices");
roleMap.put("no_indices", new RoleDescriptor("no_indices", null, null, null));
RoleDescriptor role = new RoleDescriptor("no_indices", null, null, null);
roleMap.put("no_indices", role);
assertThrowsAuthorizationException(
() -> authorize(createAuthentication(user), action, request), action, "test user");
verify(auditTrail).accessDenied(user, action, request);
verify(auditTrail).accessDenied(user, action, request, new String[] { role.getName() });
verifyNoMoreInteractions(auditTrail);
}
@ -834,11 +866,12 @@ public class AuthorizationServiceTests extends ESTestCase {
String action = compositeRequest.v1();
TransportRequest request = compositeRequest.v2();
User user = new User("test user", "role");
roleMap.put("role", new RoleDescriptor("role", null,
RoleDescriptor role = new RoleDescriptor("role", null,
new IndicesPrivileges[] { IndicesPrivileges.builder().indices(randomBoolean() ? "a" : "index").privileges("all").build() },
null));
null);
roleMap.put("role", role);
authorize(createAuthentication(user), action, request);
verify(auditTrail).accessGranted(user, action, request);
verify(auditTrail).accessGranted(user, action, request, new String[] { role.getName() });
verifyNoMoreInteractions(auditTrail);
}
@ -911,18 +944,19 @@ public class AuthorizationServiceTests extends ESTestCase {
final TransportRequest request = new BulkShardRequest(shardId, WriteRequest.RefreshPolicy.IMMEDIATE, items);
User user = new User("user", "my-role");
roleMap.put("my-role", new RoleDescriptor("my-role", null, new IndicesPrivileges[] {
RoleDescriptor role = new RoleDescriptor("my-role", null, new IndicesPrivileges[] {
IndicesPrivileges.builder().indices("concrete-index").privileges("all").build(),
IndicesPrivileges.builder().indices("alias-1").privileges("index").build(),
IndicesPrivileges.builder().indices("alias-2").privileges("delete").build()
}, null));
}, null);
roleMap.put("my-role", role);
mockEmptyMetaData();
authorize(createAuthentication(user), action, request);
verify(auditTrail).accessDenied(user, DeleteAction.NAME, request); // alias-1 delete
verify(auditTrail).accessDenied(user, IndexAction.NAME, request); // alias-2 index
verify(auditTrail).accessGranted(user, action, request); // bulk request is allowed
verify(auditTrail).accessDenied(user, DeleteAction.NAME, request, new String[] { role.getName() }); // alias-1 delete
verify(auditTrail).accessDenied(user, IndexAction.NAME, request, new String[] { role.getName() }); // alias-2 index
verify(auditTrail).accessGranted(user, action, request, new String[] { role.getName() }); // bulk request is allowed
verifyNoMoreInteractions(auditTrail);
}
@ -938,15 +972,17 @@ public class AuthorizationServiceTests extends ESTestCase {
final TransportRequest request = new BulkShardRequest(shardId, WriteRequest.RefreshPolicy.IMMEDIATE, items);
User user = new User("user", "my-role");
roleMap.put("my-role", new RoleDescriptor("my-role", null, new IndicesPrivileges[] {
IndicesPrivileges.builder().indices("datemath-*").privileges("index").build()
}, null));
RoleDescriptor role = new RoleDescriptor("my-role", null,
new IndicesPrivileges[] { IndicesPrivileges.builder().indices("datemath-*").privileges("index").build() }, null);
roleMap.put("my-role", role);
mockEmptyMetaData();
authorize(createAuthentication(user), action, request);
verify(auditTrail, Mockito.times(2)).accessDenied(user, DeleteAction.NAME, request); // both deletes should fail
verify(auditTrail).accessGranted(user, action, request); // bulk request is allowed
verify(auditTrail, Mockito.times(2)).accessDenied(user, DeleteAction.NAME, request, new String[] { role.getName() }); // both
// deletes
// should fail
verify(auditTrail).accessGranted(user, action, request, new String[] { role.getName() }); // bulk request is allowed
verifyNoMoreInteractions(auditTrail);
}
@ -1172,17 +1208,19 @@ public class AuthorizationServiceTests extends ESTestCase {
TransportRequest transportRequest = TransportActionProxy.wrapRequest(node, proxiedRequest);
String action = TransportActionProxy.getProxyAction(SearchTransportService.QUERY_ACTION_NAME);
User user = new User("test user", "no_indices");
roleMap.put("no_indices", new RoleDescriptor("no_indices", null, null, null));
RoleDescriptor role = new RoleDescriptor("no_indices", null, null, null);
roleMap.put("no_indices", role);
assertThrowsAuthorizationException(
() -> authorize(createAuthentication(user), action, transportRequest), action, "test user");
verify(auditTrail).accessDenied(user, action, proxiedRequest);
verify(auditTrail).accessDenied(user, action, proxiedRequest, new String[] { role.getName() });
verifyNoMoreInteractions(auditTrail);
}
public void testProxyRequestAuthenticationGrantedWithAllPrivileges() {
RoleDescriptor role = new RoleDescriptor("a_role", null,
new IndicesPrivileges[] { IndicesPrivileges.builder().indices("a").privileges("all").build() }, null);
User user = new User("test user", "a_all");
roleMap.put("a_all", new RoleDescriptor("a_role", null,
new IndicesPrivileges[] { IndicesPrivileges.builder().indices("a").privileges("all").build() }, null));
roleMap.put("a_all", role);
mockEmptyMetaData();
DiscoveryNode node = new DiscoveryNode("foo", buildNewFakeTransportAddress(), Version.CURRENT);
@ -1190,13 +1228,14 @@ public class AuthorizationServiceTests extends ESTestCase {
TransportRequest transportRequest = TransportActionProxy.wrapRequest(node, clearScrollRequest);
String action = TransportActionProxy.getProxyAction(SearchTransportService.CLEAR_SCROLL_CONTEXTS_ACTION_NAME);
authorize(createAuthentication(user), action, transportRequest);
verify(auditTrail).accessGranted(user, action, clearScrollRequest);
verify(auditTrail).accessGranted(user, action, clearScrollRequest, new String[] { role.getName() });
}
public void testProxyRequestAuthenticationGranted() {
RoleDescriptor role = new RoleDescriptor("a_role", null,
new IndicesPrivileges[] { IndicesPrivileges.builder().indices("a").privileges("read_cross_cluster").build() }, null);
User user = new User("test user", "a_all");
roleMap.put("a_all", new RoleDescriptor("a_role", null,
new IndicesPrivileges[] { IndicesPrivileges.builder().indices("a").privileges("read_cross_cluster").build() }, null));
roleMap.put("a_all", role);
mockEmptyMetaData();
DiscoveryNode node = new DiscoveryNode("foo", buildNewFakeTransportAddress(), Version.CURRENT);
@ -1204,13 +1243,14 @@ public class AuthorizationServiceTests extends ESTestCase {
TransportRequest transportRequest = TransportActionProxy.wrapRequest(node, clearScrollRequest);
String action = TransportActionProxy.getProxyAction(SearchTransportService.CLEAR_SCROLL_CONTEXTS_ACTION_NAME);
authorize(createAuthentication(user), action, transportRequest);
verify(auditTrail).accessGranted(user, action, clearScrollRequest);
verify(auditTrail).accessGranted(user, action, clearScrollRequest, new String[] { role.getName() });
}
public void testProxyRequestAuthenticationDeniedWithReadPrivileges() {
User user = new User("test user", "a_all");
roleMap.put("a_all", new RoleDescriptor("a_role", null,
new IndicesPrivileges[] { IndicesPrivileges.builder().indices("a").privileges("read").build() }, null));
RoleDescriptor role = new RoleDescriptor("a_role", null,
new IndicesPrivileges[] { IndicesPrivileges.builder().indices("a").privileges("read").build() }, null);
roleMap.put("a_all", role);
mockEmptyMetaData();
DiscoveryNode node = new DiscoveryNode("foo", buildNewFakeTransportAddress(), Version.CURRENT);
ClearScrollRequest clearScrollRequest = new ClearScrollRequest();
@ -1218,6 +1258,6 @@ public class AuthorizationServiceTests extends ESTestCase {
String action = TransportActionProxy.getProxyAction(SearchTransportService.CLEAR_SCROLL_CONTEXTS_ACTION_NAME);
assertThrowsAuthorizationException(
() -> authorize(createAuthentication(user), action, transportRequest), action, "test user");
verify(auditTrail).accessDenied(user, action, clearScrollRequest);
verify(auditTrail).accessDenied(user, action, clearScrollRequest, new String[] { role.getName() });
}
}

View File

@ -26,6 +26,7 @@ import org.elasticsearch.xpack.security.user.User;
import static org.elasticsearch.mock.orig.Mockito.verifyNoMoreInteractions;
import static org.elasticsearch.xpack.security.authz.AuthorizationService.ORIGINATING_ACTION_KEY;
import static org.elasticsearch.xpack.security.authz.AuthorizationService.ROLE_NAMES_KEY;
import static org.elasticsearch.xpack.security.authz.SecuritySearchOperationListener.ensureAuthenticatedUserIsSame;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.times;
@ -110,13 +111,13 @@ public class SecuritySearchOperationListenerTests extends ESTestCase {
Authentication authentication = new Authentication(new User("test", "role"), new RealmRef(realmName, type, nodeName), null);
authentication.writeToContext(threadContext);
threadContext.putTransient(ORIGINATING_ACTION_KEY, "action");
threadContext.putTransient(ROLE_NAMES_KEY, authentication.getUser().roles());
final InternalScrollSearchRequest request = new InternalScrollSearchRequest();
SearchContextMissingException expected =
expectThrows(SearchContextMissingException.class, () -> listener.validateSearchContext(testSearchContext, request));
assertEquals(testSearchContext.id(), expected.id());
verify(licenseState, times(3)).isAuthAllowed();
verify(auditTrailService)
.accessDenied(authentication.getUser(), "action", request);
verify(auditTrailService).accessDenied(authentication.getUser(), "action", request, authentication.getUser().roles());
}
// another user running as the original user
@ -144,13 +145,13 @@ public class SecuritySearchOperationListenerTests extends ESTestCase {
new Authentication(new User("authenticated", "runas"), new RealmRef(realmName, type, nodeName), null);
authentication.writeToContext(threadContext);
threadContext.putTransient(ORIGINATING_ACTION_KEY, "action");
threadContext.putTransient(ROLE_NAMES_KEY, authentication.getUser().roles());
final InternalScrollSearchRequest request = new InternalScrollSearchRequest();
SearchContextMissingException expected =
expectThrows(SearchContextMissingException.class, () -> listener.validateSearchContext(testSearchContext, request));
assertEquals(testSearchContext.id(), expected.id());
verify(licenseState, times(5)).isAuthAllowed();
verify(auditTrailService)
.accessDenied(authentication.getUser(), "action", request);
verify(auditTrailService).accessDenied(authentication.getUser(), "action", request, authentication.getUser().roles());
}
}
@ -163,54 +164,55 @@ public class SecuritySearchOperationListenerTests extends ESTestCase {
TransportRequest request = Empty.INSTANCE;
AuditTrailService auditTrail = mock(AuditTrailService.class);
ensureAuthenticatedUserIsSame(original, current, auditTrail, id, action, request);
ensureAuthenticatedUserIsSame(original, current, auditTrail, id, action, request, original.getUser().roles());
verifyZeroInteractions(auditTrail);
// original user being run as
User user = new User(new User("test", "role"), new User("authenticated", "runas"));
current = new Authentication(user, new RealmRef("realm", "file", "node"),
new RealmRef(randomAlphaOfLengthBetween(1, 16), "file", "node"));
ensureAuthenticatedUserIsSame(original, current, auditTrail, id, action, request);
ensureAuthenticatedUserIsSame(original, current, auditTrail, id, action, request, original.getUser().roles());
verifyZeroInteractions(auditTrail);
// both user are run as
current = new Authentication(user, new RealmRef("realm", "file", "node"),
new RealmRef(randomAlphaOfLengthBetween(1, 16), "file", "node"));
Authentication runAs = current;
ensureAuthenticatedUserIsSame(runAs, current, auditTrail, id, action, request);
ensureAuthenticatedUserIsSame(runAs, current, auditTrail, id, action, request, original.getUser().roles());
verifyZeroInteractions(auditTrail);
// different authenticated by type
Authentication differentRealmType =
new Authentication(new User("test", "role"), new RealmRef("realm", randomAlphaOfLength(5), "node"), null);
SearchContextMissingException e = expectThrows(SearchContextMissingException.class,
() -> ensureAuthenticatedUserIsSame(original, differentRealmType, auditTrail, id, action, request));
() -> ensureAuthenticatedUserIsSame(original, differentRealmType, auditTrail, id, action, request,
original.getUser().roles()));
assertEquals(id, e.id());
verify(auditTrail).accessDenied(differentRealmType.getUser(), action, request);
verify(auditTrail).accessDenied(differentRealmType.getUser(), action, request, original.getUser().roles());
// wrong user
Authentication differentUser =
new Authentication(new User("test2", "role"), new RealmRef("realm", "realm", "node"), null);
e = expectThrows(SearchContextMissingException.class,
() -> ensureAuthenticatedUserIsSame(original, differentUser, auditTrail, id, action, request));
() -> ensureAuthenticatedUserIsSame(original, differentUser, auditTrail, id, action, request, original.getUser().roles()));
assertEquals(id, e.id());
verify(auditTrail).accessDenied(differentUser.getUser(), action, request);
verify(auditTrail).accessDenied(differentUser.getUser(), action, request, original.getUser().roles());
// run as different user
Authentication diffRunAs = new Authentication(new User(new User("test2", "role"), new User("authenticated", "runas")),
new RealmRef("realm", "file", "node1"), new RealmRef("realm", "file", "node1"));
e = expectThrows(SearchContextMissingException.class,
() -> ensureAuthenticatedUserIsSame(original, diffRunAs, auditTrail, id, action, request));
() -> ensureAuthenticatedUserIsSame(original, diffRunAs, auditTrail, id, action, request, original.getUser().roles()));
assertEquals(id, e.id());
verify(auditTrail).accessDenied(diffRunAs.getUser(), action, request);
verify(auditTrail).accessDenied(diffRunAs.getUser(), action, request, original.getUser().roles());
// run as different looked up by type
Authentication runAsDiffType = new Authentication(user, new RealmRef("realm", "file", "node"),
new RealmRef(randomAlphaOfLengthBetween(1, 16), randomAlphaOfLengthBetween(5, 12), "node"));
e = expectThrows(SearchContextMissingException.class,
() -> ensureAuthenticatedUserIsSame(runAs, runAsDiffType, auditTrail, id, action, request));
() -> ensureAuthenticatedUserIsSame(runAs, runAsDiffType, auditTrail, id, action, request, original.getUser().roles()));
assertEquals(id, e.id());
verify(auditTrail).accessDenied(runAsDiffType.getUser(), action, request);
verify(auditTrail).accessDenied(runAsDiffType.getUser(), action, request, original.getUser().roles());
}
static class TestScrollSearchContext extends TestSearchContext {

View File

@ -40,7 +40,7 @@ public class PermissionTests extends ESTestCase {
}
public void testBuildEmptyRole() {
Role.Builder permission = Role.builder("some_role");
Role.Builder permission = Role.builder(new String[] { "some_role" });
Role role = permission.build();
assertThat(role, notNullValue());
assertThat(role.cluster(), notNullValue());

View File

@ -205,9 +205,10 @@ public class CompositeRolesStoreTests extends ESTestCase {
verify(nativeRolesStore).getRoleDescriptors(isA(String[].class), any(ActionListener.class));
final int numberOfTimesToCall = scaledRandomIntBetween(0, 32);
final boolean getSuperuserRole = randomBoolean() && roleName.equals(ReservedRolesStore.SUPERUSER_ROLE.name()) == false;
final Set<String> names = getSuperuserRole ? Sets.newHashSet(roleName, ReservedRolesStore.SUPERUSER_ROLE.name()) :
Collections.singleton(roleName);
final boolean getSuperuserRole = randomBoolean()
&& roleName.equals(ReservedRolesStore.SUPERUSER_ROLE_DESCRIPTOR.getName()) == false;
final Set<String> names = getSuperuserRole ? Sets.newHashSet(roleName, ReservedRolesStore.SUPERUSER_ROLE_DESCRIPTOR.getName())
: Collections.singleton(roleName);
for (int i = 0; i < numberOfTimesToCall; i++) {
future = new PlainActionFuture<>();
compositeRolesStore.roles(names, fieldPermissionsCache, future);

View File

@ -71,7 +71,7 @@ public class FileRolesStoreTests extends ESTestCase {
assertNotNull(descriptor);
Role role = Role.builder(descriptor, null).build();
assertThat(role, notNullValue());
assertThat(role.name(), equalTo("role1"));
assertThat(role.names(), equalTo(new String[] { "role1" }));
assertThat(role.cluster(), notNullValue());
assertThat(role.cluster().privilege(), is(ClusterPrivilege.ALL));
assertThat(role.indices(), notNullValue());
@ -99,7 +99,7 @@ public class FileRolesStoreTests extends ESTestCase {
assertNotNull(descriptor);
role = Role.builder(descriptor, null).build();
assertThat(role, notNullValue());
assertThat(role.name(), equalTo("role1.ab"));
assertThat(role.names(), equalTo(new String[] { "role1.ab" }));
assertThat(role.cluster(), notNullValue());
assertThat(role.cluster().privilege(), is(ClusterPrivilege.ALL));
assertThat(role.indices(), notNullValue());
@ -111,7 +111,7 @@ public class FileRolesStoreTests extends ESTestCase {
assertNotNull(descriptor);
role = Role.builder(descriptor, null).build();
assertThat(role, notNullValue());
assertThat(role.name(), equalTo("role2"));
assertThat(role.names(), equalTo(new String[] { "role2" }));
assertThat(role.cluster(), notNullValue());
assertTrue(Operations.sameLanguage(role.cluster().privilege().getAutomaton(), ClusterPrivilege.ALL.getAutomaton()));
assertThat(role.indices(), notNullValue());
@ -122,7 +122,7 @@ public class FileRolesStoreTests extends ESTestCase {
assertNotNull(descriptor);
role = Role.builder(descriptor, null).build();
assertThat(role, notNullValue());
assertThat(role.name(), equalTo("role3"));
assertThat(role.names(), equalTo(new String[] { "role3" }));
assertThat(role.cluster(), notNullValue());
assertThat(role.cluster(), is(ClusterPermission.NONE));
assertThat(role.indices(), notNullValue());
@ -146,7 +146,7 @@ public class FileRolesStoreTests extends ESTestCase {
assertNotNull(descriptor);
role = Role.builder(descriptor, null).build();
assertThat(role, notNullValue());
assertThat(role.name(), equalTo("role_run_as"));
assertThat(role.names(), equalTo(new String[] { "role_run_as" }));
assertThat(role.cluster(), notNullValue());
assertThat(role.cluster(), is(ClusterPermission.NONE));
assertThat(role.indices(), is(IndicesPermission.NONE));
@ -159,7 +159,7 @@ public class FileRolesStoreTests extends ESTestCase {
assertNotNull(descriptor);
role = Role.builder(descriptor, null).build();
assertThat(role, notNullValue());
assertThat(role.name(), equalTo("role_run_as1"));
assertThat(role.names(), equalTo(new String[] { "role_run_as1" }));
assertThat(role.cluster(), notNullValue());
assertThat(role.cluster(), is(ClusterPermission.NONE));
assertThat(role.indices(), is(IndicesPermission.NONE));
@ -172,7 +172,7 @@ public class FileRolesStoreTests extends ESTestCase {
assertNotNull(descriptor);
role = Role.builder(descriptor, null).build();
assertThat(role, notNullValue());
assertThat(role.name(), equalTo("role_fields"));
assertThat(role.names(), equalTo(new String[] { "role_fields" }));
assertThat(role.cluster(), notNullValue());
assertThat(role.cluster(), is(ClusterPermission.NONE));
assertThat(role.runAs(), is(RunAsPermission.NONE));
@ -194,7 +194,7 @@ public class FileRolesStoreTests extends ESTestCase {
assertNotNull(descriptor);
role = Role.builder(descriptor, null).build();
assertThat(role, notNullValue());
assertThat(role.name(), equalTo("role_query"));
assertThat(role.names(), equalTo(new String[] { "role_query" }));
assertThat(role.cluster(), notNullValue());
assertThat(role.cluster(), is(ClusterPermission.NONE));
assertThat(role.runAs(), is(RunAsPermission.NONE));
@ -215,7 +215,7 @@ public class FileRolesStoreTests extends ESTestCase {
assertNotNull(descriptor);
role = Role.builder(descriptor, null).build();
assertThat(role, notNullValue());
assertThat(role.name(), equalTo("role_query_fields"));
assertThat(role.names(), equalTo(new String[] { "role_query_fields" }));
assertThat(role.cluster(), notNullValue());
assertThat(role.cluster(), is(ClusterPermission.NONE));
assertThat(role.runAs(), is(RunAsPermission.NONE));
@ -346,7 +346,7 @@ public class FileRolesStoreTests extends ESTestCase {
assertEquals(1, descriptors.size());
Role role = Role.builder(descriptors.iterator().next(), null).build();
assertThat(role, notNullValue());
assertThat(role.name(), equalTo("role5"));
assertThat(role.names(), equalTo(new String[] { "role5" }));
assertThat(role.cluster().check("cluster:monitor/foo/bar"), is(true));
assertThat(role.cluster().check("cluster:admin/foo/bar"), is(false));
@ -375,7 +375,7 @@ public class FileRolesStoreTests extends ESTestCase {
assertNotNull(descriptor);
Role role = Role.builder(descriptor, null).build();
assertThat(role, notNullValue());
assertThat(role.name(), equalTo("valid_role"));
assertThat(role.names(), equalTo(new String[] { "valid_role" }));
List<String> entries = CapturingLogger.output(logger.getName(), Level.ERROR);
assertThat(entries, hasSize(6));