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:
parent
4262b29188
commit
3ea5a6df91
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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";
|
||||
|
|
|
@ -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());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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) -> {
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -40,6 +40,9 @@
|
|||
"principal": {
|
||||
"type": "keyword"
|
||||
},
|
||||
"roles": {
|
||||
"type": "keyword"
|
||||
},
|
||||
"run_by_principal": {
|
||||
"type": "keyword"
|
||||
},
|
||||
|
|
|
@ -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()]));
|
||||
|
|
|
@ -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));
|
||||
|
||||
|
|
|
@ -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");
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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() });
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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());
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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));
|
||||
|
|
Loading…
Reference in New Issue