Merge branch 'master' into feature/async_rest_client

Original commit: elastic/x-pack-elasticsearch@cb4f022353
This commit is contained in:
javanna 2016-07-22 15:52:44 +02:00 committed by Luca Cavanna
commit 748962e626
73 changed files with 1258 additions and 1878 deletions

View File

@ -145,7 +145,7 @@ public class IndexActionIT extends AbstractWatcherIntegrationTestCase {
assertThat(client().admin().indices().prepareExists("idx").get().isExists(), is(false));
assertThat(docCount(HistoryStore.INDEX_PREFIX + "*", HistoryStore.DOC_TYPE, searchSource()
assertThat(docCount(HistoryStore.INDEX_PREFIX_WITH_TEMPLATE + "*", HistoryStore.DOC_TYPE, searchSource()
.query(matchQuery("result.actions.status", "failure"))), is(1L));
}

View File

@ -158,7 +158,7 @@ public class WatchAckIT extends AbstractWatcherIntegrationTestCase {
assertThat(parsedWatch.status().actionStatus("_a2").ackStatus().state(),
is(ActionStatus.AckStatus.State.AWAITS_SUCCESSFUL_EXECUTION));
long throttledCount = docCount(HistoryStore.INDEX_PREFIX + "*", null,
long throttledCount = docCount(HistoryStore.INDEX_PREFIX_WITH_TEMPLATE + "*", null,
matchQuery(WatchRecord.Field.STATE.getPreferredName(), ExecutionState.THROTTLED.id()));
assertThat(throttledCount, greaterThan(0L));
}
@ -240,7 +240,7 @@ public class WatchAckIT extends AbstractWatcherIntegrationTestCase {
assertThat(parsedWatch.status().actionStatus("_a2").ackStatus().state(),
is(ActionStatus.AckStatus.State.AWAITS_SUCCESSFUL_EXECUTION));
long throttledCount = docCount(HistoryStore.INDEX_PREFIX + "*", null,
long throttledCount = docCount(HistoryStore.INDEX_PREFIX_WITH_TEMPLATE + "*", null,
matchQuery(WatchRecord.Field.STATE.getPreferredName(), ExecutionState.THROTTLED.id()));
assertThat(throttledCount, greaterThan(0L));
}

View File

@ -7,7 +7,7 @@ package org.elasticsearch.example;
import org.elasticsearch.example.realm.CustomAuthenticationFailureHandler;
import org.elasticsearch.example.realm.CustomRealm;
import org.elasticsearch.xpack.security.authc.AuthenticationModule;
import org.elasticsearch.xpack.security.authc.AuthenticationFailureHandler;
import org.elasticsearch.xpack.extensions.XPackExtension;
import org.elasticsearch.xpack.security.authc.Realm;
@ -38,15 +38,16 @@ public class ExampleRealmExtension extends XPackExtension {
return "a very basic implementation of a custom realm to validate it works";
}
public void onModule(AuthenticationModule authenticationModule) {
authenticationModule.setAuthenticationFailureHandler(CustomAuthenticationFailureHandler.class);
}
@Override
public Map<String, Realm.Factory> getRealms() {
return Collections.singletonMap(CustomRealm.TYPE, CustomRealm::new);
}
@Override
public AuthenticationFailureHandler getAuthenticationFailureHandler() {
return new CustomAuthenticationFailureHandler();
}
@Override
public Collection<String> getRestHeaders() {
return Arrays.asList(CustomRealm.USER_HEADER, CustomRealm.PW_HEADER);

View File

@ -235,10 +235,6 @@ thirdPartyAudit.excludes = [
// someone figure out what the x-plugins logic should be
licenseHeaders.enabled = false
forbiddenApisMain {
signaturesURLs += [file('signatures.txt').toURI().toURL()]
}
modifyPom { MavenPom pom ->
pom.withXml { XmlProvider xml ->
// first find if we have dependencies at all, and grab the node

View File

@ -20,7 +20,7 @@ import org.elasticsearch.common.util.concurrent.ThreadContext;
import org.elasticsearch.node.Node;
import org.elasticsearch.threadpool.ThreadPool;
import org.elasticsearch.xpack.security.authc.Authentication;
import org.elasticsearch.xpack.security.authc.InternalAuthenticationService;
import org.elasticsearch.xpack.security.authc.AuthenticationService;
import org.elasticsearch.xpack.security.crypto.CryptoService;
import org.elasticsearch.xpack.security.user.XPackUser;
@ -43,7 +43,7 @@ public class InternalClient extends FilterClient {
public InternalClient(Settings settings, ThreadPool threadPool, Client in, CryptoService cryptoService) {
super(settings, threadPool, in);
this.cryptoService = cryptoService;
this.signUserHeader = InternalAuthenticationService.SIGN_USER_HEADER.get(settings);
this.signUserHeader = AuthenticationService.SIGN_USER_HEADER.get(settings);
this.nodeName = Node.NODE_NAME_SETTING.get(settings);
}

View File

@ -11,7 +11,6 @@ import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
@ -75,8 +74,9 @@ import org.elasticsearch.xpack.security.audit.AuditTrailService;
import org.elasticsearch.xpack.security.audit.index.IndexAuditTrail;
import org.elasticsearch.xpack.security.audit.index.IndexNameResolver;
import org.elasticsearch.xpack.security.audit.logfile.LoggingAuditTrail;
import org.elasticsearch.xpack.security.authc.AuthenticationModule;
import org.elasticsearch.xpack.security.authc.InternalAuthenticationService;
import org.elasticsearch.xpack.security.authc.AuthenticationFailureHandler;
import org.elasticsearch.xpack.security.authc.DefaultAuthenticationFailureHandler;
import org.elasticsearch.xpack.security.authc.AuthenticationService;
import org.elasticsearch.xpack.security.authc.Realm;
import org.elasticsearch.xpack.security.authc.Realms;
import org.elasticsearch.xpack.security.authc.activedirectory.ActiveDirectoryRealm;
@ -89,13 +89,14 @@ import org.elasticsearch.xpack.security.authc.ldap.support.SessionFactory;
import org.elasticsearch.xpack.security.authc.pki.PkiRealm;
import org.elasticsearch.xpack.security.authc.support.SecuredString;
import org.elasticsearch.xpack.security.authc.support.UsernamePasswordToken;
import org.elasticsearch.xpack.security.authz.AuthorizationModule;
import org.elasticsearch.xpack.security.authz.InternalAuthorizationService;
import org.elasticsearch.xpack.security.authz.AuthorizationService;
import org.elasticsearch.xpack.security.authz.accesscontrol.SetSecurityUserProcessor;
import org.elasticsearch.xpack.security.authz.accesscontrol.OptOutQueryCache;
import org.elasticsearch.xpack.security.authz.accesscontrol.SecurityIndexSearcherWrapper;
import org.elasticsearch.xpack.security.authz.store.CompositeRolesStore;
import org.elasticsearch.xpack.security.authz.store.FileRolesStore;
import org.elasticsearch.xpack.security.authz.store.NativeRolesStore;
import org.elasticsearch.xpack.security.authz.store.ReservedRolesStore;
import org.elasticsearch.xpack.security.crypto.CryptoService;
import org.elasticsearch.xpack.security.rest.SecurityRestModule;
import org.elasticsearch.xpack.security.rest.action.RestAuthenticateAction;
@ -184,7 +185,6 @@ public class Security implements ActionPlugin, IngestPlugin {
if (enabled == false) {
return modules;
}
modules.add(new SecurityModule(settings));
modules.add(new SecurityTransportModule(settings));
modules.add(b -> {
// for transport client we still must inject these ssl classes with guice
@ -195,20 +195,16 @@ public class Security implements ActionPlugin, IngestPlugin {
return modules;
}
modules.add(new AuthenticationModule(settings));
modules.add(new AuthorizationModule(settings));
if (enabled == false || auditingEnabled(settings) == false) {
modules.add(b -> {
b.bind(AuditTrailService.class).toProvider(Providers.of(null));
b.bind(AuditTrail.class).toInstance(AuditTrail.NOOP);
});
}
modules.add(b -> XPackPlugin.bindFeatureSet(b, SecurityFeatureSet.class));
if (enabled == false) {
modules.add(b -> {
b.bind(CryptoService.class).toProvider(Providers.of(null));
b.bind(Realms.class).toProvider(Providers.of(null)); // for SecurityFeatureSet
b.bind(CompositeRolesStore.class).toProvider(Providers.of(null)); // for SecurityFeatureSet
b.bind(AuditTrailService.class)
.toInstance(new AuditTrailService(settings, Collections.emptyList(), securityLicenseState));
});
modules.add(new SecurityModule(settings));
modules.add(new SecurityTransportModule(settings));
return modules;
}
@ -221,33 +217,23 @@ public class Security implements ActionPlugin, IngestPlugin {
if (auditingEnabled(settings)) {
b.bind(AuditTrail.class).to(AuditTrailService.class); // interface used by some actions...
}
if (indexAuditLoggingEnabled(settings) == false) {
// TODO: remove this once we can construct SecurityLifecycleService without guice
b.bind(IndexAuditTrail.class).toProvider(Providers.of(null));
}
});
modules.add(new SecurityModule(settings));
modules.add(new SecurityRestModule(settings));
modules.add(new SecurityActionModule(settings));
modules.add(new SecurityTransportModule(settings));
return modules;
}
public Collection<Class<? extends LifecycleComponent>> nodeServices() {
if (enabled == false || transportClientMode == true) {
return Collections.emptyList();
}
List<Class<? extends LifecycleComponent>> list = new ArrayList<>();
list.add(FileRolesStore.class);
return list;
}
public Collection<Object> createComponents(InternalClient client, ThreadPool threadPool, ClusterService clusterService,
ResourceWatcherService resourceWatcherService, List<XPackExtension> extensions) {
if (enabled == false) {
return Collections.emptyList();
}
AnonymousUser.initialize(settings); // TODO: this is sketchy...testing is difficult b/c it is static....
List<Object> components = new ArrayList<>();
final SecurityContext securityContext = new SecurityContext(settings, threadPool, cryptoService);
components.add(securityContext);
final SSLConfiguration.Global globalSslConfig = new SSLConfiguration.Global(settings);
final ClientSSLService clientSSLService = new ClientSSLService(settings, env, globalSslConfig, resourceWatcherService);
@ -278,29 +264,69 @@ public class Security implements ActionPlugin, IngestPlugin {
components.add(realms);
// audit trails construction
IndexAuditTrail indexAuditTrail = null;
Set<AuditTrail> auditTrails = new LinkedHashSet<>();
if (AUDIT_ENABLED_SETTING.get(settings)) {
List<String> outputs = AUDIT_OUTPUTS_SETTING.get(settings);
if (outputs.isEmpty()) {
throw new IllegalArgumentException("Audit logging is enabled but there are zero output types in "
+ AUDIT_ENABLED_SETTING.getKey());
}
Set<AuditTrail> auditTrails = new LinkedHashSet<>();
for (String output : outputs) {
switch (output) {
case LoggingAuditTrail.NAME:
auditTrails.add(new LoggingAuditTrail(settings, clusterService, threadPool));
break;
case IndexAuditTrail.NAME:
IndexAuditTrail indexAuditTrail = new IndexAuditTrail(settings, client, threadPool, clusterService);
indexAuditTrail = new IndexAuditTrail(settings, client, threadPool, clusterService);
auditTrails.add(indexAuditTrail);
components.add(indexAuditTrail); // SecurityLifecycleService needs this....
break;
default:
throw new IllegalArgumentException("Unknown audit trail output [" + output + "]");
}
}
components.add(new AuditTrailService(settings, auditTrails.stream().collect(Collectors.toList()), securityLicenseState));
}
final AuditTrailService auditTrailService =
new AuditTrailService(settings, auditTrails.stream().collect(Collectors.toList()), securityLicenseState);
components.add(auditTrailService);
AuthenticationFailureHandler failureHandler = null;
String extensionName = null;
for (XPackExtension extension : extensions) {
AuthenticationFailureHandler extensionFailureHandler = extension.getAuthenticationFailureHandler();
if (extensionFailureHandler != null && failureHandler != null) {
throw new IllegalStateException("Extensions [" + extensionName +"] and [" + extension.name() + "] " +
"both set an authentication failure handler");
}
failureHandler = extensionFailureHandler;
extensionName = extension.name();
}
if (failureHandler == null) {
logger.debug("Using default authentication failure handler");
failureHandler = new DefaultAuthenticationFailureHandler();
} else {
logger.debug("Using authentication failure handler from extension [" + extensionName + "]");
}
final AuthenticationService authcService = new AuthenticationService(settings, realms, auditTrailService,
cryptoService, failureHandler, threadPool);
components.add(authcService);
final FileRolesStore fileRolesStore = new FileRolesStore(settings, env, resourceWatcherService);
final NativeRolesStore nativeRolesStore = new NativeRolesStore(settings, client, threadPool);
final ReservedRolesStore reservedRolesStore = new ReservedRolesStore(securityContext);
final CompositeRolesStore allRolesStore = new CompositeRolesStore(fileRolesStore, nativeRolesStore, reservedRolesStore);
final AuthorizationService authzService = new AuthorizationService(settings, allRolesStore, clusterService,
auditTrailService, failureHandler, threadPool);
components.add(fileRolesStore); // has lifecycle
components.add(nativeRolesStore); // used by roles actions
components.add(reservedRolesStore); // used by roles actions
components.add(allRolesStore); // for SecurityFeatureSet
components.add(authzService);
components.add(new SecurityLifecycleService(settings, clusterService, threadPool, indexAuditTrail,
nativeUsersStore, nativeRolesStore, client));
return components;
}
@ -359,8 +385,8 @@ public class Security implements ActionPlugin, IngestPlugin {
Realms.addSettings(settingsList);
NativeUsersStore.addSettings(settingsList);
NativeRolesStore.addSettings(settingsList);
InternalAuthenticationService.addSettings(settingsList);
InternalAuthorizationService.addSettings(settingsList);
AuthenticationService.addSettings(settingsList);
AuthorizationService.addSettings(settingsList);
// HTTP settings
SecurityNetty3HttpServerTransport.addSettings(settingsList);

View File

@ -5,110 +5,58 @@
*/
package org.elasticsearch.xpack.security;
import org.elasticsearch.ElasticsearchException;
import org.elasticsearch.common.inject.Inject;
import java.io.IOException;
import org.elasticsearch.common.logging.ESLogger;
import org.elasticsearch.common.logging.Loggers;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.common.util.concurrent.ThreadContext;
import org.elasticsearch.threadpool.ThreadPool;
import org.elasticsearch.xpack.security.authc.Authentication;
import org.elasticsearch.xpack.security.authc.AuthenticationService;
import org.elasticsearch.xpack.security.crypto.CryptoService;
import org.elasticsearch.xpack.security.user.User;
import org.elasticsearch.threadpool.ThreadPool;
import java.io.IOException;
import java.util.concurrent.Callable;
/**
*
* A lightweight utility that can find the current user and authentication information for the local thread.
*/
public interface SecurityContext {
public class SecurityContext {
void executeAs(User user, Runnable runnable);
private final ESLogger logger;
private final ThreadContext threadContext;
private final CryptoService cryptoService;
private final boolean signUserHeader;
<V> V executeAs(User user, Callable<V> callable);
User getUser();
Authentication getAuthentication();
default boolean hasAuthentication() {
return getAuthentication() != null;
/**
* Creates a new security context.
* If cryptoService is null, security is disabled and {@link #getUser()}
* and {@link #getAuthentication()} will always return null.
*/
public SecurityContext(Settings settings, ThreadPool threadPool, CryptoService cryptoService) {
this.logger = Loggers.getLogger(getClass(), settings);
this.threadContext = threadPool.getThreadContext();
this.cryptoService = cryptoService;
this.signUserHeader = AuthenticationService.SIGN_USER_HEADER.get(settings);
}
class Insecure implements SecurityContext {
public static final Insecure INSTANCE = new Insecure();
private Insecure() {
}
@Override
public void executeAs(User user, Runnable runnable) {
runnable.run();
}
@Override
public <V> V executeAs(User user, Callable<V> callable) {
try {
return callable.call();
} catch (Exception e) {
throw new ElasticsearchException(e);
}
}
@Override
public User getUser() {
return null;
}
@Override
public Authentication getAuthentication() {
return null;
}
/** Returns the current user information, or null if the current request has no authentication info. */
public User getUser() {
Authentication authentication = getAuthentication();
return authentication == null ? null : authentication.getUser();
}
class Secure implements SecurityContext {
private final ThreadContext threadContext;
private final AuthenticationService authcService;
@Inject
public Secure(ThreadPool threadPool, AuthenticationService authcService) {
this.threadContext = threadPool.getThreadContext();
this.authcService = authcService;
/** Returns the authentication information, or null if the current request has no authentication info. */
public Authentication getAuthentication() {
if (cryptoService == null) {
return null;
}
public void executeAs(User user, Runnable runnable) {
try (ThreadContext.StoredContext ctx = threadContext.stashContext()) {
setUser(user);
runnable.run();
}
}
public <V> V executeAs(User user, Callable<V> callable) {
try (ThreadContext.StoredContext ctx = threadContext.stashContext()) {
setUser(user);
return callable.call();
} catch (Exception e) {
throw new ElasticsearchException(e);
}
}
@Override
public User getUser() {
Authentication authentication = authcService.getCurrentAuthentication();
return authentication == null ? null : authentication.getUser();
}
@Override
public Authentication getAuthentication() {
return authcService.getCurrentAuthentication();
}
private void setUser(User user) {
try {
authcService.attachUserIfMissing(user);
} catch (IOException | IllegalArgumentException e) {
throw new ElasticsearchException("failed to attach user to request", e);
}
try {
return Authentication.readFromContext(threadContext, cryptoService, signUserHeader);
} catch (IOException e) {
// TODO: this seems bogus, the only way to get an ioexception here is from a corrupt or tampered
// auth header, which should be be audited?
logger.error("failed to read authentication", e);
return null;
}
}
}

View File

@ -18,6 +18,7 @@ import org.elasticsearch.xpack.security.authc.Realm;
import org.elasticsearch.xpack.security.authc.Realms;
import org.elasticsearch.xpack.security.authc.esnative.ReservedRealm;
import org.elasticsearch.xpack.XPackFeatureSet;
import org.elasticsearch.xpack.security.authz.store.CompositeRolesStore;
import org.elasticsearch.xpack.security.authz.store.RolesStore;
import org.elasticsearch.xpack.security.crypto.CryptoService;
import org.elasticsearch.xpack.security.transport.filter.IPFilter;
@ -43,7 +44,7 @@ public class SecurityFeatureSet implements XPackFeatureSet {
@Nullable
private final Realms realms;
@Nullable
private final RolesStore rolesStore;
private final CompositeRolesStore rolesStore;
@Nullable
private final IPFilter ipFilter;
@Nullable
@ -52,8 +53,8 @@ public class SecurityFeatureSet implements XPackFeatureSet {
private final CryptoService cryptoService;
@Inject
public SecurityFeatureSet(Settings settings, @Nullable SecurityLicenseState licenseState,
@Nullable Realms realms, NamedWriteableRegistry namedWriteableRegistry, @Nullable RolesStore rolesStore,
public SecurityFeatureSet(Settings settings, @Nullable SecurityLicenseState licenseState, @Nullable Realms realms,
NamedWriteableRegistry namedWriteableRegistry, @Nullable CompositeRolesStore rolesStore,
@Nullable IPFilter ipFilter, @Nullable AuditTrailService auditTrailService,
@Nullable CryptoService cryptoService) {
this.enabled = Security.enabled(settings);

View File

@ -6,18 +6,17 @@
package org.elasticsearch.xpack.security;
import org.elasticsearch.cluster.ClusterChangedEvent;
import org.elasticsearch.cluster.service.ClusterService;
import org.elasticsearch.cluster.ClusterStateListener;
import org.elasticsearch.cluster.service.ClusterService;
import org.elasticsearch.common.component.AbstractComponent;
import org.elasticsearch.common.component.LifecycleListener;
import org.elasticsearch.common.inject.Inject;
import org.elasticsearch.common.inject.internal.Nullable;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.common.util.concurrent.AbstractRunnable;
import org.elasticsearch.threadpool.ThreadPool;
import org.elasticsearch.xpack.security.audit.index.IndexAuditTrail;
import org.elasticsearch.xpack.security.authc.esnative.NativeUsersStore;
import org.elasticsearch.xpack.security.authz.store.NativeRolesStore;
import org.elasticsearch.threadpool.ThreadPool;
/**
* This class is used to provide a lifecycle for services that is based on the cluster's state
@ -38,7 +37,6 @@ public class SecurityLifecycleService extends AbstractComponent implements Clust
private final NativeUsersStore nativeUserStore;
private final NativeRolesStore nativeRolesStore;
@Inject
public SecurityLifecycleService(Settings settings, ClusterService clusterService, ThreadPool threadPool,
@Nullable IndexAuditTrail indexAuditTrail, NativeUsersStore nativeUserStore,
NativeRolesStore nativeRolesStore, InternalClient client) {

View File

@ -1,38 +0,0 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License;
* you may not use this file except in compliance with the Elastic License.
*/
package org.elasticsearch.xpack.security;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.xpack.XPackPlugin;
import org.elasticsearch.xpack.security.support.AbstractSecurityModule;
/**
*
*/
public class SecurityModule extends AbstractSecurityModule {
public SecurityModule(Settings settings) {
super(settings);
}
@Override
protected void configure(boolean clientMode) {
if (clientMode) {
return;
}
XPackPlugin.bindFeatureSet(binder(), SecurityFeatureSet.class);
if (securityEnabled) {
bind(SecurityContext.Secure.class).asEagerSingleton();
bind(SecurityContext.class).to(SecurityContext.Secure.class);
bind(SecurityLifecycleService.class).asEagerSingleton();
} else {
bind(SecurityContext.class).toInstance(SecurityContext.Insecure.INSTANCE);
}
}
}

View File

@ -22,13 +22,14 @@ import org.elasticsearch.license.plugin.core.LicenseUtils;
import org.elasticsearch.xpack.security.Security;
import org.elasticsearch.xpack.security.SecurityContext;
import org.elasticsearch.xpack.security.action.SecurityActionMapper;
import org.elasticsearch.xpack.security.audit.AuditTrailService;
import org.elasticsearch.xpack.security.authc.Authentication;
import org.elasticsearch.xpack.security.authc.AuthenticationService;
import org.elasticsearch.xpack.security.authz.AuthorizationService;
import org.elasticsearch.xpack.security.user.SystemUser;
import org.elasticsearch.xpack.security.user.User;
import org.elasticsearch.xpack.security.action.interceptor.RequestInterceptor;
import org.elasticsearch.xpack.security.audit.AuditTrail;
import org.elasticsearch.xpack.security.authc.AuthenticationService;
import org.elasticsearch.xpack.security.authz.AuthorizationService;
import org.elasticsearch.xpack.security.authz.AuthorizationUtils;
import org.elasticsearch.xpack.security.authz.privilege.HealthAndStatsPrivilege;
import org.elasticsearch.xpack.security.crypto.CryptoService;
@ -60,7 +61,7 @@ public class SecurityActionFilter extends AbstractComponent implements ActionFil
@Inject
public SecurityActionFilter(Settings settings, AuthenticationService authcService, AuthorizationService authzService,
CryptoService cryptoService, AuditTrail auditTrail, SecurityLicenseState licenseState,
CryptoService cryptoService, AuditTrailService auditTrail, SecurityLicenseState licenseState,
SecurityActionMapper actionMapper, Set<RequestInterceptor> requestInterceptors, ThreadPool threadPool,
SecurityContext securityContext) {
super(settings);
@ -92,7 +93,7 @@ public class SecurityActionFilter extends AbstractComponent implements ActionFil
// only restore the context if it is not empty. This is needed because sometimes a response is sent to the user
// and then a cleanup action is executed (like for search without a scroll)
final ThreadContext.StoredContext original = threadContext.newStoredContext();
final boolean restoreOriginalContext = securityContext.hasAuthentication();
final boolean restoreOriginalContext = securityContext.getAuthentication() != null;
try {
if (licenseState.authenticationAndAuthorizationEnabled()) {
if (AuthorizationUtils.shouldReplaceUserWithSystem(threadContext, action)) {

View File

@ -15,7 +15,7 @@ import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.common.util.concurrent.ThreadContext;
import org.elasticsearch.rest.RestStatus;
import org.elasticsearch.xpack.security.user.User;
import org.elasticsearch.xpack.security.authz.InternalAuthorizationService;
import org.elasticsearch.xpack.security.authz.AuthorizationService;
import org.elasticsearch.xpack.security.authz.accesscontrol.IndicesAccessControl;
import org.elasticsearch.threadpool.ThreadPool;
import org.elasticsearch.transport.TransportRequest;
@ -34,7 +34,7 @@ public class BulkRequestInterceptor extends AbstractComponent implements Request
}
public void intercept(BulkRequest request, User user) {
IndicesAccessControl indicesAccessControl = threadContext.getTransient(InternalAuthorizationService.INDICES_PERMISSIONS_KEY);
IndicesAccessControl indicesAccessControl = threadContext.getTransient(AuthorizationService.INDICES_PERMISSIONS_KEY);
for (IndicesRequest indicesRequest : request.subRequests()) {
for (String index : indicesRequest.indices()) {
IndicesAccessControl.IndexAccessControl indexAccessControl = indicesAccessControl.getIndexPermissions(index);

View File

@ -12,7 +12,7 @@ import org.elasticsearch.common.logging.LoggerMessageFormat;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.common.util.concurrent.ThreadContext;
import org.elasticsearch.xpack.security.user.User;
import org.elasticsearch.xpack.security.authz.InternalAuthorizationService;
import org.elasticsearch.xpack.security.authz.AuthorizationService;
import org.elasticsearch.xpack.security.authz.accesscontrol.IndicesAccessControl;
import java.util.Collections;
@ -42,7 +42,7 @@ public abstract class FieldAndDocumentLevelSecurityRequestInterceptor<Request> e
throw new IllegalArgumentException(LoggerMessageFormat.format("Expected a request of type [{}] or [{}] but got [{}] instead",
CompositeIndicesRequest.class, IndicesRequest.class, request.getClass()));
}
IndicesAccessControl indicesAccessControl = threadContext.getTransient(InternalAuthorizationService.INDICES_PERMISSIONS_KEY);
IndicesAccessControl indicesAccessControl = threadContext.getTransient(AuthorizationService.INDICES_PERMISSIONS_KEY);
for (IndicesRequest indicesRequest : indicesRequests) {
for (String index : indicesRequest.indices()) {
IndicesAccessControl.IndexAccessControl indexAccessControl = indicesAccessControl.getIndexPermissions(index);

View File

@ -18,88 +18,6 @@ import java.net.InetAddress;
*/
public interface AuditTrail {
AuditTrail NOOP = new AuditTrail() {
static final String NAME = "noop";
@Override
public String name() {
return NAME;
}
@Override
public void anonymousAccessDenied(String action, TransportMessage message) {
}
@Override
public void anonymousAccessDenied(RestRequest request) {
}
@Override
public void authenticationFailed(RestRequest request) {
}
@Override
public void authenticationFailed(String action, TransportMessage message) {
}
@Override
public void authenticationFailed(AuthenticationToken token, String action, TransportMessage message) {
}
@Override
public void authenticationFailed(AuthenticationToken token, RestRequest request) {
}
@Override
public void authenticationFailed(String realm, AuthenticationToken token, String action, TransportMessage message) {
}
@Override
public void authenticationFailed(String realm, AuthenticationToken token, RestRequest request) {
}
@Override
public void accessGranted(User user, String action, TransportMessage message) {
}
@Override
public void accessDenied(User user, String action, TransportMessage message) {
}
@Override
public void tamperedRequest(RestRequest request) {
}
@Override
public void tamperedRequest(String action, TransportMessage message) {
}
@Override
public void tamperedRequest(User user, String action, TransportMessage request) {
}
@Override
public void connectionGranted(InetAddress inetAddress, String profile, SecurityIpFilterRule rule) {
}
@Override
public void connectionDenied(InetAddress inetAddress, String profile, SecurityIpFilterRule rule) {
}
@Override
public void runAsGranted(User user, String action, TransportMessage message) {
}
@Override
public void runAsDenied(User user, String action, TransportMessage message) {
}
@Override
public void runAsDenied(User user, RestRequest request) {
}
};
String name();
void anonymousAccessDenied(String action, TransportMessage message);

View File

@ -1,46 +0,0 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License;
* you may not use this file except in compliance with the Elastic License.
*/
package org.elasticsearch.xpack.security.authc;
import org.elasticsearch.common.inject.util.Providers;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.xpack.security.support.AbstractSecurityModule;
import org.elasticsearch.xpack.security.user.AnonymousUser;
/**
*
*/
public class AuthenticationModule extends AbstractSecurityModule.Node {
private Class<? extends AuthenticationFailureHandler> authcFailureHandler = null;
public AuthenticationModule(Settings settings) {
super(settings);
}
@Override
protected void configureNode() {
if (!securityEnabled) {
bind(Realms.class).toProvider(Providers.of(null));
return;
}
AnonymousUser.initialize(settings);
if (authcFailureHandler == null) {
bind(AuthenticationFailureHandler.class).to(DefaultAuthenticationFailureHandler.class).asEagerSingleton();
} else {
bind(AuthenticationFailureHandler.class).to(authcFailureHandler).asEagerSingleton();
}
bind(AuthenticationService.class).to(InternalAuthenticationService.class).asEagerSingleton();
}
/**
* Sets the {@link AuthenticationFailureHandler} to the specified implementation
*/
public void setAuthenticationFailureHandler(Class<? extends AuthenticationFailureHandler> clazz) {
this.authcFailureHandler = clazz;
}
}

View File

@ -5,17 +5,64 @@
*/
package org.elasticsearch.xpack.security.authc;
import java.io.IOException;
import java.util.List;
import org.elasticsearch.ElasticsearchSecurityException;
import org.elasticsearch.common.Nullable;
import org.elasticsearch.common.Strings;
import org.elasticsearch.common.component.AbstractComponent;
import org.elasticsearch.common.settings.Setting;
import org.elasticsearch.common.settings.Setting.Property;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.common.util.concurrent.ThreadContext;
import org.elasticsearch.node.Node;
import org.elasticsearch.rest.RestRequest;
import org.elasticsearch.xpack.security.audit.AuditTrailService;
import org.elasticsearch.xpack.security.authc.Authentication.RealmRef;
import org.elasticsearch.xpack.security.user.AnonymousUser;
import org.elasticsearch.xpack.security.user.User;
import org.elasticsearch.xpack.security.audit.AuditTrail;
import org.elasticsearch.xpack.security.crypto.CryptoService;
import org.elasticsearch.threadpool.ThreadPool;
import org.elasticsearch.transport.TransportMessage;
import java.io.IOException;
import static org.elasticsearch.xpack.security.Security.setting;
/**
* Responsible for authenticating the Users behind requests
* An authentication service that delegates the authentication process to its configured {@link Realm realms}.
* This service also supports request level caching of authenticated users (i.e. once a user authenticated
* successfully, it is set on the request context to avoid subsequent redundant authentication process)
*/
public interface AuthenticationService {
public class AuthenticationService extends AbstractComponent {
public static final Setting<Boolean> SIGN_USER_HEADER =
Setting.boolSetting(setting("authc.sign_user_header"), true, Property.NodeScope);
public static final Setting<Boolean> RUN_AS_ENABLED =
Setting.boolSetting(setting("authc.run_as.enabled"), true, Property.NodeScope);
public static final String RUN_AS_USER_HEADER = "es-security-runas-user";
private final Realms realms;
private final AuditTrail auditTrail;
private final CryptoService cryptoService;
private final AuthenticationFailureHandler failureHandler;
private final ThreadContext threadContext;
private final String nodeName;
private final boolean signUserHeader;
private final boolean runAsEnabled;
public AuthenticationService(Settings settings, Realms realms, AuditTrailService auditTrail, CryptoService cryptoService,
AuthenticationFailureHandler failureHandler, ThreadPool threadPool) {
super(settings);
this.nodeName = Node.NODE_NAME_SETTING.get(settings);
this.realms = realms;
this.auditTrail = auditTrail;
this.cryptoService = cryptoService;
this.failureHandler = failureHandler;
this.threadContext = threadPool.getThreadContext();
this.signUserHeader = SIGN_USER_HEADER.get(settings);
this.runAsEnabled = RUN_AS_ENABLED.get(settings);
}
/**
* Authenticates the user that is associated with the given request. If the user was authenticated successfully (i.e.
@ -28,7 +75,9 @@ public interface AuthenticationService {
* user credentials were found to be invalid
* @throws IOException If an error occurs when reading or writing
*/
Authentication authenticate(RestRequest request) throws IOException, ElasticsearchSecurityException;
public Authentication authenticate(RestRequest request) throws IOException, ElasticsearchSecurityException {
return createAuthenticator(request).authenticate();
}
/**
* Authenticates the user that is associated with the given message. If the user was authenticated successfully (i.e.
@ -47,9 +96,11 @@ public interface AuthenticationService {
*
* @throws ElasticsearchSecurityException If the associated user credentials were found to be invalid or in the
* case where there was no user associated with the request, if the defautl
* token could not be authenticated.
* token could not be authenticated.
*/
Authentication authenticate(String action, TransportMessage message, User fallbackUser) throws IOException;
public Authentication authenticate(String action, TransportMessage message, User fallbackUser) throws IOException {
return createAuthenticator(action, message, fallbackUser).authenticate();
}
/**
* Checks if there's already a user header attached to the given message. If missing, a new header is
@ -57,7 +108,310 @@ public interface AuthenticationService {
*
* @param user The user to be attached if the header is missing
*/
void attachUserIfMissing(User user) throws IOException, IllegalArgumentException;
public void attachUserIfMissing(User user) throws IOException {
Authentication authentication = new Authentication(user, new RealmRef("__attach", "__attach", nodeName), null);
authentication.writeToContextIfMissing(threadContext, cryptoService, signUserHeader);
}
Authentication getCurrentAuthentication();
Authenticator createAuthenticator(RestRequest request) {
return new Authenticator(request);
}
Authenticator createAuthenticator(String action, TransportMessage message, User fallbackUser) {
return new Authenticator(action, message, fallbackUser);
}
class Authenticator {
private final AuditableRequest request;
private final User fallbackUser;
private RealmRef authenticatedBy = null;
private RealmRef lookedupBy = null;
Authenticator(RestRequest request) {
this.request = new Rest(request);
this.fallbackUser = null;
}
Authenticator(String action, TransportMessage message, User fallbackUser) {
this.request = new Transport(action, message);
this.fallbackUser = fallbackUser;
}
Authentication authenticate() throws IOException, IllegalArgumentException {
Authentication existing = getCurrentAuthentication();
if (existing != null) {
return existing;
}
AuthenticationToken token = extractToken();
if (token == null) {
return handleNullToken();
}
User user = authenticateToken(token);
if (user == null) {
throw handleNullUser(token);
}
user = lookupRunAsUserIfNecessary(user, token);
final Authentication authentication = new Authentication(user, authenticatedBy, lookedupBy);
authentication.writeToContext(threadContext, cryptoService, signUserHeader);
return authentication;
}
Authentication getCurrentAuthentication() {
Authentication authentication;
try {
authentication = Authentication.readFromContext(threadContext, cryptoService, signUserHeader);
} catch (Exception e) {
throw request.tamperedRequest();
}
// make sure this isn't a rest request since we don't allow authentication to be read via a HTTP request...
if (authentication != null && request instanceof Rest) {
throw request.tamperedRequest();
}
return authentication;
}
AuthenticationToken extractToken() {
AuthenticationToken token = null;
try {
for (Realm realm : realms) {
token = realm.token(threadContext);
if (token != null) {
logger.trace("realm [{}] resolved authentication token [{}] from [{}]", realm, token.principal(), request);
break;
}
}
} catch (Exception e) {
if (logger.isDebugEnabled()) {
logger.debug("failed to extract token from request: [{}]", e, request);
} else {
logger.warn("failed to extract token from request: [{}]: {}", request, e.getMessage());
}
throw request.exceptionProcessingRequest(e, null);
}
return token;
}
Authentication handleNullToken() throws IOException {
Authentication authentication = null;
if (fallbackUser != null) {
RealmRef authenticatedBy = new RealmRef("__fallback", "__fallback", nodeName);
authentication = new Authentication(fallbackUser, authenticatedBy, null);
} else if (AnonymousUser.enabled()) {
RealmRef authenticatedBy = new RealmRef("__anonymous", "__anonymous", nodeName);
authentication = new Authentication(AnonymousUser.INSTANCE, authenticatedBy, null);
}
if (authentication != null) {
authentication.writeToContext(threadContext, cryptoService, signUserHeader);
return authentication;
}
throw request.anonymousAccessDenied();
}
User authenticateToken(AuthenticationToken token) {
User user = null;
try {
for (Realm realm : realms) {
if (realm.supports(token)) {
user = realm.authenticate(token);
if (user != null) {
authenticatedBy = new RealmRef(realm.name(), realm.type(), nodeName);
break;
}
request.realmAuthenticationFailed(token, realm.name());
}
}
} catch (Exception e) {
logger.debug("authentication failed for principal [{}], [{}] ", e, token.principal(), request);
throw request.exceptionProcessingRequest(e, token);
} finally {
token.clearCredentials();
}
return user;
}
ElasticsearchSecurityException handleNullUser(AuthenticationToken token) {
throw request.authenticationFailed(token);
}
boolean shouldTryToRunAs(User authenticatedUser, AuthenticationToken token) {
if (runAsEnabled == false) {
return false;
}
String runAsUsername = threadContext.getHeader(RUN_AS_USER_HEADER);
if (runAsUsername == null) {
return false;
}
if (runAsUsername.isEmpty()) {
logger.debug("user [{}] attempted to runAs with an empty username", authenticatedUser.principal());
throw request.runAsDenied(new User(authenticatedUser.principal(), authenticatedUser.roles(),
new User(runAsUsername, Strings.EMPTY_ARRAY)), token);
}
return true;
}
User lookupRunAsUserIfNecessary(User authenticatedUser, AuthenticationToken token) {
User user = authenticatedUser;
if (shouldTryToRunAs(user, token) == false) {
return user;
}
final String runAsUsername = threadContext.getHeader(RUN_AS_USER_HEADER);
try {
for (Realm realm : realms) {
if (realm.userLookupSupported()) {
User runAsUser = realm.lookupUser(runAsUsername);
if (runAsUser != null) {
lookedupBy = new RealmRef(realm.name(), realm.type(), nodeName);
user = new User(user.principal(), user.roles(), runAsUser);
return user;
}
}
}
// the requested run as user does not exist, but we don't throw an error here otherwise this could let
// information leak about users in the system... instead we'll just let the authz service fail throw an
// authorization error
user = new User(user.principal(), user.roles(), new User(runAsUsername, Strings.EMPTY_ARRAY));
} catch (Exception e) {
logger.debug("run as failed for principal [{}], [{}], run as username [{}]", e, token.principal(), request, runAsUsername);
throw request.exceptionProcessingRequest(e, token);
}
return user;
}
abstract class AuditableRequest {
abstract void realmAuthenticationFailed(AuthenticationToken token, String realm);
abstract ElasticsearchSecurityException tamperedRequest();
abstract ElasticsearchSecurityException exceptionProcessingRequest(Exception e, @Nullable AuthenticationToken token);
abstract ElasticsearchSecurityException authenticationFailed(AuthenticationToken token);
abstract ElasticsearchSecurityException anonymousAccessDenied();
abstract ElasticsearchSecurityException runAsDenied(User user, AuthenticationToken token);
}
class Transport extends AuditableRequest {
private final String action;
private final TransportMessage message;
Transport(String action, TransportMessage message) {
this.action = action;
this.message = message;
}
@Override
void realmAuthenticationFailed(AuthenticationToken token, String realm) {
auditTrail.authenticationFailed(realm, token, action, message);
}
@Override
ElasticsearchSecurityException tamperedRequest() {
auditTrail.tamperedRequest(action, message);
return new ElasticsearchSecurityException("failed to verify signed authentication information");
}
@Override
ElasticsearchSecurityException exceptionProcessingRequest(Exception e, @Nullable AuthenticationToken token) {
if (token != null) {
auditTrail.authenticationFailed(token, action, message);
} else {
auditTrail.authenticationFailed(action, message);
}
return failureHandler.exceptionProcessingRequest(message, action, e, threadContext);
}
@Override
ElasticsearchSecurityException authenticationFailed(AuthenticationToken token) {
auditTrail.authenticationFailed(token, action, message);
return failureHandler.failedAuthentication(message, token, action, threadContext);
}
@Override
ElasticsearchSecurityException anonymousAccessDenied() {
auditTrail.anonymousAccessDenied(action, message);
return failureHandler.missingToken(message, action, threadContext);
}
@Override
ElasticsearchSecurityException runAsDenied(User user, AuthenticationToken token) {
auditTrail.runAsDenied(user, action, message);
return failureHandler.failedAuthentication(message, token, action, threadContext);
}
public String toString() {
return "transport request action [" + action + "]";
}
}
class Rest extends AuditableRequest {
private final RestRequest request;
Rest(RestRequest request) {
this.request = request;
}
@Override
void realmAuthenticationFailed(AuthenticationToken token, String realm) {
auditTrail.authenticationFailed(realm, token, request);
}
@Override
ElasticsearchSecurityException tamperedRequest() {
auditTrail.tamperedRequest(request);
return new ElasticsearchSecurityException("rest request attempted to inject a user");
}
@Override
ElasticsearchSecurityException exceptionProcessingRequest(Exception e, @Nullable AuthenticationToken token) {
if (token != null) {
auditTrail.authenticationFailed(token, request);
} else {
auditTrail.authenticationFailed(request);
}
return failureHandler.exceptionProcessingRequest(request, e, threadContext);
}
@Override
ElasticsearchSecurityException authenticationFailed(AuthenticationToken token) {
auditTrail.authenticationFailed(token, request);
return failureHandler.failedAuthentication(request, token, threadContext);
}
@Override
ElasticsearchSecurityException anonymousAccessDenied() {
auditTrail.anonymousAccessDenied(request);
return failureHandler.missingToken(request, threadContext);
}
@Override
ElasticsearchSecurityException runAsDenied(User user, AuthenticationToken token) {
auditTrail.runAsDenied(user, request);
return failureHandler.failedAuthentication(request, token, threadContext);
}
public String toString() {
return "rest request uri [" + request.uri() + "]";
}
}
}
public static void addSettings(List<Setting<?>> settings) {
settings.add(SIGN_USER_HEADER);
settings.add(RUN_AS_ENABLED);
}
}

View File

@ -1,397 +0,0 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License;
* you may not use this file except in compliance with the Elastic License.
*/
package org.elasticsearch.xpack.security.authc;
import org.elasticsearch.ElasticsearchSecurityException;
import org.elasticsearch.common.Nullable;
import org.elasticsearch.common.Strings;
import org.elasticsearch.common.component.AbstractComponent;
import org.elasticsearch.common.inject.Inject;
import org.elasticsearch.common.settings.Setting;
import org.elasticsearch.common.settings.Setting.Property;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.common.util.concurrent.ThreadContext;
import org.elasticsearch.rest.RestController;
import org.elasticsearch.node.Node;
import org.elasticsearch.rest.RestRequest;
import org.elasticsearch.xpack.security.authc.Authentication.RealmRef;
import org.elasticsearch.xpack.security.user.AnonymousUser;
import org.elasticsearch.xpack.security.user.User;
import org.elasticsearch.xpack.security.audit.AuditTrail;
import org.elasticsearch.xpack.security.crypto.CryptoService;
import org.elasticsearch.threadpool.ThreadPool;
import org.elasticsearch.transport.TransportMessage;
import java.io.IOException;
import java.util.List;
import static org.elasticsearch.xpack.security.Security.setting;
/**
* An authentication service that delegates the authentication process to its configured {@link Realm realms}.
* This service also supports request level caching of authenticated users (i.e. once a user authenticated
* successfully, it is set on the request context to avoid subsequent redundant authentication process)
*/
public class InternalAuthenticationService extends AbstractComponent implements AuthenticationService {
public static final Setting<Boolean> SIGN_USER_HEADER =
Setting.boolSetting(setting("authc.sign_user_header"), true, Property.NodeScope);
public static final Setting<Boolean> RUN_AS_ENABLED =
Setting.boolSetting(setting("authc.run_as.enabled"), true, Property.NodeScope);
public static final String RUN_AS_USER_HEADER = "es-security-runas-user";
private final Realms realms;
private final AuditTrail auditTrail;
private final CryptoService cryptoService;
private final AuthenticationFailureHandler failureHandler;
private final ThreadContext threadContext;
private final String nodeName;
private final boolean signUserHeader;
private final boolean runAsEnabled;
@Inject
public InternalAuthenticationService(Settings settings, Realms realms, AuditTrail auditTrail, CryptoService cryptoService,
AuthenticationFailureHandler failureHandler, ThreadPool threadPool) {
super(settings);
this.nodeName = Node.NODE_NAME_SETTING.get(settings);
this.realms = realms;
this.auditTrail = auditTrail;
this.cryptoService = cryptoService;
this.failureHandler = failureHandler;
this.threadContext = threadPool.getThreadContext();
this.signUserHeader = SIGN_USER_HEADER.get(settings);
this.runAsEnabled = RUN_AS_ENABLED.get(settings);
}
@Override
public Authentication authenticate(RestRequest request) throws IOException, ElasticsearchSecurityException {
return createAuthenticator(request).authenticate();
}
@Override
public Authentication authenticate(String action, TransportMessage message, User fallbackUser) throws IOException {
return createAuthenticator(action, message, fallbackUser).authenticate();
}
@Override
public void attachUserIfMissing(User user) throws IOException {
Authentication authentication = new Authentication(user, new RealmRef("__attach", "__attach", nodeName), null);
authentication.writeToContextIfMissing(threadContext, cryptoService, signUserHeader);
}
@Override
public Authentication getCurrentAuthentication() {
try {
Authentication authentication = Authentication.readFromContext(threadContext, cryptoService, signUserHeader);
return authentication == null ? null : authentication;
} catch (IOException e) {
logger.error("failed to read authentication", e);
return null;
}
}
Authenticator createAuthenticator(RestRequest request) {
return new Authenticator(request);
}
Authenticator createAuthenticator(String action, TransportMessage message, User fallbackUser) {
return new Authenticator(action, message, fallbackUser);
}
class Authenticator {
private final AuditableRequest request;
private final User fallbackUser;
private RealmRef authenticatedBy = null;
private RealmRef lookedupBy = null;
Authenticator(RestRequest request) {
this.request = new Rest(request);
this.fallbackUser = null;
}
Authenticator(String action, TransportMessage message, User fallbackUser) {
this.request = new Transport(action, message);
this.fallbackUser = fallbackUser;
}
Authentication authenticate() throws IOException, IllegalArgumentException {
Authentication existing = getCurrentAuthentication();
if (existing != null) {
return existing;
}
AuthenticationToken token = extractToken();
if (token == null) {
return handleNullToken();
}
User user = authenticateToken(token);
if (user == null) {
throw handleNullUser(token);
}
user = lookupRunAsUserIfNecessary(user, token);
final Authentication authentication = new Authentication(user, authenticatedBy, lookedupBy);
authentication.writeToContext(threadContext, cryptoService, signUserHeader);
return authentication;
}
Authentication getCurrentAuthentication() {
Authentication authentication;
try {
authentication = Authentication.readFromContext(threadContext, cryptoService, signUserHeader);
} catch (Exception e) {
throw request.tamperedRequest();
}
// make sure this isn't a rest request since we don't allow authentication to be read via a HTTP request...
if (authentication != null && request instanceof Rest) {
throw request.tamperedRequest();
}
return authentication;
}
AuthenticationToken extractToken() {
AuthenticationToken token = null;
try {
for (Realm realm : realms) {
token = realm.token(threadContext);
if (token != null) {
logger.trace("realm [{}] resolved authentication token [{}] from [{}]", realm, token.principal(), request);
break;
}
}
} catch (Exception e) {
if (logger.isDebugEnabled()) {
logger.debug("failed to extract token from request: [{}]", e, request);
} else {
logger.warn("failed to extract token from request: [{}]: {}", request, e.getMessage());
}
throw request.exceptionProcessingRequest(e, null);
}
return token;
}
Authentication handleNullToken() throws IOException {
Authentication authentication = null;
if (fallbackUser != null) {
RealmRef authenticatedBy = new RealmRef("__fallback", "__fallback", nodeName);
authentication = new Authentication(fallbackUser, authenticatedBy, null);
} else if (AnonymousUser.enabled()) {
RealmRef authenticatedBy = new RealmRef("__anonymous", "__anonymous", nodeName);
authentication = new Authentication(AnonymousUser.INSTANCE, authenticatedBy, null);
}
if (authentication != null) {
authentication.writeToContext(threadContext, cryptoService, signUserHeader);
return authentication;
}
throw request.anonymousAccessDenied();
}
User authenticateToken(AuthenticationToken token) {
User user = null;
try {
for (Realm realm : realms) {
if (realm.supports(token)) {
user = realm.authenticate(token);
if (user != null) {
authenticatedBy = new RealmRef(realm.name(), realm.type(), nodeName);
break;
}
request.realmAuthenticationFailed(token, realm.name());
}
}
} catch (Exception e) {
logger.debug("authentication failed for principal [{}], [{}] ", e, token.principal(), request);
throw request.exceptionProcessingRequest(e, token);
} finally {
token.clearCredentials();
}
return user;
}
ElasticsearchSecurityException handleNullUser(AuthenticationToken token) {
throw request.authenticationFailed(token);
}
boolean shouldTryToRunAs(User authenticatedUser, AuthenticationToken token) {
if (runAsEnabled == false) {
return false;
}
String runAsUsername = threadContext.getHeader(RUN_AS_USER_HEADER);
if (runAsUsername == null) {
return false;
}
if (runAsUsername.isEmpty()) {
logger.debug("user [{}] attempted to runAs with an empty username", authenticatedUser.principal());
throw request.runAsDenied(new User(authenticatedUser.principal(), authenticatedUser.roles(),
new User(runAsUsername, Strings.EMPTY_ARRAY)), token);
}
return true;
}
User lookupRunAsUserIfNecessary(User authenticatedUser, AuthenticationToken token) {
User user = authenticatedUser;
if (shouldTryToRunAs(user, token) == false) {
return user;
}
final String runAsUsername = threadContext.getHeader(RUN_AS_USER_HEADER);
try {
for (Realm realm : realms) {
if (realm.userLookupSupported()) {
User runAsUser = realm.lookupUser(runAsUsername);
if (runAsUser != null) {
lookedupBy = new RealmRef(realm.name(), realm.type(), nodeName);
user = new User(user.principal(), user.roles(), runAsUser);
return user;
}
}
}
// the requested run as user does not exist, but we don't throw an error here otherwise this could let
// information leak about users in the system... instead we'll just let the authz service fail throw an
// authorization error
user = new User(user.principal(), user.roles(), new User(runAsUsername, Strings.EMPTY_ARRAY));
} catch (Exception e) {
logger.debug("run as failed for principal [{}], [{}], run as username [{}]", e, token.principal(), request, runAsUsername);
throw request.exceptionProcessingRequest(e, token);
}
return user;
}
abstract class AuditableRequest {
abstract void realmAuthenticationFailed(AuthenticationToken token, String realm);
abstract ElasticsearchSecurityException tamperedRequest();
abstract ElasticsearchSecurityException exceptionProcessingRequest(Exception e, @Nullable AuthenticationToken token);
abstract ElasticsearchSecurityException authenticationFailed(AuthenticationToken token);
abstract ElasticsearchSecurityException anonymousAccessDenied();
abstract ElasticsearchSecurityException runAsDenied(User user, AuthenticationToken token);
}
class Transport extends AuditableRequest {
private final String action;
private final TransportMessage message;
Transport(String action, TransportMessage message) {
this.action = action;
this.message = message;
}
@Override
void realmAuthenticationFailed(AuthenticationToken token, String realm) {
auditTrail.authenticationFailed(realm, token, action, message);
}
@Override
ElasticsearchSecurityException tamperedRequest() {
auditTrail.tamperedRequest(action, message);
return new ElasticsearchSecurityException("failed to verify signed authentication information");
}
@Override
ElasticsearchSecurityException exceptionProcessingRequest(Exception e, @Nullable AuthenticationToken token) {
if (token != null) {
auditTrail.authenticationFailed(token, action, message);
} else {
auditTrail.authenticationFailed(action, message);
}
return failureHandler.exceptionProcessingRequest(message, action, e, threadContext);
}
@Override
ElasticsearchSecurityException authenticationFailed(AuthenticationToken token) {
auditTrail.authenticationFailed(token, action, message);
return failureHandler.failedAuthentication(message, token, action, threadContext);
}
@Override
ElasticsearchSecurityException anonymousAccessDenied() {
auditTrail.anonymousAccessDenied(action, message);
return failureHandler.missingToken(message, action, threadContext);
}
@Override
ElasticsearchSecurityException runAsDenied(User user, AuthenticationToken token) {
auditTrail.runAsDenied(user, action, message);
return failureHandler.failedAuthentication(message, token, action, threadContext);
}
public String toString() {
return "transport request action [" + action + "]";
}
}
class Rest extends AuditableRequest {
private final RestRequest request;
Rest(RestRequest request) {
this.request = request;
}
@Override
void realmAuthenticationFailed(AuthenticationToken token, String realm) {
auditTrail.authenticationFailed(realm, token, request);
}
@Override
ElasticsearchSecurityException tamperedRequest() {
auditTrail.tamperedRequest(request);
return new ElasticsearchSecurityException("rest request attempted to inject a user");
}
@Override
ElasticsearchSecurityException exceptionProcessingRequest(Exception e, @Nullable AuthenticationToken token) {
if (token != null) {
auditTrail.authenticationFailed(token, request);
} else {
auditTrail.authenticationFailed(request);
}
return failureHandler.exceptionProcessingRequest(request, e, threadContext);
}
@Override
ElasticsearchSecurityException authenticationFailed(AuthenticationToken token) {
auditTrail.authenticationFailed(token, request);
return failureHandler.failedAuthentication(request, token, threadContext);
}
@Override
ElasticsearchSecurityException anonymousAccessDenied() {
auditTrail.anonymousAccessDenied(request);
return failureHandler.missingToken(request, threadContext);
}
@Override
ElasticsearchSecurityException runAsDenied(User user, AuthenticationToken token) {
auditTrail.runAsDenied(user, request);
return failureHandler.failedAuthentication(request, token, threadContext);
}
public String toString() {
return "rest request uri [" + request.uri() + "]";
}
}
}
public static void addSettings(List<Setting<?>> settings) {
settings.add(SIGN_USER_HEADER);
settings.add(RUN_AS_ENABLED);
}
}

View File

@ -35,8 +35,6 @@ import org.elasticsearch.common.Nullable;
import org.elasticsearch.common.Strings;
import org.elasticsearch.common.ValidationException;
import org.elasticsearch.common.component.AbstractComponent;
import org.elasticsearch.common.inject.Inject;
import org.elasticsearch.common.inject.Provider;
import org.elasticsearch.common.settings.Setting;
import org.elasticsearch.common.settings.Setting.Property;
import org.elasticsearch.common.settings.Settings;
@ -58,11 +56,11 @@ import org.elasticsearch.xpack.security.action.user.PutUserRequest;
import org.elasticsearch.xpack.security.authc.support.Hasher;
import org.elasticsearch.xpack.security.authc.support.SecuredString;
import org.elasticsearch.xpack.security.client.SecurityClient;
import org.elasticsearch.xpack.security.support.SelfReschedulingRunnable;
import org.elasticsearch.xpack.security.user.SystemUser;
import org.elasticsearch.xpack.security.user.User;
import org.elasticsearch.xpack.security.user.User.Fields;
import org.elasticsearch.threadpool.ThreadPool;
import org.elasticsearch.threadpool.ThreadPool.Cancellable;
import org.elasticsearch.threadpool.ThreadPool.Names;
import java.util.ArrayList;
@ -117,7 +115,7 @@ public class NativeUsersStore extends AbstractComponent implements ClusterStateL
private final InternalClient client;
private final ThreadPool threadPool;
private SelfReschedulingRunnable userPoller;
private Cancellable pollerCancellable;
private int scrollSize;
private TimeValue scrollKeepAlive;
@ -533,8 +531,8 @@ public class NativeUsersStore extends AbstractComponent implements ClusterStateL
} catch (Exception e) {
logger.warn("failed to do initial poll of users", e);
}
userPoller = new SelfReschedulingRunnable(poller, threadPool, POLL_INTERVAL_SETTING.get(settings), Names.GENERIC, logger);
userPoller.start();
TimeValue interval = settings.getAsTime("shield.authc.native.reload.interval", TimeValue.timeValueSeconds(30L));
pollerCancellable = threadPool.scheduleWithFixedDelay(poller, interval, Names.GENERIC);
state.set(State.STARTED);
}
} catch (Exception e) {
@ -546,7 +544,7 @@ public class NativeUsersStore extends AbstractComponent implements ClusterStateL
public void stop() {
if (state.compareAndSet(State.STARTED, State.STOPPING)) {
try {
userPoller.stop();
pollerCancellable.cancel();
} catch (Exception e) {
state.set(State.FAILED);
throw e;

View File

@ -1,42 +0,0 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License;
* you may not use this file except in compliance with the Elastic License.
*/
package org.elasticsearch.xpack.security.authz;
import org.elasticsearch.common.inject.util.Providers;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.xpack.security.authz.store.CompositeRolesStore;
import org.elasticsearch.xpack.security.authz.store.FileRolesStore;
import org.elasticsearch.xpack.security.authz.store.NativeRolesStore;
import org.elasticsearch.xpack.security.authz.store.ReservedRolesStore;
import org.elasticsearch.xpack.security.authz.store.RolesStore;
import org.elasticsearch.xpack.security.support.AbstractSecurityModule;
/**
* Module used to bind various classes necessary for authorization
*/
public class AuthorizationModule extends AbstractSecurityModule.Node {
public AuthorizationModule(Settings settings) {
super(settings);
}
@Override
protected void configureNode() {
if (securityEnabled == false) {
bind(RolesStore.class).toProvider(Providers.of(null));
return;
}
// First the file and native roles stores must be bound...
bind(ReservedRolesStore.class).asEagerSingleton();
bind(FileRolesStore.class).asEagerSingleton();
bind(NativeRolesStore.class).asEagerSingleton();
// Then the composite roles store (which combines both) can be bound
bind(RolesStore.class).to(CompositeRolesStore.class).asEagerSingleton();
bind(AuthorizationService.class).to(InternalAuthorizationService.class).asEagerSingleton();
}
}

View File

@ -5,17 +5,94 @@
*/
package org.elasticsearch.xpack.security.authz;
import org.elasticsearch.ElasticsearchSecurityException;
import org.elasticsearch.xpack.security.authc.Authentication;
import org.elasticsearch.xpack.security.user.User;
import org.elasticsearch.transport.TransportRequest;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.function.Predicate;
import org.elasticsearch.ElasticsearchSecurityException;
import org.elasticsearch.action.CompositeIndicesRequest;
import org.elasticsearch.action.IndicesRequest;
import org.elasticsearch.action.admin.indices.alias.Alias;
import org.elasticsearch.action.admin.indices.create.CreateIndexRequest;
import org.elasticsearch.action.search.ClearScrollAction;
import org.elasticsearch.action.search.SearchScrollAction;
import org.elasticsearch.cluster.ClusterState;
import org.elasticsearch.cluster.metadata.AliasOrIndex;
import org.elasticsearch.cluster.metadata.IndexNameExpressionResolver;
import org.elasticsearch.cluster.metadata.MetaData;
import org.elasticsearch.cluster.service.ClusterService;
import org.elasticsearch.common.Strings;
import org.elasticsearch.common.component.AbstractComponent;
import org.elasticsearch.common.settings.Setting;
import org.elasticsearch.common.settings.Setting.Property;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.common.util.concurrent.ThreadContext;
import org.elasticsearch.common.util.set.Sets;
import org.elasticsearch.search.action.SearchTransportService;
import org.elasticsearch.threadpool.ThreadPool;
import org.elasticsearch.transport.TransportRequest;
import org.elasticsearch.xpack.security.SecurityTemplateService;
import org.elasticsearch.xpack.security.audit.AuditTrail;
import org.elasticsearch.xpack.security.authc.Authentication;
import org.elasticsearch.xpack.security.authc.AuthenticationFailureHandler;
import org.elasticsearch.xpack.security.authz.accesscontrol.IndicesAccessControl;
import org.elasticsearch.xpack.security.authz.indicesresolver.DefaultIndicesAndAliasesResolver;
import org.elasticsearch.xpack.security.authz.indicesresolver.IndicesAndAliasesResolver;
import org.elasticsearch.xpack.security.authz.permission.ClusterPermission;
import org.elasticsearch.xpack.security.authz.permission.DefaultRole;
import org.elasticsearch.xpack.security.authz.permission.GlobalPermission;
import org.elasticsearch.xpack.security.authz.permission.Role;
import org.elasticsearch.xpack.security.authz.permission.RunAsPermission;
import org.elasticsearch.xpack.security.authz.privilege.ClusterPrivilege;
import org.elasticsearch.xpack.security.authz.privilege.IndexPrivilege;
import org.elasticsearch.xpack.security.authz.store.CompositeRolesStore;
import org.elasticsearch.xpack.security.audit.AuditTrailService;
import org.elasticsearch.xpack.security.user.AnonymousUser;
import org.elasticsearch.xpack.security.user.SystemUser;
import org.elasticsearch.xpack.security.user.User;
import org.elasticsearch.xpack.security.user.XPackUser;
import org.elasticsearch.xpack.security.authz.store.RolesStore;
import static org.elasticsearch.xpack.security.Security.setting;
import static org.elasticsearch.xpack.security.support.Exceptions.authorizationError;
/**
*
*/
public interface AuthorizationService {
public class AuthorizationService extends AbstractComponent {
public static final Setting<Boolean> ANONYMOUS_AUTHORIZATION_EXCEPTION_SETTING =
Setting.boolSetting(setting("authc.anonymous.authz_exception"), true, Property.NodeScope);
public static final String INDICES_PERMISSIONS_KEY = "_indices_permissions";
static final String ORIGINATING_ACTION_KEY = "_originating_action_name";
private static final Predicate<String> MONITOR_INDEX_PREDICATE = IndexPrivilege.MONITOR.predicate();
private final ClusterService clusterService;
private final CompositeRolesStore rolesStore;
private final AuditTrailService auditTrail;
private final IndicesAndAliasesResolver[] indicesAndAliasesResolvers;
private final AuthenticationFailureHandler authcFailureHandler;
private final ThreadContext threadContext;
private final boolean anonymousAuthzExceptionEnabled;
public AuthorizationService(Settings settings, CompositeRolesStore rolesStore, ClusterService clusterService,
AuditTrailService auditTrail, AuthenticationFailureHandler authcFailureHandler,
ThreadPool threadPool) {
super(settings);
this.rolesStore = rolesStore;
this.clusterService = clusterService;
this.auditTrail = auditTrail;
this.indicesAndAliasesResolvers = new IndicesAndAliasesResolver[] {
new DefaultIndicesAndAliasesResolver(this, new IndexNameExpressionResolver(settings))
};
this.authcFailureHandler = authcFailureHandler;
this.threadContext = threadPool.getThreadContext();
this.anonymousAuthzExceptionEnabled = ANONYMOUS_AUTHORIZATION_EXCEPTION_SETTING.get(settings);
}
/**
* Returns all indices and aliases the given user is allowed to execute the given action on.
@ -23,7 +100,49 @@ public interface AuthorizationService {
* @param user The user
* @param action The action
*/
List<String> authorizedIndicesAndAliases(User user, String action);
public List<String> authorizedIndicesAndAliases(User user, String action) {
final String[] anonymousRoles = AnonymousUser.enabled() ? AnonymousUser.getRoles() : Strings.EMPTY_ARRAY;
String[] rolesNames = user.roles();
if (rolesNames.length == 0 && anonymousRoles.length == 0) {
return Collections.emptyList();
}
List<Predicate<String>> predicates = new ArrayList<>();
for (String roleName : rolesNames) {
Role role = rolesStore.role(roleName);
if (role != null) {
predicates.add(role.indices().allowedIndicesMatcher(action));
}
}
if (AnonymousUser.is(user) == false) {
for (String roleName : anonymousRoles) {
Role role = rolesStore.role(roleName);
if (role != null) {
predicates.add(role.indices().allowedIndicesMatcher(action));
}
}
}
Predicate<String> predicate = predicates.stream().reduce(s -> false, (p1, p2) -> p1.or(p2));
List<String> indicesAndAliases = new ArrayList<>();
MetaData metaData = clusterService.state().metaData();
// TODO: can this be done smarter? I think there are usually more indices/aliases in the cluster then indices defined a roles?
for (Map.Entry<String, AliasOrIndex> entry : metaData.getAliasAndIndexLookup().entrySet()) {
String aliasOrIndex = entry.getKey();
if (predicate.test(aliasOrIndex)) {
indicesAndAliases.add(aliasOrIndex);
}
}
if (XPackUser.is(user) == false) {
// we should filter out the .security index from wildcards
if (indicesAndAliases.remove(SecurityTemplateService.SECURITY_INDEX_NAME)) {
logger.debug("removed [{}] from user [{}] list of authorized indices",
SecurityTemplateService.SECURITY_INDEX_NAME, user.principal());
}
}
return Collections.unmodifiableList(indicesAndAliases);
}
/**
* Verifies that the given user can execute the given request (and action). If the user doesn't
@ -35,6 +154,226 @@ public interface AuthorizationService {
* @param request The request
* @throws ElasticsearchSecurityException If the given user is no allowed to execute the given request
*/
void authorize(Authentication authentication, String action, TransportRequest request) throws ElasticsearchSecurityException;
public void authorize(Authentication authentication, String action, TransportRequest request) throws ElasticsearchSecurityException {
// prior to doing any authorization lets set the originating action in the context only
setOriginatingAction(action);
// 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.getRunAsUser())) {
if (SystemUser.isAuthorized(action) && SystemUser.is(authentication.getUser())) {
setIndicesAccessControl(IndicesAccessControl.ALLOW_ALL);
grant(authentication, action, request);
return;
}
throw denial(authentication, action, request);
}
// get the roles of the authenticated user, which may be different than the effective
GlobalPermission permission = permission(authentication.getUser().roles());
final boolean isRunAs = authentication.getUser() != authentication.getRunAsUser();
// permission can be null as it might be that the user's role
// is unknown
if (permission == null || permission.isEmpty()) {
if (isRunAs) {
// the request is a run as request so we should call the specific audit event for a denied run as attempt
throw denyRunAs(authentication, action, request);
} else {
throw denial(authentication, action, request);
}
}
// check if the request is a run as request
if (isRunAs) {
// first we must authorize for the RUN_AS action
RunAsPermission runAs = permission.runAs();
if (runAs != null && runAs.check(authentication.getRunAsUser().principal())) {
grantRunAs(authentication, action, request);
permission = permission(authentication.getRunAsUser().roles());
// permission can be null as it might be that the user's role
// is unknown
if (permission == null || permission.isEmpty()) {
throw denial(authentication, action, request);
}
} else {
throw denyRunAs(authentication, action, request);
}
}
// 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();
// we use the effectiveUser for permission checking since we are running as a user!
if (cluster != null && cluster.check(action, request, authentication)) {
setIndicesAccessControl(IndicesAccessControl.ALLOW_ALL);
grant(authentication, action, request);
return;
}
throw denial(authentication, action, request);
}
// 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);
}
// some APIs are indices requests that are not actually associated with indices. For example,
// search scroll request, is categorized under the indices context, but doesn't hold indices names
// (in this case, the security check on the indices was done on the search request that initialized
// the scroll... and we rely on the signed scroll id to provide security over this request).
// so we only check indices if indeed the request is an actual IndicesRequest, if it's not,
// we just grant it if it's a scroll, deny otherwise
if (!(request instanceof IndicesRequest) && !(request instanceof CompositeIndicesRequest)) {
if (isScrollRelatedAction(action)) {
//note that clear scroll shard level actions can originate from a clear scroll all, which doesn't require any
//indices permission as it's categorized under cluster. This is why the scroll check is performed
//even before checking if the user has any indices permission.
grant(authentication, action, request);
return;
}
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);
}
if (permission.indices() == null || permission.indices().isEmpty()) {
throw denial(authentication, action, request);
}
ClusterState clusterState = clusterService.state();
Set<String> indexNames = resolveIndices(authentication, action, request, clusterState);
assert !indexNames.isEmpty() : "every indices request needs to have its indices set thus the resolved indices must not be empty";
MetaData metaData = clusterState.metaData();
IndicesAccessControl indicesAccessControl = permission.authorize(action, indexNames, metaData);
if (!indicesAccessControl.isGranted()) {
throw denial(authentication, action, request);
} else if (indicesAccessControl.getIndexPermissions(SecurityTemplateService.SECURITY_INDEX_NAME) != null
&& indicesAccessControl.getIndexPermissions(SecurityTemplateService.SECURITY_INDEX_NAME).isGranted()
&& XPackUser.is(authentication.getRunAsUser()) == false
&& MONITOR_INDEX_PREDICATE.test(action) == false) {
// only the XPackUser is allowed to work with this index, but we should allow indices monitoring actions through for debugging
// purposes. These monitor requests also sometimes resolve indices concretely and then requests them
// FIXME its not just the XPackUser. We said the elastic user and superusers could access this!
logger.debug("user [{}] attempted to directly perform [{}] against the security index [{}]",
authentication.getRunAsUser().principal(), action, SecurityTemplateService.SECURITY_INDEX_NAME);
throw denial(authentication, action, request);
} else {
setIndicesAccessControl(indicesAccessControl);
}
//if we are creating an index we need to authorize potential aliases created at the same time
if (IndexPrivilege.CREATE_INDEX_MATCHER.test(action)) {
assert request instanceof CreateIndexRequest;
Set<Alias> aliases = ((CreateIndexRequest) request).aliases();
if (!aliases.isEmpty()) {
Set<String> aliasesAndIndices = Sets.newHashSet(indexNames);
for (Alias alias : aliases) {
aliasesAndIndices.add(alias.name());
}
indicesAccessControl = permission.authorize("indices:admin/aliases", aliasesAndIndices, metaData);
if (!indicesAccessControl.isGranted()) {
throw denial(authentication, "indices:admin/aliases", request);
}
// no need to re-add the indicesAccessControl in the context,
// because the create index call doesn't do anything FLS or DLS
}
}
grant(authentication, action, request);
}
private void setIndicesAccessControl(IndicesAccessControl accessControl) {
if (threadContext.getTransient(INDICES_PERMISSIONS_KEY) == null) {
threadContext.putTransient(INDICES_PERMISSIONS_KEY, accessControl);
}
}
private void setOriginatingAction(String action) {
String originatingAction = threadContext.getTransient(ORIGINATING_ACTION_KEY);
if (originatingAction == null) {
threadContext.putTransient(ORIGINATING_ACTION_KEY, action);
}
}
private GlobalPermission permission(String[] roleNames) {
if (roleNames.length == 0) {
return DefaultRole.INSTANCE;
}
if (roleNames.length == 1) {
Role role = rolesStore.role(roleNames[0]);
return role == null ? DefaultRole.INSTANCE : GlobalPermission.Compound.builder().add(DefaultRole.INSTANCE).add(role).build();
}
// we'll take all the roles and combine their associated permissions
GlobalPermission.Compound.Builder roles = GlobalPermission.Compound.builder().add(DefaultRole.INSTANCE);
for (String roleName : roleNames) {
Role role = rolesStore.role(roleName);
if (role != null) {
roles.add(role);
}
}
return roles.build();
}
private Set<String> resolveIndices(Authentication authentication, String action, TransportRequest request, ClusterState clusterState) {
MetaData metaData = clusterState.metaData();
for (IndicesAndAliasesResolver resolver : indicesAndAliasesResolvers) {
if (resolver.requestType().isInstance(request)) {
return resolver.resolve(authentication.getRunAsUser(), action, request, metaData);
}
}
assert false : "we should be able to resolve indices for any known request that requires indices privileges";
throw denial(authentication, action, request);
}
private static boolean isScrollRelatedAction(String action) {
return action.equals(SearchScrollAction.NAME) ||
action.equals(SearchTransportService.FETCH_ID_SCROLL_ACTION_NAME) ||
action.equals(SearchTransportService.QUERY_FETCH_SCROLL_ACTION_NAME) ||
action.equals(SearchTransportService.QUERY_SCROLL_ACTION_NAME) ||
action.equals(SearchTransportService.FREE_CONTEXT_SCROLL_ACTION_NAME) ||
action.equals(ClearScrollAction.NAME) ||
action.equals(SearchTransportService.CLEAR_SCROLL_CONTEXTS_ACTION_NAME);
}
private ElasticsearchSecurityException denial(Authentication authentication, String action, TransportRequest request) {
auditTrail.accessDenied(authentication.getUser(), action, request);
return denialException(authentication, action);
}
private ElasticsearchSecurityException denyRunAs(Authentication authentication, String action, TransportRequest request) {
auditTrail.runAsDenied(authentication.getUser(), action, request);
return denialException(authentication, action);
}
private void grant(Authentication authentication, String action, TransportRequest request) {
auditTrail.accessGranted(authentication.getUser(), action, request);
}
private void grantRunAs(Authentication authentication, String action, TransportRequest request) {
auditTrail.runAsGranted(authentication.getUser(), action, request);
}
private ElasticsearchSecurityException denialException(Authentication authentication, String action) {
final User user = authentication.getUser();
// Special case for anonymous user
if (AnonymousUser.enabled() && AnonymousUser.is(user)) {
if (anonymousAuthzExceptionEnabled == false) {
throw authcFailureHandler.authenticationRequired(action, threadContext);
}
}
// check for run as
if (user != authentication.getRunAsUser()) {
return authorizationError("action [{}] is unauthorized for user [{}] run as [{}]", action, user.principal(),
authentication.getRunAsUser().principal());
}
return authorizationError("action [{}] is unauthorized for user [{}]", action, user.principal());
}
public static void addSettings(List<Setting<?>> settings) {
settings.add(ANONYMOUS_AUTHORIZATION_EXCEPTION_SETTING);
}
}

View File

@ -8,8 +8,6 @@ package org.elasticsearch.xpack.security.authz;
import org.elasticsearch.common.util.concurrent.ThreadContext;
import org.elasticsearch.xpack.security.authc.Authentication;
import org.elasticsearch.xpack.security.user.SystemUser;
import org.elasticsearch.xpack.security.user.User;
import org.elasticsearch.xpack.security.authc.InternalAuthenticationService;
import org.elasticsearch.xpack.security.support.AutomatonPredicate;
import org.elasticsearch.xpack.security.support.Automatons;
@ -52,7 +50,7 @@ public final class AuthorizationUtils {
// we have a internal action being executed by a user that is not the system user, lets verify that there is a
// originating action that is not a internal action
final String originatingAction = threadContext.getTransient(InternalAuthorizationService.ORIGINATING_ACTION_KEY);
final String originatingAction = threadContext.getTransient(AuthorizationService.ORIGINATING_ACTION_KEY);
if (originatingAction != null && isInternalAction(originatingAction) == false) {
return true;
}

View File

@ -1,365 +0,0 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License;
* you may not use this file except in compliance with the Elastic License.
*/
package org.elasticsearch.xpack.security.authz;
import org.elasticsearch.ElasticsearchSecurityException;
import org.elasticsearch.action.CompositeIndicesRequest;
import org.elasticsearch.action.IndicesRequest;
import org.elasticsearch.action.admin.indices.alias.Alias;
import org.elasticsearch.action.admin.indices.create.CreateIndexRequest;
import org.elasticsearch.action.search.ClearScrollAction;
import org.elasticsearch.action.search.SearchScrollAction;
import org.elasticsearch.cluster.metadata.IndexNameExpressionResolver;
import org.elasticsearch.cluster.service.ClusterService;
import org.elasticsearch.cluster.ClusterState;
import org.elasticsearch.cluster.metadata.AliasOrIndex;
import org.elasticsearch.cluster.metadata.MetaData;
import org.elasticsearch.common.Strings;
import org.elasticsearch.common.component.AbstractComponent;
import org.elasticsearch.common.inject.Inject;
import org.elasticsearch.common.settings.Setting;
import org.elasticsearch.common.settings.Setting.Property;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.common.util.concurrent.ThreadContext;
import org.elasticsearch.common.util.set.Sets;
import org.elasticsearch.search.action.SearchTransportService;
import org.elasticsearch.xpack.security.SecurityTemplateService;
import org.elasticsearch.xpack.security.authc.Authentication;
import org.elasticsearch.xpack.security.user.AnonymousUser;
import org.elasticsearch.xpack.security.user.SystemUser;
import org.elasticsearch.xpack.security.user.User;
import org.elasticsearch.xpack.security.user.XPackUser;
import org.elasticsearch.xpack.security.audit.AuditTrail;
import org.elasticsearch.xpack.security.authc.AuthenticationFailureHandler;
import org.elasticsearch.xpack.security.authz.accesscontrol.IndicesAccessControl;
import org.elasticsearch.xpack.security.authz.indicesresolver.DefaultIndicesAndAliasesResolver;
import org.elasticsearch.xpack.security.authz.indicesresolver.IndicesAndAliasesResolver;
import org.elasticsearch.xpack.security.authz.permission.ClusterPermission;
import org.elasticsearch.xpack.security.authz.permission.DefaultRole;
import org.elasticsearch.xpack.security.authz.permission.GlobalPermission;
import org.elasticsearch.xpack.security.authz.permission.Role;
import org.elasticsearch.xpack.security.authz.permission.RunAsPermission;
import org.elasticsearch.xpack.security.authz.privilege.ClusterPrivilege;
import org.elasticsearch.xpack.security.authz.privilege.IndexPrivilege;
import org.elasticsearch.xpack.security.authz.store.RolesStore;
import org.elasticsearch.threadpool.ThreadPool;
import org.elasticsearch.transport.TransportRequest;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.function.Predicate;
import static org.elasticsearch.xpack.security.Security.setting;
import static org.elasticsearch.xpack.security.support.Exceptions.authorizationError;
/**
*
*/
public class InternalAuthorizationService extends AbstractComponent implements AuthorizationService {
public static final Setting<Boolean> ANONYMOUS_AUTHORIZATION_EXCEPTION_SETTING =
Setting.boolSetting(setting("authc.anonymous.authz_exception"), true, Property.NodeScope);
public static final String INDICES_PERMISSIONS_KEY = "_indices_permissions";
static final String ORIGINATING_ACTION_KEY = "_originating_action_name";
private static final Predicate<String> MONITOR_INDEX_PREDICATE = IndexPrivilege.MONITOR.predicate();
private final ClusterService clusterService;
private final RolesStore rolesStore;
private final AuditTrail auditTrail;
private final IndicesAndAliasesResolver[] indicesAndAliasesResolvers;
private final AuthenticationFailureHandler authcFailureHandler;
private final ThreadContext threadContext;
private final boolean anonymousAuthzExceptionEnabled;
@Inject
public InternalAuthorizationService(Settings settings, RolesStore rolesStore, ClusterService clusterService,
AuditTrail auditTrail, AuthenticationFailureHandler authcFailureHandler,
ThreadPool threadPool, IndexNameExpressionResolver nameExpressionResolver) {
super(settings);
this.rolesStore = rolesStore;
this.clusterService = clusterService;
this.auditTrail = auditTrail;
this.indicesAndAliasesResolvers = new IndicesAndAliasesResolver[] {
new DefaultIndicesAndAliasesResolver(this, nameExpressionResolver)
};
this.authcFailureHandler = authcFailureHandler;
this.threadContext = threadPool.getThreadContext();
this.anonymousAuthzExceptionEnabled = ANONYMOUS_AUTHORIZATION_EXCEPTION_SETTING.get(settings);
}
@Override
public List<String> authorizedIndicesAndAliases(User user, String action) {
final String[] anonymousRoles = AnonymousUser.enabled() ? AnonymousUser.getRoles() : Strings.EMPTY_ARRAY;
String[] rolesNames = user.roles();
if (rolesNames.length == 0 && anonymousRoles.length == 0) {
return Collections.emptyList();
}
List<Predicate<String>> predicates = new ArrayList<>();
for (String roleName : rolesNames) {
Role role = rolesStore.role(roleName);
if (role != null) {
predicates.add(role.indices().allowedIndicesMatcher(action));
}
}
if (AnonymousUser.is(user) == false) {
for (String roleName : anonymousRoles) {
Role role = rolesStore.role(roleName);
if (role != null) {
predicates.add(role.indices().allowedIndicesMatcher(action));
}
}
}
Predicate<String> predicate = predicates.stream().reduce(s -> false, (p1, p2) -> p1.or(p2));
List<String> indicesAndAliases = new ArrayList<>();
MetaData metaData = clusterService.state().metaData();
// TODO: can this be done smarter? I think there are usually more indices/aliases in the cluster then indices defined a roles?
for (Map.Entry<String, AliasOrIndex> entry : metaData.getAliasAndIndexLookup().entrySet()) {
String aliasOrIndex = entry.getKey();
if (predicate.test(aliasOrIndex)) {
indicesAndAliases.add(aliasOrIndex);
}
}
if (XPackUser.is(user) == false) {
// we should filter out the .security index from wildcards
if (indicesAndAliases.remove(SecurityTemplateService.SECURITY_INDEX_NAME)) {
logger.debug("removed [{}] from user [{}] list of authorized indices",
SecurityTemplateService.SECURITY_INDEX_NAME, user.principal());
}
}
return Collections.unmodifiableList(indicesAndAliases);
}
@Override
public void authorize(Authentication authentication, String action, TransportRequest request) throws ElasticsearchSecurityException {
// prior to doing any authorization lets set the originating action in the context only
setOriginatingAction(action);
// 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.getRunAsUser())) {
if (SystemUser.isAuthorized(action) && SystemUser.is(authentication.getUser())) {
setIndicesAccessControl(IndicesAccessControl.ALLOW_ALL);
grant(authentication, action, request);
return;
}
throw denial(authentication, action, request);
}
// get the roles of the authenticated user, which may be different than the effective
GlobalPermission permission = permission(authentication.getUser().roles());
final boolean isRunAs = authentication.getUser() != authentication.getRunAsUser();
// permission can be null as it might be that the user's role
// is unknown
if (permission == null || permission.isEmpty()) {
if (isRunAs) {
// the request is a run as request so we should call the specific audit event for a denied run as attempt
throw denyRunAs(authentication, action, request);
} else {
throw denial(authentication, action, request);
}
}
// check if the request is a run as request
if (isRunAs) {
// first we must authorize for the RUN_AS action
RunAsPermission runAs = permission.runAs();
if (runAs != null && runAs.check(authentication.getRunAsUser().principal())) {
grantRunAs(authentication, action, request);
permission = permission(authentication.getRunAsUser().roles());
// permission can be null as it might be that the user's role
// is unknown
if (permission == null || permission.isEmpty()) {
throw denial(authentication, action, request);
}
} else {
throw denyRunAs(authentication, action, request);
}
}
// 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();
// we use the effectiveUser for permission checking since we are running as a user!
if (cluster != null && cluster.check(action, request, authentication)) {
setIndicesAccessControl(IndicesAccessControl.ALLOW_ALL);
grant(authentication, action, request);
return;
}
throw denial(authentication, action, request);
}
// 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);
}
// some APIs are indices requests that are not actually associated with indices. For example,
// search scroll request, is categorized under the indices context, but doesn't hold indices names
// (in this case, the security check on the indices was done on the search request that initialized
// the scroll... and we rely on the signed scroll id to provide security over this request).
// so we only check indices if indeed the request is an actual IndicesRequest, if it's not,
// we just grant it if it's a scroll, deny otherwise
if (!(request instanceof IndicesRequest) && !(request instanceof CompositeIndicesRequest)) {
if (isScrollRelatedAction(action)) {
//note that clear scroll shard level actions can originate from a clear scroll all, which doesn't require any
//indices permission as it's categorized under cluster. This is why the scroll check is performed
//even before checking if the user has any indices permission.
grant(authentication, action, request);
return;
}
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);
}
if (permission.indices() == null || permission.indices().isEmpty()) {
throw denial(authentication, action, request);
}
ClusterState clusterState = clusterService.state();
Set<String> indexNames = resolveIndices(authentication, action, request, clusterState);
assert !indexNames.isEmpty() : "every indices request needs to have its indices set thus the resolved indices must not be empty";
MetaData metaData = clusterState.metaData();
IndicesAccessControl indicesAccessControl = permission.authorize(action, indexNames, metaData);
if (!indicesAccessControl.isGranted()) {
throw denial(authentication, action, request);
} else if (indicesAccessControl.getIndexPermissions(SecurityTemplateService.SECURITY_INDEX_NAME) != null
&& indicesAccessControl.getIndexPermissions(SecurityTemplateService.SECURITY_INDEX_NAME).isGranted()
&& XPackUser.is(authentication.getRunAsUser()) == false
&& MONITOR_INDEX_PREDICATE.test(action) == false) {
// only the XPackUser is allowed to work with this index, but we should allow indices monitoring actions through for debugging
// purposes. These monitor requests also sometimes resolve indices concretely and then requests them
// FIXME its not just the XPackUser. We said the elastic user and superusers could access this!
logger.debug("user [{}] attempted to directly perform [{}] against the security index [{}]",
authentication.getRunAsUser().principal(), action, SecurityTemplateService.SECURITY_INDEX_NAME);
throw denial(authentication, action, request);
} else {
setIndicesAccessControl(indicesAccessControl);
}
//if we are creating an index we need to authorize potential aliases created at the same time
if (IndexPrivilege.CREATE_INDEX_MATCHER.test(action)) {
assert request instanceof CreateIndexRequest;
Set<Alias> aliases = ((CreateIndexRequest) request).aliases();
if (!aliases.isEmpty()) {
Set<String> aliasesAndIndices = Sets.newHashSet(indexNames);
for (Alias alias : aliases) {
aliasesAndIndices.add(alias.name());
}
indicesAccessControl = permission.authorize("indices:admin/aliases", aliasesAndIndices, metaData);
if (!indicesAccessControl.isGranted()) {
throw denial(authentication, "indices:admin/aliases", request);
}
// no need to re-add the indicesAccessControl in the context,
// because the create index call doesn't do anything FLS or DLS
}
}
grant(authentication, action, request);
}
private void setIndicesAccessControl(IndicesAccessControl accessControl) {
if (threadContext.getTransient(INDICES_PERMISSIONS_KEY) == null) {
threadContext.putTransient(INDICES_PERMISSIONS_KEY, accessControl);
}
}
private void setOriginatingAction(String action) {
String originatingAction = threadContext.getTransient(ORIGINATING_ACTION_KEY);
if (originatingAction == null) {
threadContext.putTransient(ORIGINATING_ACTION_KEY, action);
}
}
private GlobalPermission permission(String[] roleNames) {
if (roleNames.length == 0) {
return DefaultRole.INSTANCE;
}
if (roleNames.length == 1) {
Role role = rolesStore.role(roleNames[0]);
return role == null ? DefaultRole.INSTANCE : GlobalPermission.Compound.builder().add(DefaultRole.INSTANCE).add(role).build();
}
// we'll take all the roles and combine their associated permissions
GlobalPermission.Compound.Builder roles = GlobalPermission.Compound.builder().add(DefaultRole.INSTANCE);
for (String roleName : roleNames) {
Role role = rolesStore.role(roleName);
if (role != null) {
roles.add(role);
}
}
return roles.build();
}
private Set<String> resolveIndices(Authentication authentication, String action, TransportRequest request, ClusterState clusterState) {
MetaData metaData = clusterState.metaData();
for (IndicesAndAliasesResolver resolver : indicesAndAliasesResolvers) {
if (resolver.requestType().isInstance(request)) {
return resolver.resolve(authentication.getRunAsUser(), action, request, metaData);
}
}
assert false : "we should be able to resolve indices for any known request that requires indices privileges";
throw denial(authentication, action, request);
}
private static boolean isScrollRelatedAction(String action) {
return action.equals(SearchScrollAction.NAME) ||
action.equals(SearchTransportService.FETCH_ID_SCROLL_ACTION_NAME) ||
action.equals(SearchTransportService.QUERY_FETCH_SCROLL_ACTION_NAME) ||
action.equals(SearchTransportService.QUERY_SCROLL_ACTION_NAME) ||
action.equals(SearchTransportService.FREE_CONTEXT_SCROLL_ACTION_NAME) ||
action.equals(ClearScrollAction.NAME) ||
action.equals(SearchTransportService.CLEAR_SCROLL_CONTEXTS_ACTION_NAME);
}
private ElasticsearchSecurityException denial(Authentication authentication, String action, TransportRequest request) {
auditTrail.accessDenied(authentication.getUser(), action, request);
return denialException(authentication, action);
}
private ElasticsearchSecurityException denyRunAs(Authentication authentication, String action, TransportRequest request) {
auditTrail.runAsDenied(authentication.getUser(), action, request);
return denialException(authentication, action);
}
private void grant(Authentication authentication, String action, TransportRequest request) {
auditTrail.accessGranted(authentication.getUser(), action, request);
}
private void grantRunAs(Authentication authentication, String action, TransportRequest request) {
auditTrail.runAsGranted(authentication.getUser(), action, request);
}
private ElasticsearchSecurityException denialException(Authentication authentication, String action) {
final User user = authentication.getUser();
// Special case for anonymous user
if (AnonymousUser.enabled() && AnonymousUser.is(user)) {
if (anonymousAuthzExceptionEnabled == false) {
throw authcFailureHandler.authenticationRequired(action, threadContext);
}
}
// check for run as
if (user != authentication.getRunAsUser()) {
return authorizationError("action [{}] is unauthorized for user [{}] run as [{}]", action, user.principal(),
authentication.getRunAsUser().principal());
}
return authorizationError("action [{}] is unauthorized for user [{}]", action, user.principal());
}
public static void addSettings(List<Setting<?>> settings) {
settings.add(ANONYMOUS_AUTHORIZATION_EXCEPTION_SETTING);
}
}

View File

@ -14,7 +14,7 @@ import org.elasticsearch.index.IndexSettings;
import org.elasticsearch.index.cache.query.QueryCache;
import org.elasticsearch.indices.IndicesQueryCache;
import org.elasticsearch.search.internal.ShardSearchRequest;
import org.elasticsearch.xpack.security.authz.InternalAuthorizationService;
import org.elasticsearch.xpack.security.authz.AuthorizationService;
import java.util.HashSet;
import java.util.Set;
@ -50,7 +50,7 @@ public final class OptOutQueryCache extends AbstractIndexComponent implements Qu
throw new IllegalStateException("opting out of the query cache. current request can't be found");
}
IndicesAccessControl indicesAccessControl = context.getThreadContext().getTransient(
InternalAuthorizationService.INDICES_PERMISSIONS_KEY);
AuthorizationService.INDICES_PERMISSIONS_KEY);
if (indicesAccessControl == null) {
logger.debug("opting out of the query cache. current request doesn't hold indices permissions");
return weight;

View File

@ -43,7 +43,7 @@ import org.elasticsearch.index.query.QueryShardContext;
import org.elasticsearch.index.shard.IndexSearcherWrapper;
import org.elasticsearch.index.shard.ShardId;
import org.elasticsearch.index.shard.ShardUtils;
import org.elasticsearch.xpack.security.authz.InternalAuthorizationService;
import org.elasticsearch.xpack.security.authz.AuthorizationService;
import org.elasticsearch.xpack.security.authz.accesscontrol.DocumentSubsetReader.DocumentSubsetDirectoryReader;
import org.elasticsearch.xpack.security.SecurityLicenseState;
import org.elasticsearch.xpack.security.support.Exceptions;
@ -263,7 +263,7 @@ public class SecurityIndexSearcherWrapper extends IndexSearcherWrapper {
}
protected IndicesAccessControl getIndicesAccessControl() {
IndicesAccessControl indicesAccessControl = threadContext.getTransient(InternalAuthorizationService.INDICES_PERMISSIONS_KEY);
IndicesAccessControl indicesAccessControl = threadContext.getTransient(AuthorizationService.INDICES_PERMISSIONS_KEY);
if (indicesAccessControl == null) {
throw Exceptions.authorizationError("no indices permissions found");
}

View File

@ -7,9 +7,7 @@ package org.elasticsearch.xpack.security.authz.indicesresolver;
import org.elasticsearch.action.AliasesRequest;
import org.elasticsearch.action.CompositeIndicesRequest;
import org.elasticsearch.action.DocumentRequest;
import org.elasticsearch.action.IndicesRequest;
import org.elasticsearch.action.admin.indices.create.CreateIndexRequest;
import org.elasticsearch.action.admin.indices.mapping.put.PutMappingRequest;
import org.elasticsearch.action.support.IndicesOptions;
import org.elasticsearch.cluster.metadata.AliasOrIndex;
@ -19,8 +17,8 @@ import org.elasticsearch.cluster.metadata.MetaData;
import org.elasticsearch.common.regex.Regex;
import org.elasticsearch.common.util.set.Sets;
import org.elasticsearch.index.IndexNotFoundException;
import org.elasticsearch.xpack.security.user.User;
import org.elasticsearch.xpack.security.authz.AuthorizationService;
import org.elasticsearch.xpack.security.user.User;
import org.elasticsearch.transport.TransportRequest;
import java.util.ArrayList;

View File

@ -21,7 +21,6 @@ public class CompositeRolesStore implements RolesStore {
private final NativeRolesStore nativeRolesStore;
private final ReservedRolesStore reservedRolesStore;
@Inject
public CompositeRolesStore(FileRolesStore fileRolesStore, NativeRolesStore nativeRolesStore, ReservedRolesStore reservedRolesStore) {
this.fileRolesStore = fileRolesStore;
this.nativeRolesStore = nativeRolesStore;

View File

@ -5,31 +5,6 @@
*/
package org.elasticsearch.xpack.security.authz.store;
import com.fasterxml.jackson.dataformat.yaml.snakeyaml.error.YAMLException;
import org.elasticsearch.ElasticsearchException;
import org.elasticsearch.ElasticsearchParseException;
import org.elasticsearch.common.Nullable;
import org.elasticsearch.common.component.AbstractLifecycleComponent;
import org.elasticsearch.common.inject.Inject;
import org.elasticsearch.common.logging.ESLogger;
import org.elasticsearch.common.settings.Setting;
import org.elasticsearch.common.settings.Setting.Property;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.common.xcontent.XContentParser;
import org.elasticsearch.common.xcontent.yaml.YamlXContent;
import org.elasticsearch.env.Environment;
import org.elasticsearch.xpack.security.Security;
import org.elasticsearch.xpack.security.authc.support.RefreshListener;
import org.elasticsearch.xpack.security.authz.RoleDescriptor;
import org.elasticsearch.xpack.security.authz.permission.IndicesPermission.Group;
import org.elasticsearch.xpack.security.authz.permission.Role;
import org.elasticsearch.xpack.security.support.NoOpLogger;
import org.elasticsearch.xpack.security.support.Validation;
import org.elasticsearch.watcher.FileChangesListener;
import org.elasticsearch.watcher.FileWatcher;
import org.elasticsearch.watcher.ResourceWatcherService;
import org.elasticsearch.xpack.XPackPlugin;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
@ -41,6 +16,30 @@ import java.util.Map;
import java.util.Set;
import java.util.regex.Pattern;
import com.fasterxml.jackson.dataformat.yaml.snakeyaml.error.YAMLException;
import org.elasticsearch.ElasticsearchException;
import org.elasticsearch.ElasticsearchParseException;
import org.elasticsearch.common.Nullable;
import org.elasticsearch.common.component.AbstractLifecycleComponent;
import org.elasticsearch.common.logging.ESLogger;
import org.elasticsearch.common.settings.Setting;
import org.elasticsearch.common.settings.Setting.Property;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.common.xcontent.XContentParser;
import org.elasticsearch.common.xcontent.yaml.YamlXContent;
import org.elasticsearch.env.Environment;
import org.elasticsearch.watcher.FileChangesListener;
import org.elasticsearch.watcher.FileWatcher;
import org.elasticsearch.watcher.ResourceWatcherService;
import org.elasticsearch.xpack.XPackPlugin;
import org.elasticsearch.xpack.security.Security;
import org.elasticsearch.xpack.security.authc.support.RefreshListener;
import org.elasticsearch.xpack.security.authz.RoleDescriptor;
import org.elasticsearch.xpack.security.authz.permission.IndicesPermission.Group;
import org.elasticsearch.xpack.security.authz.permission.Role;
import org.elasticsearch.xpack.security.support.NoOpLogger;
import org.elasticsearch.xpack.security.support.Validation;
import static java.util.Collections.emptyMap;
import static java.util.Collections.emptySet;
import static java.util.Collections.unmodifiableMap;
@ -59,7 +58,6 @@ public class FileRolesStore extends AbstractLifecycleComponent implements RolesS
private volatile Map<String, Role> permissions;
@Inject
public FileRolesStore(Settings settings, Environment env, ResourceWatcherService watcherService) {
this(settings, env, watcherService, RefreshListener.NOOP);
}

View File

@ -5,6 +5,21 @@
*/
package org.elasticsearch.xpack.security.authz.store;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicReference;
import java.util.function.BiFunction;
import java.util.function.Function;
import org.elasticsearch.ElasticsearchException;
import org.elasticsearch.action.ActionListener;
import org.elasticsearch.action.LatchedActionListener;
@ -29,8 +44,6 @@ import org.elasticsearch.cluster.ClusterStateListener;
import org.elasticsearch.common.Nullable;
import org.elasticsearch.common.bytes.BytesReference;
import org.elasticsearch.common.component.AbstractComponent;
import org.elasticsearch.common.inject.Inject;
import org.elasticsearch.common.inject.Provider;
import org.elasticsearch.common.settings.Setting;
import org.elasticsearch.common.settings.Setting.Property;
import org.elasticsearch.common.settings.Settings;
@ -43,6 +56,8 @@ import org.elasticsearch.index.get.GetResult;
import org.elasticsearch.index.query.QueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.search.SearchHit;
import org.elasticsearch.threadpool.ThreadPool;
import org.elasticsearch.threadpool.ThreadPool.Names;
import org.elasticsearch.xpack.security.InternalClient;
import org.elasticsearch.xpack.security.SecurityTemplateService;
import org.elasticsearch.xpack.security.action.role.ClearRolesCacheRequest;
@ -53,24 +68,7 @@ import org.elasticsearch.xpack.security.authz.RoleDescriptor;
import org.elasticsearch.xpack.security.authz.permission.IndicesPermission.Group;
import org.elasticsearch.xpack.security.authz.permission.Role;
import org.elasticsearch.xpack.security.client.SecurityClient;
import org.elasticsearch.xpack.security.support.SelfReschedulingRunnable;
import org.elasticsearch.threadpool.ThreadPool;
import org.elasticsearch.threadpool.ThreadPool.Names;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicReference;
import java.util.function.BiFunction;
import java.util.function.Function;
import org.elasticsearch.threadpool.ThreadPool.Cancellable;
import static org.elasticsearch.common.xcontent.XContentFactory.jsonBuilder;
import static org.elasticsearch.xpack.security.Security.setting;
@ -113,11 +111,10 @@ public class NativeRolesStore extends AbstractComponent implements RolesStore, C
private SecurityClient securityClient;
private int scrollSize;
private TimeValue scrollKeepAlive;
private SelfReschedulingRunnable rolesPoller;
private Cancellable pollerCancellable;
private volatile boolean securityIndexExists = false;
@Inject
public NativeRolesStore(Settings settings, InternalClient client, ThreadPool threadPool) {
super(settings);
this.client = client;
@ -160,8 +157,7 @@ public class NativeRolesStore extends AbstractComponent implements RolesStore, C
logger.warn("failed to perform initial poll of roles index [{}]. scheduling again in [{}]", e,
SecurityTemplateService.SECURITY_INDEX_NAME, pollInterval);
}
rolesPoller = new SelfReschedulingRunnable(poller, threadPool, pollInterval, Names.GENERIC, logger);
rolesPoller.start();
pollerCancellable = threadPool.scheduleWithFixedDelay(poller, pollInterval, Names.GENERIC);
state.set(State.STARTED);
}
} catch (Exception e) {
@ -173,7 +169,7 @@ public class NativeRolesStore extends AbstractComponent implements RolesStore, C
public void stop() {
if (state.compareAndSet(State.STARTED, State.STOPPING)) {
try {
rolesPoller.stop();
pollerCancellable.cancel();
} finally {
state.set(State.STOPPED);
}

View File

@ -5,7 +5,12 @@
*/
package org.elasticsearch.xpack.security.authz.store;
import org.elasticsearch.common.inject.Inject;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.Map;
import java.util.Set;
import org.elasticsearch.common.util.set.Sets;
import org.elasticsearch.xpack.security.SecurityContext;
import org.elasticsearch.xpack.security.authz.RoleDescriptor;
@ -17,12 +22,6 @@ import org.elasticsearch.xpack.security.authz.permission.TransportClientRole;
import org.elasticsearch.xpack.security.user.KibanaUser;
import org.elasticsearch.xpack.security.user.SystemUser;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.Map;
import java.util.Set;
/**
*
*/
@ -30,7 +29,6 @@ public class ReservedRolesStore implements RolesStore {
private final SecurityContext securityContext;
@Inject
public ReservedRolesStore(SecurityContext securityContext) {
this.securityContext = securityContext;
}

View File

@ -1,76 +0,0 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License;
* you may not use this file except in compliance with the Elastic License.
*/
package org.elasticsearch.xpack.security.support;
import org.elasticsearch.common.logging.ESLogger;
import org.elasticsearch.common.unit.TimeValue;
import org.elasticsearch.common.util.concurrent.AbstractRunnable;
import org.elasticsearch.common.util.concurrent.FutureUtils;
import org.elasticsearch.threadpool.ThreadPool;
import java.util.concurrent.ScheduledFuture;
public class SelfReschedulingRunnable extends AbstractRunnable {
private final AbstractRunnable runnable;
private final ThreadPool threadPool;
private final TimeValue interval;
private final String executorName;
private final ESLogger logger;
private ScheduledFuture<?> scheduledFuture = null;
private volatile boolean run = false;
public SelfReschedulingRunnable(AbstractRunnable runnable, ThreadPool threadPool, TimeValue interval, String executorName,
ESLogger logger) {
this.runnable = runnable;
this.threadPool = threadPool;
this.interval = interval;
this.executorName = executorName;
this.logger = logger;
}
public synchronized void start() {
if (run != false || scheduledFuture != null) {
throw new IllegalStateException("start should not be called again before calling stop");
}
run = true;
scheduledFuture = threadPool.schedule(interval, executorName, this);
}
@Override
public synchronized void onAfter() {
if (run) {
scheduledFuture = threadPool.schedule(interval, executorName, this);
}
}
@Override
public void onFailure(Exception e) {
logger.warn("failed to run scheduled task", e);
}
@Override
protected void doRun() throws Exception {
if (run) {
runnable.run();
}
}
public synchronized void stop() {
if (run == false) {
throw new IllegalStateException("stop called but not started or stop called twice");
}
run = false;
FutureUtils.cancel(scheduledFuture);
scheduledFuture = null;
}
// package private for testing
ScheduledFuture<?> getScheduledFuture() {
return scheduledFuture;
}
}

View File

@ -5,26 +5,26 @@
*/
package org.elasticsearch.xpack.security.transport;
import org.elasticsearch.common.logging.ESLogger;
import org.elasticsearch.common.logging.Loggers;
import org.elasticsearch.common.util.concurrent.ThreadContext;
import org.elasticsearch.transport.TcpTransportChannel;
import org.elasticsearch.xpack.security.authc.Authentication;
import org.elasticsearch.xpack.security.action.SecurityActionMapper;
import org.elasticsearch.xpack.security.authc.AuthenticationService;
import org.elasticsearch.xpack.security.authc.pki.PkiRealm;
import org.elasticsearch.xpack.security.authz.AuthorizationService;
import org.elasticsearch.transport.DelegatingTransportChannel;
import org.elasticsearch.transport.TransportChannel;
import org.elasticsearch.transport.TransportRequest;
import org.jboss.netty.channel.Channel;
import org.jboss.netty.handler.ssl.SslHandler;
import javax.net.ssl.SSLPeerUnverifiedException;
import java.io.IOException;
import java.security.cert.Certificate;
import java.security.cert.X509Certificate;
import org.elasticsearch.common.logging.ESLogger;
import org.elasticsearch.common.logging.Loggers;
import org.elasticsearch.common.util.concurrent.ThreadContext;
import org.elasticsearch.transport.DelegatingTransportChannel;
import org.elasticsearch.transport.TcpTransportChannel;
import org.elasticsearch.transport.TransportChannel;
import org.elasticsearch.transport.TransportRequest;
import org.elasticsearch.xpack.security.action.SecurityActionMapper;
import org.elasticsearch.xpack.security.authc.Authentication;
import org.elasticsearch.xpack.security.authc.AuthenticationService;
import org.elasticsearch.xpack.security.authc.pki.PkiRealm;
import org.elasticsearch.xpack.security.authz.AuthorizationService;
import org.jboss.netty.channel.Channel;
import org.jboss.netty.handler.ssl.SslHandler;
import static org.elasticsearch.xpack.security.support.Exceptions.authenticationError;
/**

View File

@ -19,6 +19,7 @@ import org.elasticsearch.common.transport.TransportAddress;
import org.elasticsearch.xpack.security.audit.AuditTrail;
import org.elasticsearch.xpack.security.SecurityLicenseState;
import org.elasticsearch.transport.TransportSettings;
import org.elasticsearch.xpack.security.audit.AuditTrailService;
import java.net.InetAddress;
import java.util.ArrayList;
@ -105,7 +106,7 @@ public class IPFilter {
private final SetOnce<Map<String, BoundTransportAddress>> profileBoundAddress = new SetOnce<>();
@Inject
public IPFilter(final Settings settings, AuditTrail auditTrail, ClusterSettings clusterSettings,
public IPFilter(final Settings settings, AuditTrailService auditTrail, ClusterSettings clusterSettings,
SecurityLicenseState licenseState) {
this.logger = Loggers.getLogger(getClass(), settings);
this.auditTrail = auditTrail;

View File

@ -13,6 +13,7 @@ import org.elasticsearch.xpack.XPackFeatureSet;
import org.elasticsearch.xpack.security.audit.AuditTrailService;
import org.elasticsearch.xpack.security.authc.Realm;
import org.elasticsearch.xpack.security.authc.Realms;
import org.elasticsearch.xpack.security.authz.store.CompositeRolesStore;
import org.elasticsearch.xpack.security.authz.store.RolesStore;
import org.elasticsearch.xpack.security.crypto.CryptoService;
import org.elasticsearch.xpack.security.transport.filter.IPFilter;
@ -44,7 +45,7 @@ public class SecurityFeatureSetTests extends ESTestCase {
private Realms realms;
private NamedWriteableRegistry namedWriteableRegistry;
private IPFilter ipFilter;
private RolesStore rolesStore;
private CompositeRolesStore rolesStore;
private AuditTrailService auditTrail;
private CryptoService cryptoService;
@ -55,7 +56,7 @@ public class SecurityFeatureSetTests extends ESTestCase {
realms = mock(Realms.class);
namedWriteableRegistry = mock(NamedWriteableRegistry.class);
ipFilter = mock(IPFilter.class);
rolesStore = mock(RolesStore.class);
rolesStore = mock(CompositeRolesStore.class);
auditTrail = mock(AuditTrailService.class);
cryptoService = mock(CryptoService.class);
}

View File

@ -9,18 +9,18 @@ import java.io.IOException;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import org.elasticsearch.cluster.service.ClusterService;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.env.Environment;
import org.elasticsearch.test.ESTestCase;
import org.elasticsearch.threadpool.ThreadPool;
import org.elasticsearch.xpack.extensions.XPackExtension;
import org.elasticsearch.xpack.security.audit.AuditTrail;
import org.elasticsearch.xpack.security.audit.AuditTrailService;
import org.elasticsearch.xpack.security.audit.index.IndexAuditTrail;
import org.elasticsearch.xpack.security.audit.logfile.LoggingAuditTrail;
import org.elasticsearch.xpack.security.authc.AuthenticationService;
import org.elasticsearch.xpack.security.authc.Realm;
import org.elasticsearch.xpack.security.authc.Realms;
import org.elasticsearch.xpack.security.authc.file.FileRealm;
@ -54,7 +54,8 @@ public class SecurityTests extends ESTestCase {
Environment env = new Environment(settings);
Security security = new Security(settings, env);
ThreadPool threadPool = mock(ThreadPool.class);
return security.createComponents(null, threadPool, null, null, Arrays.asList(extensions));
ClusterService clusterService = mock(ClusterService.class);
return security.createComponents(null, threadPool, clusterService, null, Arrays.asList(extensions));
}
private <T> T findComponent(Class<T> type, Collection<Object> components) {
@ -91,7 +92,8 @@ public class SecurityTests extends ESTestCase {
public void testDisabledByDefault() throws Exception {
Collection<Object> components = createComponents(Settings.EMPTY);
assertNull(findComponent(AuditTrailService.class, components));
AuditTrailService auditTrailService = findComponent(AuditTrailService.class, components);
assertEquals(0, auditTrailService.getAuditTrails().size());
}
public void testIndexAuditTrail() throws Exception {

View File

@ -5,6 +5,8 @@
*/
package org.elasticsearch.xpack.security.action.filter;
import java.util.HashSet;
import org.elasticsearch.ElasticsearchSecurityException;
import org.elasticsearch.action.ActionListener;
import org.elasticsearch.action.ActionRequest;
@ -12,24 +14,22 @@ import org.elasticsearch.action.search.SearchScrollRequest;
import org.elasticsearch.action.support.ActionFilterChain;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.common.util.concurrent.ThreadContext;
import org.elasticsearch.xpack.security.SecurityContext;
import org.elasticsearch.xpack.security.action.SecurityActionMapper;
import org.elasticsearch.xpack.security.authc.Authentication;
import org.elasticsearch.xpack.security.authc.Authentication.RealmRef;
import org.elasticsearch.xpack.security.user.SystemUser;
import org.elasticsearch.xpack.security.user.User;
import org.elasticsearch.xpack.security.audit.AuditTrail;
import org.elasticsearch.xpack.security.authc.AuthenticationService;
import org.elasticsearch.xpack.security.authz.AuthorizationService;
import org.elasticsearch.xpack.security.crypto.CryptoService;
import org.elasticsearch.xpack.security.SecurityLicenseState;
import org.elasticsearch.tasks.Task;
import org.elasticsearch.test.ESTestCase;
import org.elasticsearch.threadpool.ThreadPool;
import org.elasticsearch.xpack.security.SecurityContext;
import org.elasticsearch.xpack.security.SecurityLicenseState;
import org.elasticsearch.xpack.security.action.SecurityActionMapper;
import org.elasticsearch.xpack.security.audit.AuditTrailService;
import org.elasticsearch.xpack.security.authc.Authentication;
import org.elasticsearch.xpack.security.authc.Authentication.RealmRef;
import org.elasticsearch.xpack.security.authc.AuthenticationService;
import org.elasticsearch.xpack.security.authz.AuthorizationService;
import org.elasticsearch.xpack.security.user.SystemUser;
import org.elasticsearch.xpack.security.user.User;
import org.elasticsearch.xpack.security.crypto.CryptoService;
import org.junit.Before;
import java.util.HashSet;
import static org.hamcrest.Matchers.equalTo;
import static org.mockito.Matchers.eq;
import static org.mockito.Matchers.isA;
@ -49,7 +49,7 @@ public class SecurityActionFilterTests extends ESTestCase {
private AuthenticationService authcService;
private AuthorizationService authzService;
private CryptoService cryptoService;
private AuditTrail auditTrail;
private AuditTrailService auditTrail;
private SecurityLicenseState securityLicenseState;
private SecurityActionFilter filter;
@ -58,7 +58,7 @@ public class SecurityActionFilterTests extends ESTestCase {
authcService = mock(AuthenticationService.class);
authzService = mock(AuthorizationService.class);
cryptoService = mock(CryptoService.class);
auditTrail = mock(AuditTrail.class);
auditTrail = mock(AuditTrailService.class);
securityLicenseState = mock(SecurityLicenseState.class);
when(securityLicenseState.authenticationAndAuthorizationEnabled()).thenReturn(true);
when(securityLicenseState.statsAndHealthEnabled()).thenReturn(true);

View File

@ -14,6 +14,8 @@ import org.elasticsearch.test.ESIntegTestCase.Scope;
import org.elasticsearch.test.InternalTestCluster;
import org.elasticsearch.test.SecurityIntegTestCase;
import org.elasticsearch.test.SecuritySettingsSource;
import org.elasticsearch.xpack.security.audit.AuditTrail;
import org.elasticsearch.xpack.security.audit.AuditTrailService;
import org.junit.After;
import org.junit.Before;
@ -22,6 +24,7 @@ import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.Set;
import java.util.concurrent.TimeUnit;
@ -137,10 +140,13 @@ public class RemoteIndexAuditTrailStartingTests extends SecurityIntegTestCase {
}
public void testThatRemoteAuditInstancesAreStarted() throws Exception {
Iterable<IndexAuditTrail> auditTrails = remoteCluster.getInstances(IndexAuditTrail.class);
for (final IndexAuditTrail auditTrail : auditTrails) {
awaitBusy(() -> auditTrail.state() == IndexAuditTrail.State.STARTED, 2L, TimeUnit.SECONDS);
assertThat(auditTrail.state(), is(IndexAuditTrail.State.STARTED));
}
AuditTrailService auditTrailService = remoteCluster.getInstance(AuditTrailService.class);
Optional<AuditTrail> auditTrail = auditTrailService.getAuditTrails().stream()
.filter(t -> t.name().equals(IndexAuditTrail.NAME)).findFirst();
assertTrue(auditTrail.isPresent());
IndexAuditTrail indexAuditTrail = (IndexAuditTrail)auditTrail.get();
awaitBusy(() -> indexAuditTrail.state() == IndexAuditTrail.State.STARTED, 2L, TimeUnit.SECONDS);
assertThat(indexAuditTrail.state(), is(IndexAuditTrail.State.STARTED));
}
}

View File

@ -5,6 +5,10 @@
*/
package org.elasticsearch.xpack.security.authc;
import java.io.IOException;
import java.util.Arrays;
import java.util.Collections;
import org.elasticsearch.ElasticsearchException;
import org.elasticsearch.ElasticsearchSecurityException;
import org.elasticsearch.common.io.stream.BytesStreamOutput;
@ -12,33 +16,28 @@ import org.elasticsearch.common.io.stream.StreamInput;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.common.util.concurrent.ThreadContext;
import org.elasticsearch.env.Environment;
import org.elasticsearch.rest.RestController;
import org.elasticsearch.rest.RestRequest;
import org.elasticsearch.xpack.security.authc.Authentication.RealmRef;
import org.elasticsearch.xpack.security.authc.InternalAuthenticationService.Authenticator;
import org.elasticsearch.xpack.security.SecurityLicenseState.EnabledRealmType;
import org.elasticsearch.xpack.security.user.AnonymousUser;
import org.elasticsearch.xpack.security.user.SystemUser;
import org.elasticsearch.xpack.security.user.User;
import org.elasticsearch.xpack.security.audit.AuditTrail;
import org.elasticsearch.xpack.security.authc.esnative.ReservedRealm;
import org.elasticsearch.xpack.security.authc.support.SecuredString;
import org.elasticsearch.xpack.security.authc.support.UsernamePasswordToken;
import org.elasticsearch.xpack.security.crypto.CryptoService;
import org.elasticsearch.xpack.security.SecurityLicenseState;
import org.elasticsearch.test.ESTestCase;
import org.elasticsearch.test.rest.FakeRestRequest;
import org.elasticsearch.threadpool.ThreadPool;
import org.elasticsearch.transport.TransportMessage;
import org.elasticsearch.xpack.security.SecurityLicenseState;
import org.elasticsearch.xpack.security.SecurityLicenseState.EnabledRealmType;
import org.elasticsearch.xpack.security.audit.AuditTrailService;
import org.elasticsearch.xpack.security.authc.Authentication.RealmRef;
import org.elasticsearch.xpack.security.authc.AuthenticationService.Authenticator;
import org.elasticsearch.xpack.security.authc.esnative.ReservedRealm;
import org.elasticsearch.xpack.security.authc.support.SecuredString;
import org.elasticsearch.xpack.security.authc.support.UsernamePasswordToken;
import org.elasticsearch.xpack.security.crypto.CryptoService;
import org.elasticsearch.xpack.security.user.AnonymousUser;
import org.elasticsearch.xpack.security.user.SystemUser;
import org.elasticsearch.xpack.security.user.User;
import org.junit.After;
import org.junit.Before;
import java.io.IOException;
import java.util.Arrays;
import java.util.Collections;
import static org.elasticsearch.xpack.security.support.Exceptions.authenticationError;
import static org.elasticsearch.test.SecurityTestsUtils.assertAuthenticationException;
import static org.elasticsearch.xpack.security.support.Exceptions.authenticationError;
import static org.hamcrest.Matchers.arrayContaining;
import static org.hamcrest.Matchers.containsString;
import static org.hamcrest.Matchers.equalTo;
@ -60,15 +59,15 @@ import static org.mockito.Mockito.when;
/**
*
*/
public class InternalAuthenticationServiceTests extends ESTestCase {
public class AuthenticationServiceTests extends ESTestCase {
InternalAuthenticationService service;
AuthenticationService service;
TransportMessage message;
RestRequest restRequest;
Realms realms;
Realm firstRealm;
Realm secondRealm;
AuditTrail auditTrail;
AuditTrailService auditTrail;
AuthenticationToken token;
CryptoService cryptoService;
ThreadPool threadPool;
@ -105,12 +104,12 @@ public class InternalAuthenticationServiceTests extends ESTestCase {
realms.start();
cryptoService = mock(CryptoService.class);
auditTrail = mock(AuditTrail.class);
auditTrail = mock(AuditTrailService.class);
threadPool = mock(ThreadPool.class);
threadContext = new ThreadContext(Settings.EMPTY);
when(threadPool.getThreadContext()).thenReturn(threadContext);
when(cryptoService.sign(any(String.class))).thenReturn("_signed_auth");
service = new InternalAuthenticationService(settings, realms, auditTrail, cryptoService,
service = new AuthenticationService(settings, realms, auditTrail, cryptoService,
new DefaultAuthenticationFailureHandler(), threadPool);
}
@ -309,7 +308,7 @@ public class InternalAuthenticationServiceTests extends ESTestCase {
InternalMessage message1 = new InternalMessage();
ThreadContext threadContext1 = new ThreadContext(Settings.EMPTY);
when(threadPool.getThreadContext()).thenReturn(threadContext1);
service = new InternalAuthenticationService(Settings.EMPTY, realms, auditTrail, cryptoService,
service = new AuthenticationService(Settings.EMPTY, realms, auditTrail, cryptoService,
new DefaultAuthenticationFailureHandler(), threadPool);
threadContext1.putTransient(Authentication.AUTHENTICATION_KEY, threadContext.getTransient(Authentication.AUTHENTICATION_KEY));
@ -323,7 +322,7 @@ public class InternalAuthenticationServiceTests extends ESTestCase {
// checking authentication from the user header
threadContext1 = new ThreadContext(Settings.EMPTY);
when(threadPool.getThreadContext()).thenReturn(threadContext1);
service = new InternalAuthenticationService(Settings.EMPTY, realms, auditTrail, cryptoService,
service = new AuthenticationService(Settings.EMPTY, realms, auditTrail, cryptoService,
new DefaultAuthenticationFailureHandler(), threadPool);
threadContext1.putHeader(Authentication.AUTHENTICATION_KEY, threadContext.getHeader(Authentication.AUTHENTICATION_KEY));
when(cryptoService.unsignAndVerify("_signed_auth")).thenReturn(authentication.encode());
@ -335,7 +334,7 @@ public class InternalAuthenticationServiceTests extends ESTestCase {
threadContext1.readHeaders(input);
when(threadPool.getThreadContext()).thenReturn(threadContext1);
service = new InternalAuthenticationService(Settings.EMPTY, realms, auditTrail, cryptoService,
service = new AuthenticationService(Settings.EMPTY, realms, auditTrail, cryptoService,
new DefaultAuthenticationFailureHandler(), threadPool);
Authentication result = service.authenticate("_action", new InternalMessage(), SystemUser.INSTANCE);
assertThat(result, notNullValue());
@ -344,8 +343,8 @@ public class InternalAuthenticationServiceTests extends ESTestCase {
}
public void testAuthenticateTransportContextAndHeaderNoSigning() throws Exception {
Settings settings = Settings.builder().put(InternalAuthenticationService.SIGN_USER_HEADER.getKey(), false).build();
service = new InternalAuthenticationService(settings, realms, auditTrail, cryptoService,
Settings settings = Settings.builder().put(AuthenticationService.SIGN_USER_HEADER.getKey(), false).build();
service = new AuthenticationService(settings, realms, auditTrail, cryptoService,
new DefaultAuthenticationFailureHandler(), threadPool);
User user1 = new User("username", "r1", "r2");
@ -362,7 +361,7 @@ public class InternalAuthenticationServiceTests extends ESTestCase {
InternalMessage message1 = new InternalMessage();
ThreadContext threadContext1 = new ThreadContext(Settings.EMPTY);
when(threadPool.getThreadContext()).thenReturn(threadContext1);
service = new InternalAuthenticationService(Settings.EMPTY, realms, auditTrail, cryptoService,
service = new AuthenticationService(Settings.EMPTY, realms, auditTrail, cryptoService,
new DefaultAuthenticationFailureHandler(), threadPool);
threadContext1.putTransient(Authentication.AUTHENTICATION_KEY, threadContext.getTransient(Authentication.AUTHENTICATION_KEY));
threadContext1.putHeader(Authentication.AUTHENTICATION_KEY, threadContext.getHeader(Authentication.AUTHENTICATION_KEY));
@ -382,7 +381,7 @@ public class InternalAuthenticationServiceTests extends ESTestCase {
threadContext1.readHeaders(input);
when(threadPool.getThreadContext()).thenReturn(threadContext1);
service = new InternalAuthenticationService(settings, realms, auditTrail, cryptoService,
service = new AuthenticationService(settings, realms, auditTrail, cryptoService,
new DefaultAuthenticationFailureHandler(), threadPool);
Authentication result = service.authenticate("_action", new InternalMessage(), SystemUser.INSTANCE);
assertThat(result, notNullValue());
@ -445,7 +444,7 @@ public class InternalAuthenticationServiceTests extends ESTestCase {
}
Settings settings = builder.build();
AnonymousUser.initialize(settings);
service = new InternalAuthenticationService(settings, realms, auditTrail, cryptoService, new DefaultAuthenticationFailureHandler(),
service = new AuthenticationService(settings, realms, auditTrail, cryptoService, new DefaultAuthenticationFailureHandler(),
threadPool);
RestRequest request = new FakeRestRequest();
@ -461,7 +460,7 @@ public class InternalAuthenticationServiceTests extends ESTestCase {
.putArray(AnonymousUser.ROLES_SETTING.getKey(), "r1", "r2", "r3")
.build();
AnonymousUser.initialize(settings);
service = new InternalAuthenticationService(settings, realms, auditTrail, cryptoService,
service = new AuthenticationService(settings, realms, auditTrail, cryptoService,
new DefaultAuthenticationFailureHandler(), threadPool);
InternalMessage message = new InternalMessage();
@ -476,7 +475,7 @@ public class InternalAuthenticationServiceTests extends ESTestCase {
.putArray(AnonymousUser.ROLES_SETTING.getKey(), "r1", "r2", "r3")
.build();
AnonymousUser.initialize(settings);
service = new InternalAuthenticationService(settings, realms, auditTrail, cryptoService,
service = new AuthenticationService(settings, realms, auditTrail, cryptoService,
new DefaultAuthenticationFailureHandler(), threadPool);
InternalMessage message = new InternalMessage();
@ -565,7 +564,7 @@ public class InternalAuthenticationServiceTests extends ESTestCase {
public void testRealmLookupThrowingException() throws Exception {
AuthenticationToken token = mock(AuthenticationToken.class);
threadContext.putHeader(InternalAuthenticationService.RUN_AS_USER_HEADER, "run_as");
threadContext.putHeader(AuthenticationService.RUN_AS_USER_HEADER, "run_as");
when(secondRealm.token(threadContext)).thenReturn(token);
when(secondRealm.supports(token)).thenReturn(true);
when(secondRealm.authenticate(token)).thenReturn(new User("lookup user", new String[]{"user"}));
@ -583,7 +582,7 @@ public class InternalAuthenticationServiceTests extends ESTestCase {
public void testRealmLookupThrowingExceptionRest() throws Exception {
AuthenticationToken token = mock(AuthenticationToken.class);
threadContext.putHeader(InternalAuthenticationService.RUN_AS_USER_HEADER, "run_as");
threadContext.putHeader(AuthenticationService.RUN_AS_USER_HEADER, "run_as");
when(secondRealm.token(threadContext)).thenReturn(token);
when(secondRealm.supports(token)).thenReturn(true);
when(secondRealm.authenticate(token)).thenReturn(new User("lookup user", new String[]{"user"}));
@ -601,7 +600,7 @@ public class InternalAuthenticationServiceTests extends ESTestCase {
public void testRunAsLookupSameRealm() throws Exception {
AuthenticationToken token = mock(AuthenticationToken.class);
threadContext.putHeader(InternalAuthenticationService.RUN_AS_USER_HEADER, "run_as");
threadContext.putHeader(AuthenticationService.RUN_AS_USER_HEADER, "run_as");
when(secondRealm.token(threadContext)).thenReturn(token);
when(secondRealm.supports(token)).thenReturn(true);
when(secondRealm.authenticate(token)).thenReturn(new User("lookup user", new String[]{"user"}));
@ -628,7 +627,7 @@ public class InternalAuthenticationServiceTests extends ESTestCase {
public void testRunAsLookupDifferentRealm() throws Exception {
AuthenticationToken token = mock(AuthenticationToken.class);
threadContext.putHeader(InternalAuthenticationService.RUN_AS_USER_HEADER, "run_as");
threadContext.putHeader(AuthenticationService.RUN_AS_USER_HEADER, "run_as");
when(secondRealm.token(threadContext)).thenReturn(token);
when(secondRealm.supports(token)).thenReturn(true);
when(secondRealm.authenticate(token)).thenReturn(new User("lookup user", new String[]{"user"}));
@ -657,7 +656,7 @@ public class InternalAuthenticationServiceTests extends ESTestCase {
public void testRunAsWithEmptyRunAsUsernameRest() throws Exception {
AuthenticationToken token = mock(AuthenticationToken.class);
User user = new User("lookup user", new String[]{"user"});
threadContext.putHeader(InternalAuthenticationService.RUN_AS_USER_HEADER, "");
threadContext.putHeader(AuthenticationService.RUN_AS_USER_HEADER, "");
when(secondRealm.token(threadContext)).thenReturn(token);
when(secondRealm.supports(token)).thenReturn(true);
when(secondRealm.authenticate(token)).thenReturn(user);
@ -675,7 +674,7 @@ public class InternalAuthenticationServiceTests extends ESTestCase {
public void testRunAsWithEmptyRunAsUsername() throws Exception {
AuthenticationToken token = mock(AuthenticationToken.class);
User user = new User("lookup user", new String[]{"user"});
threadContext.putHeader(InternalAuthenticationService.RUN_AS_USER_HEADER, "");
threadContext.putHeader(AuthenticationService.RUN_AS_USER_HEADER, "");
when(secondRealm.token(threadContext)).thenReturn(token);
when(secondRealm.supports(token)).thenReturn(true);
when(secondRealm.authenticate(token)).thenReturn(user);

View File

@ -95,7 +95,7 @@ public class RunAsIntegTests extends SecurityIntegTestCase {
// let's run as without authorization
try {
Map<String, String> headers = Collections.singletonMap(InternalAuthenticationService.RUN_AS_USER_HEADER,
Map<String, String> headers = Collections.singletonMap(AuthenticationService.RUN_AS_USER_HEADER,
SecuritySettingsSource.DEFAULT_USER_NAME);
client.filterWithHeader(headers)
.admin().cluster().prepareHealth().get();
@ -108,7 +108,7 @@ public class RunAsIntegTests extends SecurityIntegTestCase {
Map<String, String> headers = new HashMap<>();
headers.put("Authorization", UsernamePasswordToken.basicAuthHeaderValue(RUN_AS_USER,
new SecuredString(SecuritySettingsSource.DEFAULT_PASSWORD.toCharArray())));
headers.put(InternalAuthenticationService.RUN_AS_USER_HEADER, SecuritySettingsSource.DEFAULT_USER_NAME);
headers.put(AuthenticationService.RUN_AS_USER_HEADER, SecuritySettingsSource.DEFAULT_USER_NAME);
// lets set the user
ClusterHealthResponse response = client.filterWithHeader(headers).admin().cluster().prepareHealth().get();
assertThat(response.isTimedOut(), is(false));
@ -122,7 +122,7 @@ public class RunAsIntegTests extends SecurityIntegTestCase {
new BasicHeader(UsernamePasswordToken.BASIC_AUTH_HEADER,
UsernamePasswordToken.basicAuthHeaderValue(TRANSPORT_CLIENT_USER,
SecuredStringTests.build(SecuritySettingsSource.DEFAULT_PASSWORD))),
new BasicHeader(InternalAuthenticationService.RUN_AS_USER_HEADER, SecuritySettingsSource.DEFAULT_USER_NAME));
new BasicHeader(AuthenticationService.RUN_AS_USER_HEADER, SecuritySettingsSource.DEFAULT_USER_NAME));
fail("request should have failed");
} catch(ResponseException e) {
assertThat(e.getResponse().getStatusLine().getStatusCode(), is(403));
@ -144,7 +144,7 @@ public class RunAsIntegTests extends SecurityIntegTestCase {
new BasicHeader(UsernamePasswordToken.BASIC_AUTH_HEADER,
UsernamePasswordToken.basicAuthHeaderValue(RUN_AS_USER,
SecuredStringTests.build(SecuritySettingsSource.DEFAULT_PASSWORD))),
new BasicHeader(InternalAuthenticationService.RUN_AS_USER_HEADER, SecuritySettingsSource.DEFAULT_USER_NAME));
new BasicHeader(AuthenticationService.RUN_AS_USER_HEADER, SecuritySettingsSource.DEFAULT_USER_NAME));
assertThat(response.getStatusLine().getStatusCode(), is(200));
}
@ -160,7 +160,7 @@ public class RunAsIntegTests extends SecurityIntegTestCase {
Map<String, String> headers = new HashMap<>();
headers.put("Authorization", UsernamePasswordToken.basicAuthHeaderValue(RUN_AS_USER,
new SecuredString(SecuritySettingsSource.DEFAULT_PASSWORD.toCharArray())));
headers.put(InternalAuthenticationService.RUN_AS_USER_HEADER, "");
headers.put(AuthenticationService.RUN_AS_USER_HEADER, "");
client.filterWithHeader(headers).admin().cluster().prepareHealth().get();
fail("run as header should not be allowed to be empty");
@ -176,7 +176,7 @@ public class RunAsIntegTests extends SecurityIntegTestCase {
new BasicHeader(UsernamePasswordToken.BASIC_AUTH_HEADER,
UsernamePasswordToken.basicAuthHeaderValue(RUN_AS_USER,
SecuredStringTests.build(SecuritySettingsSource.DEFAULT_PASSWORD))),
new BasicHeader(InternalAuthenticationService.RUN_AS_USER_HEADER, ""));
new BasicHeader(AuthenticationService.RUN_AS_USER_HEADER, ""));
fail("request should have failed");
} catch(ResponseException e) {
assertThat(e.getResponse().getStatusLine().getStatusCode(), is(401));
@ -195,7 +195,7 @@ public class RunAsIntegTests extends SecurityIntegTestCase {
Map<String, String> headers = new HashMap<>();
headers.put("Authorization", UsernamePasswordToken.basicAuthHeaderValue(RUN_AS_USER,
new SecuredString(SecuritySettingsSource.DEFAULT_PASSWORD.toCharArray())));
headers.put(InternalAuthenticationService.RUN_AS_USER_HEADER, "idontexist");
headers.put(AuthenticationService.RUN_AS_USER_HEADER, "idontexist");
client.filterWithHeader(headers).admin().cluster().prepareHealth().get();
fail("run as header should not accept non-existent users");
@ -211,7 +211,7 @@ public class RunAsIntegTests extends SecurityIntegTestCase {
new BasicHeader(UsernamePasswordToken.BASIC_AUTH_HEADER,
UsernamePasswordToken.basicAuthHeaderValue(RUN_AS_USER,
SecuredStringTests.build(SecuritySettingsSource.DEFAULT_PASSWORD))),
new BasicHeader(InternalAuthenticationService.RUN_AS_USER_HEADER, "idontexist"));
new BasicHeader(AuthenticationService.RUN_AS_USER_HEADER, "idontexist"));
fail("request should have failed");
} catch (ResponseException e) {
assertThat(e.getResponse().getStatusLine().getStatusCode(), is(403));

View File

@ -5,6 +5,9 @@
*/
package org.elasticsearch.xpack.security.authz;
import java.util.ArrayList;
import java.util.List;
import org.elasticsearch.ElasticsearchSecurityException;
import org.elasticsearch.Version;
import org.elasticsearch.action.admin.cluster.health.ClusterHealthAction;
@ -45,47 +48,42 @@ import org.elasticsearch.action.termvectors.TermVectorsAction;
import org.elasticsearch.action.termvectors.TermVectorsRequest;
import org.elasticsearch.action.update.UpdateAction;
import org.elasticsearch.action.update.UpdateRequest;
import org.elasticsearch.cluster.metadata.IndexNameExpressionResolver;
import org.elasticsearch.cluster.service.ClusterService;
import org.elasticsearch.cluster.ClusterState;
import org.elasticsearch.cluster.metadata.AliasMetaData;
import org.elasticsearch.cluster.metadata.IndexMetaData;
import org.elasticsearch.cluster.metadata.MetaData;
import org.elasticsearch.cluster.service.ClusterService;
import org.elasticsearch.common.collect.Tuple;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.common.util.concurrent.ThreadContext;
import org.elasticsearch.search.action.SearchTransportService;
import org.elasticsearch.test.ESTestCase;
import org.elasticsearch.threadpool.ThreadPool;
import org.elasticsearch.transport.TransportRequest;
import org.elasticsearch.xpack.security.SecurityTemplateService;
import org.elasticsearch.xpack.security.audit.AuditTrailService;
import org.elasticsearch.xpack.security.authc.Authentication;
import org.elasticsearch.xpack.security.authc.Authentication.RealmRef;
import org.elasticsearch.xpack.security.authz.store.CompositeRolesStore;
import org.elasticsearch.xpack.security.user.AnonymousUser;
import org.elasticsearch.xpack.security.user.SystemUser;
import org.elasticsearch.xpack.security.user.User;
import org.elasticsearch.xpack.security.user.XPackUser;
import org.elasticsearch.xpack.security.audit.AuditTrail;
import org.elasticsearch.xpack.security.authc.DefaultAuthenticationFailureHandler;
import org.elasticsearch.xpack.security.authz.permission.Role;
import org.elasticsearch.xpack.security.authz.permission.SuperuserRole;
import org.elasticsearch.xpack.security.authz.privilege.ClusterPrivilege;
import org.elasticsearch.xpack.security.authz.privilege.GeneralPrivilege;
import org.elasticsearch.xpack.security.authz.privilege.IndexPrivilege;
import org.elasticsearch.xpack.security.authz.store.RolesStore;
import org.elasticsearch.test.ESTestCase;
import org.elasticsearch.threadpool.ThreadPool;
import org.elasticsearch.transport.TransportRequest;
import org.junit.After;
import org.junit.Before;
import java.util.ArrayList;
import java.util.List;
import static org.elasticsearch.test.SecurityTestsUtils.assertAuthenticationException;
import static org.elasticsearch.test.SecurityTestsUtils.assertAuthorizationException;
import static org.hamcrest.Matchers.containsInAnyOrder;
import static org.hamcrest.Matchers.containsString;
import static org.hamcrest.Matchers.is;
import static org.hamcrest.Matchers.notNullValue;
import static org.mockito.AdditionalAnswers.returnsFirstArg;
import static org.mockito.Matchers.any;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.times;
@ -93,27 +91,25 @@ import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.verifyNoMoreInteractions;
import static org.mockito.Mockito.when;
public class InternalAuthorizationServiceTests extends ESTestCase {
private AuditTrail auditTrail;
private RolesStore rolesStore;
public class AuthorizationServiceTests extends ESTestCase {
private AuditTrailService auditTrail;
private CompositeRolesStore rolesStore;
private ClusterService clusterService;
private InternalAuthorizationService internalAuthorizationService;
private AuthorizationService authorizationService;
private ThreadContext threadContext;
private ThreadPool threadPool;
@Before
public void setup() {
rolesStore = mock(RolesStore.class);
rolesStore = mock(CompositeRolesStore.class);
clusterService = mock(ClusterService.class);
auditTrail = mock(AuditTrail.class);
auditTrail = mock(AuditTrailService.class);
threadContext = new ThreadContext(Settings.EMPTY);
threadPool = mock(ThreadPool.class);
when(threadPool.getThreadContext()).thenReturn(threadContext);
IndexNameExpressionResolver nameExpressionResolver = mock(IndexNameExpressionResolver.class);
when(nameExpressionResolver.resolveDateMathExpression(any(String.class))).thenAnswer(returnsFirstArg());
internalAuthorizationService = new InternalAuthorizationService(Settings.EMPTY, rolesStore, clusterService,
auditTrail, new DefaultAuthenticationFailureHandler(), threadPool, nameExpressionResolver);
authorizationService = new AuthorizationService(Settings.EMPTY, rolesStore, clusterService,
auditTrail, new DefaultAuthenticationFailureHandler(), threadPool);
}
@After
@ -125,10 +121,10 @@ public class InternalAuthorizationServiceTests extends ESTestCase {
TransportRequest request = mock(TransportRequest.class);
// A failure would throw an exception
internalAuthorizationService.authorize(createAuthentication(SystemUser.INSTANCE), "indices:monitor/whatever", request);
authorizationService.authorize(createAuthentication(SystemUser.INSTANCE), "indices:monitor/whatever", request);
verify(auditTrail).accessGranted(SystemUser.INSTANCE, "indices:monitor/whatever", request);
internalAuthorizationService.authorize(createAuthentication(SystemUser.INSTANCE), "internal:whatever", request);
authorizationService.authorize(createAuthentication(SystemUser.INSTANCE), "internal:whatever", request);
verify(auditTrail).accessGranted(SystemUser.INSTANCE, "internal:whatever", request);
verifyNoMoreInteractions(auditTrail);
}
@ -136,7 +132,7 @@ public class InternalAuthorizationServiceTests extends ESTestCase {
public void testIndicesActionsAreNotAuthorized() {
TransportRequest request = mock(TransportRequest.class);
try {
internalAuthorizationService.authorize(createAuthentication(SystemUser.INSTANCE), "indices:", request);
authorizationService.authorize(createAuthentication(SystemUser.INSTANCE), "indices:", request);
fail("action beginning with indices should have failed");
} catch (ElasticsearchSecurityException e) {
assertAuthorizationException(e,
@ -149,7 +145,7 @@ public class InternalAuthorizationServiceTests extends ESTestCase {
public void testClusterAdminActionsAreNotAuthorized() {
TransportRequest request = mock(TransportRequest.class);
try {
internalAuthorizationService.authorize(createAuthentication(SystemUser.INSTANCE), "cluster:admin/whatever", request);
authorizationService.authorize(createAuthentication(SystemUser.INSTANCE), "cluster:admin/whatever", request);
fail("action beginning with cluster:admin/whatever should have failed");
} catch (ElasticsearchSecurityException e) {
assertAuthorizationException(e,
@ -162,7 +158,7 @@ public class InternalAuthorizationServiceTests extends ESTestCase {
public void testClusterAdminSnapshotStatusActionIsNotAuthorized() {
TransportRequest request = mock(TransportRequest.class);
try {
internalAuthorizationService.authorize(createAuthentication(SystemUser.INSTANCE), "cluster:admin/snapshot/status", request);
authorizationService.authorize(createAuthentication(SystemUser.INSTANCE), "cluster:admin/snapshot/status", request);
fail("action beginning with cluster:admin/snapshot/status should have failed");
} catch (ElasticsearchSecurityException e) {
assertAuthorizationException(e, containsString("action [cluster:admin/snapshot/status] is unauthorized for user [" +
@ -176,7 +172,7 @@ public class InternalAuthorizationServiceTests extends ESTestCase {
TransportRequest request = new SearchRequest();
User user = new User("test user");
try {
internalAuthorizationService.authorize(createAuthentication(user), "indices:a", request);
authorizationService.authorize(createAuthentication(user), "indices:a", request);
fail("user without roles should be denied");
} catch (ElasticsearchSecurityException e) {
assertAuthorizationException(e, containsString("action [indices:a] is unauthorized for user [test user]"));
@ -189,7 +185,7 @@ public class InternalAuthorizationServiceTests extends ESTestCase {
TransportRequest request = new SearchRequest();
User user = new User("test user", "non-existent-role");
try {
internalAuthorizationService.authorize(createAuthentication(user), "indices:a", request);
authorizationService.authorize(createAuthentication(user), "indices:a", request);
fail("user with unknown role only should have been denied");
} catch (ElasticsearchSecurityException e) {
assertAuthorizationException(e, containsString("action [indices:a] is unauthorized for user [test user]"));
@ -204,7 +200,7 @@ public class InternalAuthorizationServiceTests extends ESTestCase {
when(rolesStore.role("a_all")).thenReturn(Role.builder("a_role").add(IndexPrivilege.ALL, "a").build());
try {
internalAuthorizationService.authorize(createAuthentication(user), "whatever", request);
authorizationService.authorize(createAuthentication(user), "whatever", request);
fail("non indices and non cluster requests should be denied");
} catch (ElasticsearchSecurityException e) {
assertAuthorizationException(e, containsString("action [whatever] is unauthorized for user [test user]"));
@ -219,7 +215,7 @@ public class InternalAuthorizationServiceTests extends ESTestCase {
when(rolesStore.role("no_indices")).thenReturn(Role.builder("no_indices").cluster(ClusterPrivilege.action("")).build());
try {
internalAuthorizationService.authorize(createAuthentication(user), "indices:a", request);
authorizationService.authorize(createAuthentication(user), "indices:a", request);
fail("user only has cluster roles so indices requests should fail");
} catch (ElasticsearchSecurityException e) {
assertAuthorizationException(e, containsString("action [indices:a] is unauthorized for user [test user]"));
@ -233,29 +229,29 @@ public class InternalAuthorizationServiceTests extends ESTestCase {
when(rolesStore.role("a_all")).thenReturn(Role.builder("a_role").add(IndexPrivilege.ALL, "a").build());
ClearScrollRequest clearScrollRequest = new ClearScrollRequest();
internalAuthorizationService.authorize(createAuthentication(user), ClearScrollAction.NAME, clearScrollRequest);
authorizationService.authorize(createAuthentication(user), ClearScrollAction.NAME, clearScrollRequest);
verify(auditTrail).accessGranted(user, ClearScrollAction.NAME, clearScrollRequest);
SearchScrollRequest searchScrollRequest = new SearchScrollRequest();
internalAuthorizationService.authorize(createAuthentication(user), SearchScrollAction.NAME, searchScrollRequest);
authorizationService.authorize(createAuthentication(user), SearchScrollAction.NAME, searchScrollRequest);
verify(auditTrail).accessGranted(user, SearchScrollAction.NAME, searchScrollRequest);
// 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);
internalAuthorizationService
authorizationService
.authorize(createAuthentication(user), SearchTransportService.CLEAR_SCROLL_CONTEXTS_ACTION_NAME, request);
verify(auditTrail).accessGranted(user, SearchTransportService.CLEAR_SCROLL_CONTEXTS_ACTION_NAME, request);
internalAuthorizationService.authorize(createAuthentication(user), SearchTransportService.FETCH_ID_SCROLL_ACTION_NAME, request);
authorizationService.authorize(createAuthentication(user), SearchTransportService.FETCH_ID_SCROLL_ACTION_NAME, request);
verify(auditTrail).accessGranted(user, SearchTransportService.FETCH_ID_SCROLL_ACTION_NAME, request);
internalAuthorizationService.authorize(createAuthentication(user), SearchTransportService.QUERY_FETCH_SCROLL_ACTION_NAME, request);
authorizationService.authorize(createAuthentication(user), SearchTransportService.QUERY_FETCH_SCROLL_ACTION_NAME, request);
verify(auditTrail).accessGranted(user, SearchTransportService.QUERY_FETCH_SCROLL_ACTION_NAME, request);
internalAuthorizationService.authorize(createAuthentication(user), SearchTransportService.QUERY_SCROLL_ACTION_NAME, request);
authorizationService.authorize(createAuthentication(user), SearchTransportService.QUERY_SCROLL_ACTION_NAME, request);
verify(auditTrail).accessGranted(user, SearchTransportService.QUERY_SCROLL_ACTION_NAME, request);
internalAuthorizationService.authorize(createAuthentication(user), SearchTransportService.FREE_CONTEXT_SCROLL_ACTION_NAME, request);
authorizationService.authorize(createAuthentication(user), SearchTransportService.FREE_CONTEXT_SCROLL_ACTION_NAME, request);
verify(auditTrail).accessGranted(user, SearchTransportService.FREE_CONTEXT_SCROLL_ACTION_NAME, request);
verifyNoMoreInteractions(auditTrail);
}
@ -269,7 +265,7 @@ public class InternalAuthorizationServiceTests extends ESTestCase {
when(state.metaData()).thenReturn(MetaData.EMPTY_META_DATA);
try {
internalAuthorizationService.authorize(createAuthentication(user), "indices:a", request);
authorizationService.authorize(createAuthentication(user), "indices:a", request);
fail("indices request for b should be denied since there is no such index");
} catch (ElasticsearchSecurityException e) {
assertAuthorizationException(e, containsString("action [indices:a] is unauthorized for user [test user]"));
@ -290,7 +286,7 @@ public class InternalAuthorizationServiceTests extends ESTestCase {
when(state.metaData()).thenReturn(MetaData.EMPTY_META_DATA);
try {
internalAuthorizationService.authorize(createAuthentication(user), CreateIndexAction.NAME, request);
authorizationService.authorize(createAuthentication(user), CreateIndexAction.NAME, request);
fail("indices creation request with alias should be denied since user does not have permission to alias");
} catch (ElasticsearchSecurityException e) {
assertAuthorizationException(e,
@ -311,7 +307,7 @@ public class InternalAuthorizationServiceTests extends ESTestCase {
when(clusterService.state()).thenReturn(state);
when(state.metaData()).thenReturn(MetaData.EMPTY_META_DATA);
internalAuthorizationService.authorize(createAuthentication(user), CreateIndexAction.NAME, request);
authorizationService.authorize(createAuthentication(user), CreateIndexAction.NAME, request);
verify(auditTrail).accessGranted(user, CreateIndexAction.NAME, request);
verifyNoMoreInteractions(auditTrail);
@ -322,7 +318,7 @@ public class InternalAuthorizationServiceTests extends ESTestCase {
public void testIndicesAliasesWithNoRolesUser() {
User user = new User("test user");
List<String> list = internalAuthorizationService.authorizedIndicesAndAliases(user, "");
List<String> list = authorizationService.authorizedIndicesAndAliases(user, "");
assertThat(list.isEmpty(), is(true));
}
@ -347,7 +343,7 @@ public class InternalAuthorizationServiceTests extends ESTestCase {
.build(), true)
.build());
List<String> list = internalAuthorizationService.authorizedIndicesAndAliases(user, SearchAction.NAME);
List<String> list = authorizationService.authorizedIndicesAndAliases(user, SearchAction.NAME);
assertThat(list, containsInAnyOrder("a1", "a2", "aaaaaa", "b", "ab"));
assertThat(list.contains("bbbbb"), is(false));
assertThat(list.contains("ba"), is(false));
@ -357,17 +353,15 @@ public class InternalAuthorizationServiceTests extends ESTestCase {
TransportRequest request = new IndicesExistsRequest("b");
ClusterState state = mock(ClusterState.class);
AnonymousUser.initialize(Settings.builder().put(AnonymousUser.ROLES_SETTING.getKey(), "a_all").build());
IndexNameExpressionResolver nameExpressionResolver = mock(IndexNameExpressionResolver.class);
when(nameExpressionResolver.resolveDateMathExpression(any(String.class))).thenAnswer(returnsFirstArg());
internalAuthorizationService = new InternalAuthorizationService(Settings.EMPTY, rolesStore, clusterService, auditTrail,
new DefaultAuthenticationFailureHandler(), threadPool, nameExpressionResolver);
authorizationService = new AuthorizationService(Settings.EMPTY, rolesStore, clusterService, auditTrail,
new DefaultAuthenticationFailureHandler(), threadPool);
when(rolesStore.role("a_all")).thenReturn(Role.builder("a_all").add(IndexPrivilege.ALL, "a").build());
when(clusterService.state()).thenReturn(state);
when(state.metaData()).thenReturn(MetaData.EMPTY_META_DATA);
try {
internalAuthorizationService.authorize(createAuthentication(AnonymousUser.INSTANCE), "indices:a", request);
authorizationService.authorize(createAuthentication(AnonymousUser.INSTANCE), "indices:a", request);
fail("indices request for b should be denied since there is no such index");
} catch (ElasticsearchSecurityException e) {
assertAuthorizationException(e,
@ -384,21 +378,19 @@ public class InternalAuthorizationServiceTests extends ESTestCase {
ClusterState state = mock(ClusterState.class);
AnonymousUser.initialize(Settings.builder()
.put(AnonymousUser.ROLES_SETTING.getKey(), "a_all")
.put(InternalAuthorizationService.ANONYMOUS_AUTHORIZATION_EXCEPTION_SETTING.getKey(), false)
.put(AuthorizationService.ANONYMOUS_AUTHORIZATION_EXCEPTION_SETTING.getKey(), false)
.build());
User anonymousUser = AnonymousUser.INSTANCE;
IndexNameExpressionResolver nameExpressionResolver = mock(IndexNameExpressionResolver.class);
when(nameExpressionResolver.resolveDateMathExpression(any(String.class))).thenAnswer(returnsFirstArg());
internalAuthorizationService = new InternalAuthorizationService(
Settings.builder().put(InternalAuthorizationService.ANONYMOUS_AUTHORIZATION_EXCEPTION_SETTING.getKey(), false).build(),
rolesStore, clusterService, auditTrail, new DefaultAuthenticationFailureHandler(), threadPool, nameExpressionResolver);
authorizationService = new AuthorizationService(
Settings.builder().put(AuthorizationService.ANONYMOUS_AUTHORIZATION_EXCEPTION_SETTING.getKey(), false).build(),
rolesStore, clusterService, auditTrail, new DefaultAuthenticationFailureHandler(), threadPool);
when(rolesStore.role("a_all")).thenReturn(Role.builder("a_all").add(IndexPrivilege.ALL, "a").build());
when(clusterService.state()).thenReturn(state);
when(state.metaData()).thenReturn(MetaData.EMPTY_META_DATA);
try {
internalAuthorizationService.authorize(createAuthentication(anonymousUser), "indices:a", request);
authorizationService.authorize(createAuthentication(anonymousUser), "indices:a", request);
fail("indices request for b should be denied since there is no such index");
} catch (ElasticsearchSecurityException e) {
assertAuthenticationException(e, containsString("action [indices:a] requires authentication"));
@ -414,7 +406,7 @@ public class InternalAuthorizationServiceTests extends ESTestCase {
User user = new User("test user", null, new User("run as me", new String[] { "admin" }));
assertThat(user.runAs(), is(notNullValue()));
try {
internalAuthorizationService.authorize(createAuthentication(user), "indices:a", request);
authorizationService.authorize(createAuthentication(user), "indices:a", request);
fail("user without roles should be denied for run as");
} catch (ElasticsearchSecurityException e) {
assertAuthorizationException(e, containsString("action [indices:a] is unauthorized for user [test user] run as [run as me]"));
@ -434,7 +426,7 @@ public class InternalAuthorizationServiceTests extends ESTestCase {
.build());
try {
internalAuthorizationService.authorize(createAuthentication(user), "indices:a", request);
authorizationService.authorize(createAuthentication(user), "indices:a", request);
fail("user without roles should be denied for run as");
} catch (ElasticsearchSecurityException e) {
assertAuthorizationException(e, containsString("action [indices:a] is unauthorized for user [test user] run as [run as me]"));
@ -468,7 +460,7 @@ public class InternalAuthorizationServiceTests extends ESTestCase {
}
try {
internalAuthorizationService.authorize(createAuthentication(user), "indices:a", request);
authorizationService.authorize(createAuthentication(user), "indices:a", request);
fail("the run as user's role doesn't exist so they should not get authorized");
} catch (ElasticsearchSecurityException e) {
assertAuthorizationException(e, containsString("action [indices:a] is unauthorized for user [test user] run as [run as me]"));
@ -499,7 +491,7 @@ public class InternalAuthorizationServiceTests extends ESTestCase {
.add(IndexPrivilege.ALL, "b")
.build());
internalAuthorizationService.authorize(createAuthentication(user), "indices:a", request);
authorizationService.authorize(createAuthentication(user), "indices:a", request);
verify(auditTrail).runAsGranted(user, "indices:a", request);
verify(auditTrail).accessGranted(user, "indices:a", request);
verifyNoMoreInteractions(auditTrail);
@ -538,7 +530,7 @@ public class InternalAuthorizationServiceTests extends ESTestCase {
String action = requestTuple.v1();
TransportRequest request = requestTuple.v2();
try {
internalAuthorizationService.authorize(createAuthentication(user), action, request);
authorizationService.authorize(createAuthentication(user), action, request);
fail("only the xpack user can execute operation [" + action + "] against the internal index");
} catch (ElasticsearchSecurityException e) {
assertAuthorizationException(e, containsString("action [" + action + "] is unauthorized for user [all_access_user]"));
@ -549,12 +541,12 @@ public class InternalAuthorizationServiceTests extends ESTestCase {
// we should allow waiting for the health of the index or any index if the user has this permission
ClusterHealthRequest request = new ClusterHealthRequest(SecurityTemplateService.SECURITY_INDEX_NAME);
internalAuthorizationService.authorize(createAuthentication(user), ClusterHealthAction.NAME, request);
authorizationService.authorize(createAuthentication(user), ClusterHealthAction.NAME, request);
verify(auditTrail).accessGranted(user, ClusterHealthAction.NAME, request);
// multiple indices
request = new ClusterHealthRequest(SecurityTemplateService.SECURITY_INDEX_NAME, "foo", "bar");
internalAuthorizationService.authorize(createAuthentication(user), ClusterHealthAction.NAME, request);
authorizationService.authorize(createAuthentication(user), ClusterHealthAction.NAME, request);
verify(auditTrail).accessGranted(user, ClusterHealthAction.NAME, request);
}
@ -586,7 +578,7 @@ public class InternalAuthorizationServiceTests extends ESTestCase {
for (Tuple<String, ? extends TransportRequest> requestTuple : requests) {
String action = requestTuple.v1();
TransportRequest request = requestTuple.v2();
internalAuthorizationService.authorize(createAuthentication(user), action, request);
authorizationService.authorize(createAuthentication(user), action, request);
verify(auditTrail).accessGranted(user, action, request);
}
}
@ -620,7 +612,7 @@ public class InternalAuthorizationServiceTests extends ESTestCase {
for (Tuple<String, TransportRequest> requestTuple : requests) {
String action = requestTuple.v1();
TransportRequest request = requestTuple.v2();
internalAuthorizationService.authorize(createAuthentication(XPackUser.INSTANCE), action, request);
authorizationService.authorize(createAuthentication(XPackUser.INSTANCE), action, request);
verify(auditTrail).accessGranted(XPackUser.INSTANCE, action, request);
}
}

View File

@ -44,7 +44,7 @@ public class AuthorizationUtilsTests extends ESTestCase {
User user = new User(randomAsciiOfLength(6), new String[] {});
Authentication authentication = new Authentication(user, new RealmRef("test", "test", "foo"), null);
threadContext.putTransient(Authentication.AUTHENTICATION_KEY, authentication);
threadContext.putTransient(InternalAuthorizationService.ORIGINATING_ACTION_KEY, randomFrom("indices:foo", "cluster:bar"));
threadContext.putTransient(AuthorizationService.ORIGINATING_ACTION_KEY, randomFrom("indices:foo", "cluster:bar"));
assertThat(AuthorizationUtils.shouldReplaceUserWithSystem(threadContext, "internal:something"), is(true));
}
@ -52,7 +52,7 @@ public class AuthorizationUtilsTests extends ESTestCase {
User user = new User(randomAsciiOfLength(6), new String[] {});
Authentication authentication = new Authentication(user, new RealmRef("test", "test", "foo"), null);
threadContext.putTransient(Authentication.AUTHENTICATION_KEY, authentication);
threadContext.putTransient(InternalAuthorizationService.ORIGINATING_ACTION_KEY, randomFrom("internal:foo/bar"));
threadContext.putTransient(AuthorizationService.ORIGINATING_ACTION_KEY, randomFrom("internal:foo/bar"));
assertThat(AuthorizationUtils.shouldReplaceUserWithSystem(threadContext, "internal:something"), is(false));
}
}

View File

@ -5,6 +5,8 @@
*/
package org.elasticsearch.xpack.security.authz.indicesresolver;
import java.util.Set;
import org.elasticsearch.Version;
import org.elasticsearch.action.admin.indices.alias.IndicesAliasesAction;
import org.elasticsearch.action.admin.indices.alias.IndicesAliasesRequest;
@ -20,32 +22,31 @@ import org.elasticsearch.action.search.SearchAction;
import org.elasticsearch.action.search.SearchRequest;
import org.elasticsearch.action.support.IndicesOptions;
import org.elasticsearch.client.Requests;
import org.elasticsearch.cluster.metadata.IndexNameExpressionResolver;
import org.elasticsearch.cluster.service.ClusterService;
import org.elasticsearch.cluster.ClusterState;
import org.elasticsearch.cluster.metadata.AliasAction;
import org.elasticsearch.cluster.metadata.AliasMetaData;
import org.elasticsearch.cluster.metadata.IndexMetaData;
import org.elasticsearch.cluster.metadata.IndexNameExpressionResolver;
import org.elasticsearch.cluster.metadata.MetaData;
import org.elasticsearch.cluster.service.ClusterService;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.index.IndexNotFoundException;
import org.elasticsearch.test.ESTestCase;
import org.elasticsearch.threadpool.ThreadPool;
import org.elasticsearch.xpack.security.SecurityTemplateService;
import org.elasticsearch.xpack.security.authz.store.CompositeRolesStore;
import org.elasticsearch.xpack.security.user.User;
import org.elasticsearch.xpack.security.user.XPackUser;
import org.elasticsearch.xpack.security.audit.AuditTrail;
import org.elasticsearch.xpack.security.audit.AuditTrailService;
import org.elasticsearch.xpack.security.authc.DefaultAuthenticationFailureHandler;
import org.elasticsearch.xpack.security.authz.InternalAuthorizationService;
import org.elasticsearch.xpack.security.authz.AuthorizationService;
import org.elasticsearch.xpack.security.authz.permission.Role;
import org.elasticsearch.xpack.security.authz.permission.SuperuserRole;
import org.elasticsearch.xpack.security.authz.privilege.ClusterPrivilege;
import org.elasticsearch.xpack.security.authz.privilege.IndexPrivilege;
import org.elasticsearch.xpack.security.authz.store.RolesStore;
import org.elasticsearch.test.ESTestCase;
import org.elasticsearch.threadpool.ThreadPool;
import org.junit.Before;
import java.util.Set;
import static org.hamcrest.Matchers.arrayContaining;
import static org.hamcrest.Matchers.arrayContainingInAnyOrder;
import static org.hamcrest.Matchers.equalTo;
@ -60,7 +61,7 @@ public class DefaultIndicesResolverTests extends ESTestCase {
private User user;
private User userNoIndices;
private RolesStore rolesStore;
private CompositeRolesStore rolesStore;
private MetaData metaData;
private DefaultIndicesAndAliasesResolver defaultIndicesResolver;
private IndexNameExpressionResolver indexNameExpressionResolver;
@ -91,7 +92,7 @@ public class DefaultIndicesResolverTests extends ESTestCase {
user = new User("user", "role");
userNoIndices = new User("test", "test");
rolesStore = mock(RolesStore.class);
rolesStore = mock(CompositeRolesStore.class);
String[] authorizedIndices = new String[] { "bar", "bar-closed", "foofoobar", "foofoo", "missing", "foofoo-closed" };
when(rolesStore.role("role")).thenReturn(Role.builder("role").add(IndexPrivilege.ALL, authorizedIndices).build());
when(rolesStore.role("test")).thenReturn(Role.builder("test").cluster(ClusterPrivilege.MONITOR).build());
@ -101,8 +102,8 @@ public class DefaultIndicesResolverTests extends ESTestCase {
when(clusterService.state()).thenReturn(state);
when(state.metaData()).thenReturn(metaData);
InternalAuthorizationService authzService = new InternalAuthorizationService(settings, rolesStore, clusterService,
mock(AuditTrail.class), new DefaultAuthenticationFailureHandler(), mock(ThreadPool.class), indexNameExpressionResolver);
AuthorizationService authzService = new AuthorizationService(settings, rolesStore, clusterService,
mock(AuditTrailService.class), new DefaultAuthenticationFailureHandler(), mock(ThreadPool.class));
defaultIndicesResolver = new DefaultIndicesAndAliasesResolver(authzService, indexNameExpressionResolver);
}

View File

@ -13,10 +13,10 @@ import org.elasticsearch.rest.RestController;
import org.elasticsearch.rest.RestFilterChain;
import org.elasticsearch.rest.RestRequest;
import org.elasticsearch.xpack.security.authc.Authentication;
import org.elasticsearch.xpack.security.authc.AuthenticationService;
import org.elasticsearch.xpack.security.SecurityLicenseState;
import org.elasticsearch.test.ESTestCase;
import org.elasticsearch.threadpool.ThreadPool;
import org.elasticsearch.xpack.security.authc.AuthenticationService;
import org.junit.Before;
import static org.elasticsearch.xpack.security.support.Exceptions.authenticationError;

View File

@ -17,7 +17,7 @@ import org.elasticsearch.test.SecurityIntegTestCase;
import org.elasticsearch.test.SecuritySettingsSource;
import org.elasticsearch.test.rest.ObjectPath;
import org.elasticsearch.xpack.security.authc.support.SecuredString;
import org.elasticsearch.xpack.security.authz.InternalAuthorizationService;
import org.elasticsearch.xpack.security.authz.AuthorizationService;
import org.elasticsearch.xpack.security.user.AnonymousUser;
import org.junit.BeforeClass;
@ -46,7 +46,7 @@ public class RestAuthenticateActionTests extends SecurityIntegTestCase {
if (anonymousEnabled) {
builder.put(AnonymousUser.USERNAME_SETTING.getKey(), "anon")
.putArray(AnonymousUser.ROLES_SETTING.getKey(), SecuritySettingsSource.DEFAULT_ROLE, "foo")
.put(InternalAuthorizationService.ANONYMOUS_AUTHORIZATION_EXCEPTION_SETTING.getKey(), false);
.put(AuthorizationService.ANONYMOUS_AUTHORIZATION_EXCEPTION_SETTING.getKey(), false);
}
return builder.build();
}

View File

@ -1,278 +0,0 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License;
* you may not use this file except in compliance with the Elastic License.
*/
package org.elasticsearch.xpack.security.support;
import org.elasticsearch.ElasticsearchSecurityException;
import org.elasticsearch.common.logging.ESLogger;
import org.elasticsearch.common.unit.TimeValue;
import org.elasticsearch.common.util.concurrent.AbstractRunnable;
import org.elasticsearch.test.ESTestCase;
import org.elasticsearch.threadpool.TestThreadPool;
import org.elasticsearch.threadpool.ThreadPool;
import org.elasticsearch.threadpool.ThreadPool.Names;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ScheduledFuture;
import java.util.concurrent.ScheduledThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;
import static org.hamcrest.Matchers.is;
import static org.hamcrest.Matchers.containsString;
import static org.hamcrest.Matchers.notNullValue;
import static org.hamcrest.Matchers.nullValue;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.verifyZeroInteractions;
import static org.mockito.Mockito.when;
public class SelfReschedulingRunnableTests extends ESTestCase {
public void testSelfReschedulingRunnableReschedules() throws Exception {
final ThreadPool threadPool = mock(ThreadPool.class);
final AbstractRunnable runnable = mock(AbstractRunnable.class);
final ESLogger logger = mock(ESLogger.class);
final TimeValue timeValue = TimeValue.timeValueMillis(1L);
final String name = Names.GENERIC;
SelfReschedulingRunnable reschedulingRunnable = new SelfReschedulingRunnable(runnable, threadPool, timeValue, name, logger);
reschedulingRunnable.start();
final int iterations = randomIntBetween(4, 24);
for (int i = 0; i < iterations; i++) {
// pretend we are the scheduler running it
reschedulingRunnable.run();
}
verify(threadPool, times(iterations + 1)).schedule(timeValue, name, reschedulingRunnable);
verifyZeroInteractions(logger);
}
public void testThrowingRunnableReschedules() throws Exception {
final ThreadPool threadPool = mock(ThreadPool.class);
final AbstractRunnable runnable = new AbstractRunnable() {
@Override
public void onFailure(Exception throwable) {
}
@Override
protected void doRun() throws Exception {
throw randomFrom(new UnsupportedOperationException(),
new ElasticsearchSecurityException(""),
new IllegalArgumentException(),
new NullPointerException());
}
};
final ESLogger logger = mock(ESLogger.class);
final TimeValue timeValue = TimeValue.timeValueMillis(1L);
final String name = Names.GENERIC;
SelfReschedulingRunnable reschedulingRunnable = new SelfReschedulingRunnable(runnable, threadPool, timeValue, name, logger);
reschedulingRunnable.start();
final int iterations = randomIntBetween(4, 24);
for (int i = 0; i < iterations; i++) {
// pretend we are the scheduler running it
reschedulingRunnable.run();
}
verify(threadPool, times(iterations + 1)).schedule(timeValue, name, reschedulingRunnable);
verifyZeroInteractions(logger);
}
public void testDoesNotRescheduleUntilExecutionFinished() throws Exception {
final ThreadPool threadPool = mock(ThreadPool.class);
final CountDownLatch startLatch = new CountDownLatch(1);
final CountDownLatch pauseLatch = new CountDownLatch(1);
final AbstractRunnable runnable = new AbstractRunnable() {
@Override
public void onFailure(Exception throwable) {
}
@Override
protected void doRun() throws Exception {
startLatch.countDown();
pauseLatch.await();
}
};
final ESLogger logger = mock(ESLogger.class);
final TimeValue timeValue = TimeValue.timeValueMillis(1L);
final String name = Names.GENERIC;
final SelfReschedulingRunnable reschedulingRunnable = new SelfReschedulingRunnable(runnable, threadPool, timeValue, name, logger);
reschedulingRunnable.start();
verify(threadPool).schedule(timeValue, name, reschedulingRunnable);
Thread thread = new Thread() {
@Override
public void run() {
reschedulingRunnable.run();
}
};
thread.start();
startLatch.await();
verify(threadPool).schedule(timeValue, name, reschedulingRunnable);
pauseLatch.countDown();
thread.join();
verify(threadPool, times(2)).schedule(timeValue, name, reschedulingRunnable);
}
public void testStopCancelsScheduledFuture() {
final ThreadPool threadPool = mock(ThreadPool.class);
final ScheduledFuture future = mock(ScheduledFuture.class);
final AbstractRunnable runnable = mock(AbstractRunnable.class);
final ESLogger logger = mock(ESLogger.class);
final TimeValue timeValue = TimeValue.timeValueMillis(1L);
final String name = Names.GENERIC;
SelfReschedulingRunnable reschedulingRunnable = new SelfReschedulingRunnable(runnable, threadPool, timeValue, name, logger);
when(threadPool.schedule(timeValue, name, reschedulingRunnable)).thenReturn(future);
reschedulingRunnable.start();
reschedulingRunnable.run();
reschedulingRunnable.stop();
verify(threadPool, times(2)).schedule(timeValue, name, reschedulingRunnable);
verify(future).cancel(false);
}
public void testDoubleStartThrowsException() {
final ThreadPool threadPool = mock(ThreadPool.class);
final AbstractRunnable runnable = mock(AbstractRunnable.class);
final ESLogger logger = mock(ESLogger.class);
final TimeValue timeValue = TimeValue.timeValueMillis(1L);
final String name = Names.GENERIC;
SelfReschedulingRunnable reschedulingRunnable = new SelfReschedulingRunnable(runnable, threadPool, timeValue, name, logger);
reschedulingRunnable.start();
try {
reschedulingRunnable.start();
fail("calling start before stopping is not allowed");
} catch (IllegalStateException e) {
assertThat(e.getMessage(), containsString("start should not be called again"));
}
}
public void testDoubleStopThrowsException() {
final ThreadPool threadPool = mock(ThreadPool.class);
final AbstractRunnable runnable = mock(AbstractRunnable.class);
final ESLogger logger = mock(ESLogger.class);
final TimeValue timeValue = TimeValue.timeValueMillis(1L);
final String name = Names.GENERIC;
SelfReschedulingRunnable reschedulingRunnable = new SelfReschedulingRunnable(runnable, threadPool, timeValue, name, logger);
reschedulingRunnable.start();
reschedulingRunnable.stop();
try {
reschedulingRunnable.stop();
fail("calling stop while not running is not allowed");
} catch (IllegalStateException e) {
assertThat(e.getMessage(), containsString("stop called but not started or stop called twice"));
}
}
public void testStopWithoutStartThrowsException() {
final ThreadPool threadPool = mock(ThreadPool.class);
final AbstractRunnable runnable = mock(AbstractRunnable.class);
final ESLogger logger = mock(ESLogger.class);
final TimeValue timeValue = TimeValue.timeValueMillis(1L);
final String name = Names.GENERIC;
SelfReschedulingRunnable reschedulingRunnable = new SelfReschedulingRunnable(runnable, threadPool, timeValue, name, logger);
try {
reschedulingRunnable.stop();
fail("calling stop while not running is not allowed");
} catch (IllegalStateException e) {
assertThat(e.getMessage(), containsString("stop called but not started or stop called twice"));
}
}
public void testStopPreventsRunning() throws Exception {
final ThreadPool threadPool = new TestThreadPool("test-stop-self-schedule");
final AtomicInteger failureCounter = new AtomicInteger(0);
final AtomicInteger runCounter = new AtomicInteger(0);
final AbstractRunnable runnable = new AbstractRunnable() {
@Override
public void onFailure(Exception throwable) {
failureCounter.incrementAndGet();
}
@Override
protected void doRun() throws Exception {
runCounter.incrementAndGet();
}
};
final ESLogger logger = mock(ESLogger.class);
// arbitrary run time
final TimeValue timeValue = TimeValue.timeValueSeconds(2L);
final String name = Names.GENERIC;
try {
SelfReschedulingRunnable reschedulingRunnable = new SelfReschedulingRunnable(runnable, threadPool, timeValue, name, logger);
reschedulingRunnable.start();
ScheduledFuture future = reschedulingRunnable.getScheduledFuture();
assertThat(future, notNullValue());
assertThat(future.isDone(), is(false));
assertThat(future.isCancelled(), is(false));
reschedulingRunnable.stop();
assertThat(reschedulingRunnable.getScheduledFuture(), nullValue());
assertThat(future.isCancelled(), is(true));
assertThat(future.isDone(), is(true));
boolean ran = awaitBusy(() -> runCounter.get() > 0 || failureCounter.get() > 0, 3L, TimeUnit.SECONDS);
assertThat(ran, is(false));
} finally {
threadPool.shutdownNow();
}
}
public void testStopPreventsRescheduling() throws Exception {
final ThreadPool threadPool = new TestThreadPool("test-stop-self-schedule");
final CountDownLatch threadRunningLatch = new CountDownLatch(randomIntBetween(1, 16));
final CountDownLatch stopCalledLatch = new CountDownLatch(1);
final AbstractRunnable runnable = new AbstractRunnable() {
@Override
public void onFailure(Exception throwable) {
throw new IllegalStateException("we should never be in this method!");
}
@Override
protected void doRun() throws Exception {
// notify we are running
threadRunningLatch.countDown();
if (threadRunningLatch.getCount() > 0) {
// let it keep running
return;
}
stopCalledLatch.await();
}
};
final ESLogger logger = mock(ESLogger.class);
final TimeValue timeValue = TimeValue.timeValueMillis(1L);
final String name = Names.GENERIC;
try {
SelfReschedulingRunnable reschedulingRunnable = new SelfReschedulingRunnable(runnable, threadPool, timeValue, name, logger);
reschedulingRunnable.start();
threadRunningLatch.await();
// call stop
reschedulingRunnable.stop();
stopCalledLatch.countDown();
assertThat(reschedulingRunnable.getScheduledFuture(), nullValue());
final ScheduledThreadPoolExecutor scheduledThreadPooleExecutor = (ScheduledThreadPoolExecutor) threadPool.scheduler();
boolean somethingQueued = awaitBusy(() -> scheduledThreadPooleExecutor.getQueue().isEmpty() == false, 1L, TimeUnit.SECONDS);
assertThat(somethingQueued, is(false));
} finally {
threadPool.shutdownNow();
}
}
}

View File

@ -5,8 +5,8 @@
*/
package org.elasticsearch.xpack.security.transport;
import org.elasticsearch.xpack.security.user.SystemUser;
import org.elasticsearch.xpack.security.authc.AuthenticationService;
import org.elasticsearch.xpack.security.user.SystemUser;
import org.elasticsearch.test.ESTestCase;
import org.elasticsearch.transport.TransportRequest;
import org.junit.Before;

View File

@ -11,11 +11,11 @@ import org.elasticsearch.common.util.concurrent.ThreadContext;
import org.elasticsearch.transport.TransportChannel;
import org.elasticsearch.xpack.security.authc.Authentication;
import org.elasticsearch.xpack.security.action.SecurityActionMapper;
import org.elasticsearch.xpack.security.authc.AuthenticationService;
import org.elasticsearch.xpack.security.authz.AuthorizationService;
import org.elasticsearch.test.ESTestCase;
import org.elasticsearch.transport.TransportRequest;
import org.elasticsearch.transport.TransportSettings;
import org.elasticsearch.xpack.security.authc.AuthenticationService;
import org.elasticsearch.xpack.security.authz.AuthorizationService;
import org.junit.Before;
import static org.elasticsearch.xpack.security.support.Exceptions.authenticationError;

View File

@ -17,8 +17,6 @@ import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.plugins.Plugin;
import org.elasticsearch.transport.MockTcpTransportPlugin;
import org.elasticsearch.xpack.security.action.SecurityActionMapper;
import org.elasticsearch.xpack.security.authc.AuthenticationService;
import org.elasticsearch.xpack.security.authz.AuthorizationService;
import org.elasticsearch.xpack.security.SecurityLicenseState;
import org.elasticsearch.test.ESIntegTestCase;
import org.elasticsearch.test.ESIntegTestCase.ClusterScope;
@ -32,6 +30,8 @@ import org.elasticsearch.transport.TransportResponse;
import org.elasticsearch.transport.TransportResponseHandler;
import org.elasticsearch.transport.TransportService;
import org.elasticsearch.transport.TransportSettings;
import org.elasticsearch.xpack.security.authc.AuthenticationService;
import org.elasticsearch.xpack.security.authz.AuthorizationService;
import org.mockito.InOrder;
import java.io.IOException;

View File

@ -20,6 +20,7 @@ import org.elasticsearch.test.ESTestCase;
import org.elasticsearch.test.junit.annotations.Network;
import org.elasticsearch.transport.Transport;
import org.elasticsearch.transport.TransportSettings;
import org.elasticsearch.xpack.security.audit.AuditTrailService;
import org.junit.Before;
import org.mockito.ArgumentCaptor;
@ -45,7 +46,7 @@ import static org.mockito.Mockito.when;
public class IPFilterTests extends ESTestCase {
private IPFilter ipFilter;
private SecurityLicenseState licenseState;
private AuditTrail auditTrail;
private AuditTrailService auditTrail;
private Transport transport;
private HttpServerTransport httpTransport;
private ClusterSettings clusterSettings;
@ -54,7 +55,7 @@ public class IPFilterTests extends ESTestCase {
public void init() {
licenseState = mock(SecurityLicenseState.class);
when(licenseState.ipFilteringEnabled()).thenReturn(true);
auditTrail = mock(AuditTrail.class);
auditTrail = mock(AuditTrailService.class);
clusterSettings = new ClusterSettings(Settings.EMPTY, new HashSet<>(Arrays.asList(
IPFilter.HTTP_FILTER_ALLOW_SETTING,
IPFilter.HTTP_FILTER_DENY_SETTING,

View File

@ -15,6 +15,7 @@ import org.elasticsearch.common.transport.TransportAddress;
import org.elasticsearch.http.HttpServerTransport;
import org.elasticsearch.xpack.security.audit.AuditTrail;
import org.elasticsearch.xpack.security.SecurityLicenseState;
import org.elasticsearch.xpack.security.audit.AuditTrailService;
import org.elasticsearch.xpack.security.transport.filter.IPFilter;
import org.elasticsearch.test.ESTestCase;
import org.elasticsearch.transport.Transport;
@ -34,6 +35,7 @@ import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.net.SocketAddress;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashSet;
@ -67,7 +69,8 @@ public class IPFilterNetty3UpstreamHandlerTests extends ESTestCase {
TransportSettings.TRANSPORT_PROFILES_SETTING)));
SecurityLicenseState licenseState = mock(SecurityLicenseState.class);
when(licenseState.ipFilteringEnabled()).thenReturn(true);
IPFilter ipFilter = new IPFilter(settings, AuditTrail.NOOP, clusterSettings, licenseState);
AuditTrailService auditTrailService = new AuditTrailService(settings, Collections.emptyList(), licenseState);
IPFilter ipFilter = new IPFilter(settings, auditTrailService, clusterSettings, licenseState);
ipFilter.setBoundTransportAddress(transport.boundAddress(), transport.profileBoundAddresses());
if (isHttpEnabled) {
HttpServerTransport httpTransport = mock(HttpServerTransport.class);

View File

@ -11,7 +11,7 @@ import org.elasticsearch.client.ResponseException;
import org.elasticsearch.common.network.NetworkModule;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.test.SecurityIntegTestCase;
import org.elasticsearch.xpack.security.authz.InternalAuthorizationService;
import org.elasticsearch.xpack.security.authz.AuthorizationService;
import static org.hamcrest.Matchers.containsString;
import static org.hamcrest.Matchers.is;
@ -27,7 +27,7 @@ public class AnonymousUserIntegTests extends SecurityIntegTestCase {
.put(super.nodeSettings(nodeOrdinal))
.put(NetworkModule.HTTP_ENABLED.getKey(), true)
.put(AnonymousUser.ROLES_SETTING.getKey(), "anonymous")
.put(InternalAuthorizationService.ANONYMOUS_AUTHORIZATION_EXCEPTION_SETTING.getKey(), authorizationExceptionsEnabled)
.put(AuthorizationService.ANONYMOUS_AUTHORIZATION_EXCEPTION_SETTING.getKey(), authorizationExceptionsEnabled)
.build();
}

View File

@ -1,18 +0,0 @@
# Licensed to Elasticsearch under one or more contributor
# license agreements. See the NOTICE file distributed with
# this work for additional information regarding copyright
# ownership. Elasticsearch licenses this file to you under
# the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing,
# software distributed under the License is distributed on
# an 'AS IS' BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
# either express or implied. See the License for the specific
# language governing permissions and limitations under the License.
@defaultMessage reschedule yourself using #schedule if you are using blocking code in runnable
org.elasticsearch.threadpool.ThreadPool#scheduleWithFixedDelay(java.lang.Runnable, org.elasticsearch.common.unit.TimeValue)

View File

@ -69,8 +69,7 @@ import org.elasticsearch.xpack.rest.action.RestXPackInfoAction;
import org.elasticsearch.xpack.rest.action.RestXPackUsageAction;
import org.elasticsearch.xpack.security.InternalClient;
import org.elasticsearch.xpack.security.Security;
import org.elasticsearch.xpack.security.authc.AuthenticationModule;
import org.elasticsearch.xpack.security.authc.InternalAuthenticationService;
import org.elasticsearch.xpack.security.authc.AuthenticationService;
import org.elasticsearch.xpack.security.authc.support.UsernamePasswordToken;
import org.elasticsearch.xpack.support.clock.Clock;
import org.elasticsearch.xpack.support.clock.SystemClock;
@ -180,7 +179,6 @@ public class XPackPlugin extends Plugin implements ScriptPlugin, ActionPlugin, I
public Collection<Class<? extends LifecycleComponent>> getGuiceServiceClasses() {
ArrayList<Class<? extends LifecycleComponent>> services = new ArrayList<>();
services.addAll(notification.nodeServices());
services.addAll(security.nodeServices());
services.addAll(monitoring.nodeServices());
return services;
}
@ -223,8 +221,8 @@ public class XPackPlugin extends Plugin implements ScriptPlugin, ActionPlugin, I
}
Set<String> headers = new HashSet<>();
headers.add(UsernamePasswordToken.BASIC_AUTH_HEADER);
if (InternalAuthenticationService.RUN_AS_ENABLED.get(settings)) {
headers.add(InternalAuthenticationService.RUN_AS_USER_HEADER);
if (AuthenticationService.RUN_AS_ENABLED.get(settings)) {
headers.add(AuthenticationService.RUN_AS_USER_HEADER);
}
headers.addAll(extensionsService.getExtensions().stream()
.flatMap(e -> e.getRestHeaders().stream()).collect(Collectors.toList()));
@ -315,12 +313,6 @@ public class XPackPlugin extends Plugin implements ScriptPlugin, ActionPlugin, I
return security.getProcessors(parameters);
}
public void onModule(AuthenticationModule module) {
if (extensionsService != null) {
extensionsService.onModule(module);
}
}
public void onIndexModule(IndexModule module) {
security.onIndexModule(module);
}

View File

@ -16,6 +16,9 @@ import java.io.IOException;
import java.nio.file.DirectoryStream;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import static org.elasticsearch.cli.Terminal.Verbosity.VERBOSE;
@ -36,13 +39,20 @@ class ListXPackExtensionCommand extends SettingCommand {
if (Files.exists(resolveXPackExtensionsFile(env)) == false) {
throw new IOException("Extensions directory missing: " + resolveXPackExtensionsFile(env));
}
terminal.println(VERBOSE, "Extensions directory: " + resolveXPackExtensionsFile(env));
try (DirectoryStream<Path> stream = Files.newDirectoryStream(resolveXPackExtensionsFile(env))) {
for (Path extension : stream) {
terminal.println(extension.getFileName().toString());
terminal.println(VERBOSE, "XPack Extensions directory: " + resolveXPackExtensionsFile(env));
final List<Path> extensions = new ArrayList<>();
try (DirectoryStream<Path> paths = Files.newDirectoryStream(resolveXPackExtensionsFile(env))) {
for (Path extension : paths) {
extensions.add(extension);
}
}
Collections.sort(extensions);
for (final Path extension : extensions) {
terminal.println(extension.getFileName().toString());
XPackExtensionInfo info =
XPackExtensionInfo.readFromProperties(extension);
terminal.println(VERBOSE, info.toString());
}
}
}

View File

@ -9,9 +9,7 @@ import java.util.Collection;
import java.util.Collections;
import java.util.Map;
import org.elasticsearch.watcher.ResourceWatcherService;
import org.elasticsearch.xpack.security.authc.AuthenticationFailureHandler;
import org.elasticsearch.xpack.security.authc.AuthenticationModule;
import org.elasticsearch.xpack.security.authc.Realm;
@ -29,11 +27,6 @@ public abstract class XPackExtension {
*/
public abstract String description();
/**
* Implement this function to register custom extensions in the authentication module.
*/
public void onModule(AuthenticationModule module) {}
/**
* Returns headers which should be copied from REST requests to internal cluster requests.
*/
@ -41,7 +34,6 @@ public abstract class XPackExtension {
return Collections.emptyList();
}
/**
* Returns authentication realm implementations added by this extension.
*
@ -52,4 +44,14 @@ public abstract class XPackExtension {
public Map<String, Realm.Factory> getRealms() {
return Collections.emptyMap();
}
/**
* Returns a handler for authentication failures, or null to use the default handler.
*
* Only one installed extension may have an authentication failure handler. If more than
* one extension returns a non-null handler, an error is raised.
*/
public AuthenticationFailureHandler getAuthenticationFailureHandler() {
return null;
}
}

View File

@ -12,7 +12,6 @@ import org.elasticsearch.common.io.FileSystemUtils;
import org.elasticsearch.common.logging.ESLogger;
import org.elasticsearch.common.logging.Loggers;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.xpack.security.authc.AuthenticationModule;
import java.io.IOException;
import java.net.URL;
@ -74,12 +73,6 @@ public class XPackExtensionsService {
extensions = Collections.unmodifiableList(extensionsLoaded);
}
public void onModule(AuthenticationModule module) {
for (Tuple<XPackExtensionInfo, XPackExtension> tuple : extensions) {
tuple.v2().onModule(module);
}
}
public List<XPackExtension> getExtensions() {
return extensions.stream().map(Tuple::v2).collect(Collectors.toList());
}

View File

@ -6,6 +6,7 @@
package org.elasticsearch.xpack.extensions;
import org.apache.lucene.util.LuceneTestCase;
import org.elasticsearch.Version;
import org.elasticsearch.cli.ExitCodes;
import org.elasticsearch.cli.MockTerminal;
import org.elasticsearch.common.settings.Settings;
@ -15,23 +16,44 @@ import org.junit.Before;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.NoSuchFileException;
import java.nio.file.Path;
import java.util.Arrays;
import java.util.stream.Collectors;
@LuceneTestCase.SuppressFileSystems("*")
public class ListXPackExtensionCommandTests extends ESTestCase {
private Path home;
private Environment env;
@Before
public void setUp() throws Exception {
super.setUp();
home = createTempDir();
Settings settings = Settings.builder()
.put("path.home", home)
.build();
env = new Environment(settings);
Files.createDirectories(extensionsFile(env));
}
private static Path createExtensionDir(final Path home) throws IOException {
final Environment env = new Environment(Settings.builder().put("path.home", home.toString()).build());
final Path path = env.pluginsFile().resolve("x-pack").resolve("extensions");
return Files.createDirectories(path);
static String buildMultiline(String... args){
return Arrays.asList(args).stream().collect(Collectors.joining("\n", "", "\n"));
}
static void buildFakeExtension(Environment env, String description, String name, String className) throws IOException {
XPackExtensionTestUtil.writeProperties(extensionsFile(env).resolve(name),
"description", description,
"name", name,
"version", "1.0",
"xpack.version", Version.CURRENT.toString(),
"java.version", System.getProperty("java.specification.version"),
"classname", className);
}
static Path extensionsFile(final Environment env) throws IOException {
return env.pluginsFile().resolve("x-pack").resolve("extensions");
}
static MockTerminal listExtensions(Path home) throws Exception {
@ -41,34 +63,88 @@ public class ListXPackExtensionCommandTests extends ESTestCase {
return terminal;
}
static MockTerminal listExtensions(Path home, String[] args) throws Exception {
String[] argsAndHome = new String[args.length + 1];
System.arraycopy(args, 0, argsAndHome, 0, args.length);
argsAndHome[args.length] = "-Epath.home=" + home;
MockTerminal terminal = new MockTerminal();
int status = new ListXPackExtensionCommand().main(argsAndHome, terminal);
assertEquals(ExitCodes.OK, status);
return terminal;
}
public void testExtensionsDirMissing() throws Exception {
Path extDir = createExtensionDir(home);
Files.delete(extDir);
Files.delete(extensionsFile(env));
IOException e = expectThrows(IOException.class, () -> listExtensions(home));
assertTrue(e.getMessage(), e.getMessage().contains("Extensions directory missing"));
}
public void testNoExtensions() throws Exception {
createExtensionDir(home);
MockTerminal terminal = listExtensions(home);
assertTrue(terminal.getOutput(), terminal.getOutput().isEmpty());
}
public void testNoExtensionsVerbose() throws Exception {
String[] params = { "-v" };
MockTerminal terminal = listExtensions(home, params);
assertEquals(terminal.getOutput(), buildMultiline("XPack Extensions directory: " + extensionsFile(env)));
}
public void testOneExtension() throws Exception {
Path extDir = createExtensionDir(home);
Files.createDirectory(extDir.resolve("fake"));
buildFakeExtension(env, "", "fake", "org.fake");
MockTerminal terminal = listExtensions(home);
assertTrue(terminal.getOutput(), terminal.getOutput().contains("fake"));
assertEquals(terminal.getOutput(), buildMultiline("fake"));
}
public void testTwoExtensions() throws Exception {
Path extDir = createExtensionDir(home);
Files.createDirectory(extDir.resolve("fake1"));
Files.createDirectory(extDir.resolve("fake2"));
buildFakeExtension(env, "", "fake1", "org.fake1");
buildFakeExtension(env, "", "fake2", "org.fake2");
MockTerminal terminal = listExtensions(home);
String output = terminal.getOutput();
assertTrue(output, output.contains("fake1"));
assertTrue(output, output.contains("fake2"));
assertEquals(terminal.getOutput(), buildMultiline("fake1", "fake2"));
}
public void testExtensionWithVerbose() throws Exception {
buildFakeExtension(env, "fake desc", "fake_extension", "org.fake");
String[] params = { "-v" };
MockTerminal terminal = listExtensions(home, params);
assertEquals(terminal.getOutput(), buildMultiline("XPack Extensions directory: " + extensionsFile(env),
"fake_extension", "- XPack Extension information:", "Name: fake_extension",
"Description: fake desc", "Version: 1.0", " * Classname: org.fake"));
}
public void testExtensionWithVerboseMultipleExtensions() throws Exception {
buildFakeExtension(env, "fake desc 1", "fake_extension1", "org.fake");
buildFakeExtension(env, "fake desc 2", "fake_extension2", "org.fake2");
String[] params = { "-v" };
MockTerminal terminal = listExtensions(home, params);
assertEquals(terminal.getOutput(), buildMultiline("XPack Extensions directory: " + extensionsFile(env),
"fake_extension1", "- XPack Extension information:", "Name: fake_extension1",
"Description: fake desc 1", "Version: 1.0", " * Classname: org.fake",
"fake_extension2", "- XPack Extension information:", "Name: fake_extension2",
"Description: fake desc 2", "Version: 1.0", " * Classname: org.fake2"));
}
public void testExtensionWithoutVerboseMultipleExtensions() throws Exception {
buildFakeExtension(env, "fake desc 1", "fake_extension1", "org.fake");
buildFakeExtension(env, "fake desc 2", "fake_extension2", "org.fake2");
MockTerminal terminal = listExtensions(home, new String[0]);
String output = terminal.getOutput();
assertEquals(output, buildMultiline("fake_extension1", "fake_extension2"));
}
public void testExtensionWithoutDescriptorFile() throws Exception{
Files.createDirectories(extensionsFile(env).resolve("fake1"));
NoSuchFileException e = expectThrows(NoSuchFileException.class, () -> listExtensions(home));
assertEquals(e.getFile(),
extensionsFile(env).resolve("fake1").resolve(XPackExtensionInfo.XPACK_EXTENSION_PROPERTIES).toString());
}
public void testExtensionWithWrongDescriptorFile() throws Exception{
XPackExtensionTestUtil.writeProperties(extensionsFile(env).resolve("fake1"),
"description", "fake desc");
IllegalArgumentException e = expectThrows(IllegalArgumentException.class, () -> listExtensions(home));
assertEquals(e.getMessage(), "Property [name] is missing in [" +
extensionsFile(env).resolve("fake1")
.resolve(XPackExtensionInfo.XPACK_EXTENSION_PROPERTIES).toString() + "]");
}
}

View File

@ -11,7 +11,6 @@ import org.elasticsearch.client.Client;
import org.elasticsearch.cluster.metadata.MetaData;
import org.elasticsearch.common.Booleans;
import org.elasticsearch.common.Strings;
import org.elasticsearch.common.component.LifecycleComponent;
import org.elasticsearch.common.inject.Module;
import org.elasticsearch.common.logging.ESLogger;
import org.elasticsearch.common.logging.LoggerMessageFormat;
@ -32,6 +31,7 @@ import org.elasticsearch.xpack.watcher.condition.ConditionModule;
import org.elasticsearch.xpack.watcher.execution.ExecutionModule;
import org.elasticsearch.xpack.watcher.execution.ExecutionService;
import org.elasticsearch.xpack.watcher.execution.InternalWatchExecutor;
import org.elasticsearch.xpack.watcher.execution.TriggeredWatchStore;
import org.elasticsearch.xpack.watcher.history.HistoryModule;
import org.elasticsearch.xpack.watcher.history.HistoryStore;
import org.elasticsearch.xpack.watcher.input.InputModule;
@ -66,6 +66,7 @@ import org.elasticsearch.xpack.watcher.transport.actions.stats.WatcherStatsActio
import org.elasticsearch.xpack.watcher.trigger.TriggerModule;
import org.elasticsearch.xpack.watcher.trigger.schedule.ScheduleModule;
import org.elasticsearch.xpack.watcher.watch.WatchModule;
import org.elasticsearch.xpack.watcher.watch.WatchStore;
import org.joda.time.DateTime;
import org.joda.time.DateTimeZone;
@ -216,7 +217,7 @@ public class Watcher implements ActionPlugin {
String errorMessage = LoggerMessageFormat.format("the [action.auto_create_index] setting value [{}] is too" +
" restrictive. disable [action.auto_create_index] or set it to " +
"[.watches,.triggered_watches,.watcher-history*]", (Object) value);
"[{}, {}, {}*]", (Object) value, WatchStore.INDEX, TriggeredWatchStore.INDEX_NAME, HistoryStore.INDEX_PREFIX);
if (Booleans.isExplicitFalse(value)) {
throw new IllegalArgumentException(errorMessage);
}

View File

@ -32,7 +32,8 @@ import static org.elasticsearch.xpack.watcher.support.Exceptions.ioException;
*/
public class HistoryStore extends AbstractComponent {
public static final String INDEX_PREFIX = ".watcher-history-" + WatcherIndexTemplateRegistry.INDEX_TEMPLATE_VERSION + "-";
public static final String INDEX_PREFIX = ".watcher-history-";
public static final String INDEX_PREFIX_WITH_TEMPLATE = INDEX_PREFIX + WatcherIndexTemplateRegistry.INDEX_TEMPLATE_VERSION + "-";
public static final String DOC_TYPE = "watch_record";
static final DateTimeFormatter indexTimeFormat = DateTimeFormat.forPattern("YYYY.MM.dd");
@ -123,7 +124,7 @@ public class HistoryStore extends AbstractComponent {
* Calculates the correct history index name for a given time
*/
public static String getHistoryIndexNameForTime(DateTime time) {
return INDEX_PREFIX + indexTimeFormat.print(time);
return INDEX_PREFIX_WITH_TEMPLATE + indexTimeFormat.print(time);
}
}

View File

@ -15,34 +15,27 @@ public class WatcherPluginTests extends ESTestCase {
public void testValidAutoCreateIndex() {
Watcher.validAutoCreateIndex(Settings.EMPTY);
Watcher.validAutoCreateIndex(Settings.builder().put("action.auto_create_index", true).build());
try {
Watcher.validAutoCreateIndex(Settings.builder().put("action.auto_create_index", false).build());
fail("IllegalArgumentException expected");
} catch (IllegalArgumentException e) {
assertThat(e.getMessage(), containsString("[.watches,.triggered_watches,.watcher-history*]"));
}
IllegalArgumentException exception = expectThrows(IllegalArgumentException.class,
() -> Watcher.validAutoCreateIndex(Settings.builder().put("action.auto_create_index", false).build()));
assertThat(exception.getMessage(), containsString("[.watches, .triggered_watches, .watcher-history-*]"));
Watcher.validAutoCreateIndex(Settings.builder().put("action.auto_create_index",
".watches,.triggered_watches,.watcher-history*").build());
Watcher.validAutoCreateIndex(Settings.builder().put("action.auto_create_index", "*w*").build());
Watcher.validAutoCreateIndex(Settings.builder().put("action.auto_create_index", ".w*,.t*").build());
try {
Watcher.validAutoCreateIndex(Settings.builder().put("action.auto_create_index", ".watches").build());
fail("IllegalArgumentException expected");
} catch (IllegalArgumentException e) {
assertThat(e.getMessage(), containsString("[.watches,.triggered_watches,.watcher-history*]"));
}
try {
Watcher.validAutoCreateIndex(Settings.builder().put("action.auto_create_index", ".triggered_watch").build());
fail("IllegalArgumentException expected");
} catch (IllegalArgumentException e) {
assertThat(e.getMessage(), containsString("[.watches,.triggered_watches,.watcher-history*]"));
}
try {
Watcher.validAutoCreateIndex(Settings.builder().put("action.auto_create_index", ".watcher-history*").build());
fail("IllegalArgumentException expected");
} catch (IllegalArgumentException e) {
assertThat(e.getMessage(), containsString("[.watches,.triggered_watches,.watcher-history*]"));
}
exception = expectThrows(IllegalArgumentException.class,
() -> Watcher.validAutoCreateIndex(Settings.builder().put("action.auto_create_index", ".watches").build()));
assertThat(exception.getMessage(), containsString("[.watches, .triggered_watches, .watcher-history-*]"));
exception = expectThrows(IllegalArgumentException.class,
() -> Watcher.validAutoCreateIndex(Settings.builder().put("action.auto_create_index", ".triggered_watch").build()));
assertThat(exception.getMessage(), containsString("[.watches, .triggered_watches, .watcher-history-*]"));
exception = expectThrows(IllegalArgumentException.class,
() -> Watcher.validAutoCreateIndex(Settings.builder().put("action.auto_create_index", ".watcher-history-*").build()));
assertThat(exception.getMessage(), containsString("[.watches, .triggered_watches, .watcher-history-*]"));
}
}

View File

@ -95,7 +95,7 @@ public class TimeThrottleIntegrationTests extends AbstractWatcherIntegrationTest
actionsCount = docCount("actions", "action", matchAllQuery());
assertThat(actionsCount, is(2L));
long throttledCount = docCount(HistoryStore.INDEX_PREFIX + "*", null,
long throttledCount = docCount(HistoryStore.INDEX_PREFIX_WITH_TEMPLATE + "*", null,
matchQuery(WatchRecord.Field.STATE.getPreferredName(), ExecutionState.THROTTLED.id()));
assertThat(throttledCount, is(1L));
@ -119,7 +119,7 @@ public class TimeThrottleIntegrationTests extends AbstractWatcherIntegrationTest
long actionsCount = docCount("actions", "action", matchAllQuery());
assertThat(actionsCount, is(1L));
long throttledCount = docCount(HistoryStore.INDEX_PREFIX + "*", null,
long throttledCount = docCount(HistoryStore.INDEX_PREFIX_WITH_TEMPLATE + "*", null,
matchQuery(WatchRecord.Field.STATE.getPreferredName(), ExecutionState.THROTTLED.id()));
assertThat(throttledCount, greaterThanOrEqualTo(1L));
}
@ -168,7 +168,7 @@ public class TimeThrottleIntegrationTests extends AbstractWatcherIntegrationTest
actionsCount = docCount("actions", "action", matchAllQuery());
assertThat(actionsCount, is(2L));
long throttledCount = docCount(HistoryStore.INDEX_PREFIX + "*", null,
long throttledCount = docCount(HistoryStore.INDEX_PREFIX_WITH_TEMPLATE + "*", null,
matchQuery(WatchRecord.Field.STATE.getPreferredName(), ExecutionState.THROTTLED.id()));
assertThat(throttledCount, is(1L));
}

View File

@ -135,7 +135,7 @@ public class IndexActionIntegrationTests extends AbstractWatcherIntegrationTestC
assertThat(client().admin().indices().prepareExists("idx").get().isExists(), is(false));
assertThat(docCount(HistoryStore.INDEX_PREFIX + "*", HistoryStore.DOC_TYPE, searchSource()
assertThat(docCount(HistoryStore.INDEX_PREFIX_WITH_TEMPLATE + "*", HistoryStore.DOC_TYPE, searchSource()
.query(matchQuery("result.actions.status", "failure"))), is(1L));
}

View File

@ -109,13 +109,13 @@ public class ManualExecutionTests extends AbstractWatcherIntegrationTestCase {
ManualExecutionContext ctx = ctxBuilder.build();
refresh();
long oldRecordCount = docCount(HistoryStore.INDEX_PREFIX + "*", HistoryStore.DOC_TYPE, matchAllQuery());
long oldRecordCount = docCount(HistoryStore.INDEX_PREFIX_WITH_TEMPLATE + "*", HistoryStore.DOC_TYPE, matchAllQuery());
WatchRecord watchRecord = executionService().execute(ctx);
refresh();
long newRecordCount = docCount(HistoryStore.INDEX_PREFIX + "*", HistoryStore.DOC_TYPE, matchAllQuery());
long newRecordCount = docCount(HistoryStore.INDEX_PREFIX_WITH_TEMPLATE + "*", HistoryStore.DOC_TYPE, matchAllQuery());
long expectedCount = oldRecordCount + (recordExecution ? 1 : 0);
assertThat("the expected count of history records should be [" + expectedCount + "]", newRecordCount, equalTo(expectedCount));

View File

@ -7,7 +7,6 @@ package org.elasticsearch.xpack.watcher.history;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.common.logging.ESLogger;
import org.elasticsearch.common.logging.ESLoggerFactory;
import org.elasticsearch.common.logging.Loggers;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.search.aggregations.Aggregations;
@ -17,9 +16,7 @@ import org.elasticsearch.xpack.notification.email.support.EmailServer;
import org.elasticsearch.xpack.watcher.execution.ExecutionState;
import org.elasticsearch.xpack.watcher.test.AbstractWatcherIntegrationTestCase;
import org.elasticsearch.xpack.watcher.transport.actions.put.PutWatchResponse;
import org.junit.After;
import org.junit.AfterClass;
import org.junit.Before;
import org.junit.BeforeClass;
import static org.elasticsearch.search.aggregations.AggregationBuilders.terms;
@ -107,7 +104,7 @@ public class HistoryTemplateEmailMappingsTests extends AbstractWatcherIntegratio
// the action should fail as no email server is available
assertWatchWithMinimumActionsCount("_id", ExecutionState.EXECUTED, 1);
SearchResponse response = client().prepareSearch(HistoryStore.INDEX_PREFIX + "*").setSource(searchSource()
SearchResponse response = client().prepareSearch(HistoryStore.INDEX_PREFIX_WITH_TEMPLATE + "*").setSource(searchSource()
.aggregation(terms("from").field("result.actions.email.message.from"))
.aggregation(terms("to").field("result.actions.email.message.to"))
.aggregation(terms("cc").field("result.actions.email.message.cc"))

View File

@ -93,7 +93,7 @@ public class HistoryTemplateHttpMappingsTests extends AbstractWatcherIntegration
// the action should fail as no email server is available
assertWatchWithMinimumActionsCount("_id", ExecutionState.EXECUTED, 1);
SearchResponse response = client().prepareSearch(HistoryStore.INDEX_PREFIX + "*").setSource(searchSource()
SearchResponse response = client().prepareSearch(HistoryStore.INDEX_PREFIX_WITH_TEMPLATE + "*").setSource(searchSource()
.aggregation(terms("input_result_path").field("result.input.http.request.path"))
.aggregation(terms("input_result_host").field("result.input.http.request.host"))
.aggregation(terms("webhook_path").field("result.actions.webhook.request.path")))

View File

@ -55,7 +55,7 @@ public class HistoryTemplateIndexActionMappingsTests extends AbstractWatcherInte
flush();
refresh();
SearchResponse response = client().prepareSearch(HistoryStore.INDEX_PREFIX + "*").setSource(searchSource()
SearchResponse response = client().prepareSearch(HistoryStore.INDEX_PREFIX_WITH_TEMPLATE + "*").setSource(searchSource()
.aggregation(terms("index_action_indices").field("result.actions.index.response.index"))
.aggregation(terms("index_action_types").field("result.actions.index.response.type")))
.get();

View File

@ -66,7 +66,7 @@ public class HistoryTemplateSearchInputMappingsTests extends AbstractWatcherInte
// the action should fail as no email server is available
assertWatchWithMinimumActionsCount("_id", ExecutionState.EXECUTED, 1);
SearchResponse response = client().prepareSearch(HistoryStore.INDEX_PREFIX + "*").setSource(searchSource()
SearchResponse response = client().prepareSearch(HistoryStore.INDEX_PREFIX_WITH_TEMPLATE + "*").setSource(searchSource()
.aggregation(terms("input_search_type").field("result.input.search.request.search_type"))
.aggregation(terms("input_indices").field("result.input.search.request.indices"))
.aggregation(terms("input_types").field("result.input.search.request.types"))

View File

@ -149,7 +149,7 @@ public class HttpInputIntegrationTests extends AbstractWatcherIntegrationTestCas
// Check that the input result payload has been filtered
refresh();
SearchResponse searchResponse = client().prepareSearch(HistoryStore.INDEX_PREFIX + "*")
SearchResponse searchResponse = client().prepareSearch(HistoryStore.INDEX_PREFIX_WITH_TEMPLATE + "*")
.setIndicesOptions(IndicesOptions.lenientExpandOpen())
.setQuery(matchQuery("watch_id", "_name1"))
.setSize(1)

View File

@ -133,7 +133,7 @@ public class WatcherUtilsTests extends ESTestCase {
assertThat(parser.nextToken(), equalTo(XContentParser.Token.START_OBJECT));
IndicesQueriesRegistry registry = new IndicesQueriesRegistry();
QueryParser<MatchAllQueryBuilder> queryParser = MatchAllQueryBuilder::fromXContent;
registry.register(queryParser, MatchAllQueryBuilder.QUERY_NAME_FIELD);
registry.register(queryParser, MatchAllQueryBuilder.NAME);
QueryParseContext context = new QueryParseContext(registry, parser, ParseFieldMatcher.STRICT);
WatcherSearchTemplateRequest result = WatcherSearchTemplateRequest.fromXContent(parser, DEFAULT_SEARCH_TYPE, context, null, null);
@ -220,7 +220,7 @@ public class WatcherUtilsTests extends ESTestCase {
assertThat(parser.nextToken(), equalTo(XContentParser.Token.START_OBJECT));
IndicesQueriesRegistry registry = new IndicesQueriesRegistry();
QueryParser<MatchAllQueryBuilder> queryParser = MatchAllQueryBuilder::fromXContent;
registry.register(queryParser, MatchAllQueryBuilder.QUERY_NAME_FIELD);
registry.register(queryParser, MatchAllQueryBuilder.NAME);
QueryParseContext context = new QueryParseContext(registry, parser, ParseFieldMatcher.STRICT);
WatcherSearchTemplateRequest result = WatcherSearchTemplateRequest.fromXContent(parser, DEFAULT_SEARCH_TYPE, context, null, null);

View File

@ -312,7 +312,8 @@ public abstract class AbstractWatcherIntegrationTestCase extends ESIntegTestCase
protected long watchRecordCount(QueryBuilder query) {
refresh();
return docCount(HistoryStore.INDEX_PREFIX + "*", HistoryStore.DOC_TYPE, SearchSourceBuilder.searchSource().query(query));
return docCount(HistoryStore.INDEX_PREFIX_WITH_TEMPLATE + "*",
HistoryStore.DOC_TYPE, SearchSourceBuilder.searchSource().query(query));
}
protected long docCount(String index, String type, SearchSourceBuilder source) {
@ -324,7 +325,7 @@ public abstract class AbstractWatcherIntegrationTestCase extends ESIntegTestCase
}
protected SearchResponse searchHistory(SearchSourceBuilder builder) {
return client().prepareSearch(HistoryStore.INDEX_PREFIX + "*").setSource(builder).get();
return client().prepareSearch(HistoryStore.INDEX_PREFIX_WITH_TEMPLATE + "*").setSource(builder).get();
}
protected <T> T getInstanceFromMaster(Class<T> type) {
@ -398,7 +399,7 @@ public abstract class AbstractWatcherIntegrationTestCase extends ESIntegTestCase
assertBusy(() -> {
ClusterState state = client().admin().cluster().prepareState().get().getState();
String[] watchHistoryIndices = indexNameExpressionResolver().concreteIndexNames(state,
IndicesOptions.lenientExpandOpen(), HistoryStore.INDEX_PREFIX + "*");
IndicesOptions.lenientExpandOpen(), HistoryStore.INDEX_PREFIX_WITH_TEMPLATE + "*");
assertThat(watchHistoryIndices, not(emptyArray()));
for (String index : watchHistoryIndices) {
IndexRoutingTable routingTable = state.getRoutingTable().index(index);
@ -407,7 +408,7 @@ public abstract class AbstractWatcherIntegrationTestCase extends ESIntegTestCase
}
refresh();
SearchResponse searchResponse = client().prepareSearch(HistoryStore.INDEX_PREFIX + "*")
SearchResponse searchResponse = client().prepareSearch(HistoryStore.INDEX_PREFIX_WITH_TEMPLATE + "*")
.setIndicesOptions(IndicesOptions.lenientExpandOpen())
.setQuery(boolQuery().must(matchQuery("watch_id", watchName)).must(matchQuery("state",
ExecutionState.EXECUTED.id())))
@ -432,14 +433,15 @@ public abstract class AbstractWatcherIntegrationTestCase extends ESIntegTestCase
}
protected SearchResponse searchWatchRecords(Callback<SearchRequestBuilder> requestBuilderCallback) {
SearchRequestBuilder builder = client().prepareSearch(HistoryStore.INDEX_PREFIX + "*").setTypes(HistoryStore.DOC_TYPE);
SearchRequestBuilder builder =
client().prepareSearch(HistoryStore.INDEX_PREFIX_WITH_TEMPLATE + "*").setTypes(HistoryStore.DOC_TYPE);
requestBuilderCallback.handle(builder);
return builder.get();
}
protected long historyRecordsCount(String watchName) {
refresh();
SearchResponse searchResponse = client().prepareSearch(HistoryStore.INDEX_PREFIX + "*")
SearchResponse searchResponse = client().prepareSearch(HistoryStore.INDEX_PREFIX_WITH_TEMPLATE + "*")
.setIndicesOptions(IndicesOptions.lenientExpandOpen())
.setSize(0)
.setQuery(matchQuery("watch_id", watchName))
@ -449,7 +451,7 @@ public abstract class AbstractWatcherIntegrationTestCase extends ESIntegTestCase
protected long findNumberOfPerformedActions(String watchName) {
refresh();
SearchResponse searchResponse = client().prepareSearch(HistoryStore.INDEX_PREFIX + "*")
SearchResponse searchResponse = client().prepareSearch(HistoryStore.INDEX_PREFIX_WITH_TEMPLATE + "*")
.setIndicesOptions(IndicesOptions.lenientExpandOpen())
.setQuery(boolQuery().must(matchQuery("watch_id", watchName)).must(matchQuery("state", ExecutionState.EXECUTED.id())))
.get();
@ -465,7 +467,7 @@ public abstract class AbstractWatcherIntegrationTestCase extends ESIntegTestCase
// so we to check first is this index is created and shards are started
ClusterState state = client().admin().cluster().prepareState().get().getState();
String[] watchHistoryIndices = indexNameExpressionResolver().concreteIndexNames(state,
IndicesOptions.lenientExpandOpen(), HistoryStore.INDEX_PREFIX + "*");
IndicesOptions.lenientExpandOpen(), HistoryStore.INDEX_PREFIX_WITH_TEMPLATE + "*");
assertThat(watchHistoryIndices, not(emptyArray()));
for (String index : watchHistoryIndices) {
IndexRoutingTable routingTable = state.getRoutingTable().index(index);
@ -473,7 +475,7 @@ public abstract class AbstractWatcherIntegrationTestCase extends ESIntegTestCase
assertThat(routingTable.allPrimaryShardsActive(), is(true));
}
refresh();
SearchResponse searchResponse = client().prepareSearch(HistoryStore.INDEX_PREFIX + "*")
SearchResponse searchResponse = client().prepareSearch(HistoryStore.INDEX_PREFIX_WITH_TEMPLATE + "*")
.setIndicesOptions(IndicesOptions.lenientExpandOpen())
.setQuery(boolQuery().must(matchQuery("watch_id", watchName)).must(matchQuery("state",
ExecutionState.EXECUTION_NOT_NEEDED.id())))
@ -497,7 +499,7 @@ public abstract class AbstractWatcherIntegrationTestCase extends ESIntegTestCase
assertBusy(() -> {
ClusterState state = client().admin().cluster().prepareState().get().getState();
String[] watchHistoryIndices = indexNameExpressionResolver().concreteIndexNames(state, IndicesOptions.lenientExpandOpen(),
HistoryStore.INDEX_PREFIX + "*");
HistoryStore.INDEX_PREFIX_WITH_TEMPLATE + "*");
assertThat(watchHistoryIndices, not(emptyArray()));
for (String index : watchHistoryIndices) {
IndexRoutingTable routingTable = state.getRoutingTable().index(index);
@ -506,7 +508,7 @@ public abstract class AbstractWatcherIntegrationTestCase extends ESIntegTestCase
}
refresh();
SearchResponse searchResponse = client().prepareSearch(HistoryStore.INDEX_PREFIX + "*")
SearchResponse searchResponse = client().prepareSearch(HistoryStore.INDEX_PREFIX_WITH_TEMPLATE + "*")
.setIndicesOptions(IndicesOptions.lenientExpandOpen())
.setQuery(boolQuery().must(matchQuery("watch_id", watchName)).must(matchQuery("state", recordState.id())))
.get();

View File

@ -140,7 +140,7 @@ public class WatcherScheduleEngineBenchmark {
try (Node node = new MockNode(settings, Arrays.asList(XPackPlugin.class, XPackPlugin.class))) {
try (final Client client = node.client()) {
client.admin().cluster().prepareHealth().setWaitForNodes("2").get();
client.admin().indices().prepareDelete(HistoryStore.INDEX_PREFIX + "*").get();
client.admin().indices().prepareDelete(HistoryStore.INDEX_PREFIX_WITH_TEMPLATE + "*").get();
client.admin().cluster().prepareHealth(WatchStore.INDEX, "test").setWaitForYellowStatus().get();
Clock clock = node.injector().getInstance(Clock.class);
@ -185,10 +185,10 @@ public class WatcherScheduleEngineBenchmark {
}
}
}
client.admin().indices().prepareRefresh(HistoryStore.INDEX_PREFIX + "*").get();
client.admin().indices().prepareRefresh(HistoryStore.INDEX_PREFIX_WITH_TEMPLATE + "*").get();
Script script = new Script("doc['trigger_event.schedule.triggered_time'].value - doc['trigger_event.schedule" +
".scheduled_time'].value");
SearchResponse searchResponse = client.prepareSearch(HistoryStore.INDEX_PREFIX + "*")
SearchResponse searchResponse = client.prepareSearch(HistoryStore.INDEX_PREFIX_WITH_TEMPLATE + "*")
.setQuery(QueryBuilders.rangeQuery("trigger_event.schedule.scheduled_time").gte(startTime).lte(endTime))
.addAggregation(terms("state").field("state"))
.addAggregation(histogram("delay")

View File

@ -208,7 +208,7 @@ public class BootStrapTests extends AbstractWatcherIntegrationTestCase {
startWatcher();
refresh();
SearchResponse searchResponse = client().prepareSearch(HistoryStore.INDEX_PREFIX + "*").get();
SearchResponse searchResponse = client().prepareSearch(HistoryStore.INDEX_PREFIX_WITH_TEMPLATE + "*").get();
assertHitCount(searchResponse, 1);
assertThat(searchResponse.getHits().getAt(0).id(), Matchers.equalTo(wid.value()));
assertThat(searchResponse.getHits().getAt(0).sourceAsMap().get(WatchRecord.Field.STATE.getPreferredName()).toString(),

View File

@ -71,7 +71,7 @@ public class WatchMetadataTests extends AbstractWatcherIntegrationTestCase {
}
refresh();
SearchResponse searchResponse = client().prepareSearch(HistoryStore.INDEX_PREFIX + "*")
SearchResponse searchResponse = client().prepareSearch(HistoryStore.INDEX_PREFIX_WITH_TEMPLATE + "*")
.setQuery(termQuery("metadata.foo", "bar"))
.get();
assertThat(searchResponse.getHits().getTotalHits(), greaterThan(0L));

View File

@ -350,7 +350,7 @@ public class WatchTests extends ESTestCase {
case SearchInput.TYPE:
IndicesQueriesRegistry queryRegistry = new IndicesQueriesRegistry();
QueryParser<MatchAllQueryBuilder> queryParser = MatchAllQueryBuilder::fromXContent;
queryRegistry.register(queryParser, MatchAllQueryBuilder.QUERY_NAME_FIELD);
queryRegistry.register(queryParser, MatchAllQueryBuilder.NAME);
parsers.put(SearchInput.TYPE, new SearchInputFactory(settings, client, queryRegistry, null, null, scriptService));
return new InputRegistry(Settings.EMPTY, parsers);
default:
@ -423,7 +423,7 @@ public class WatchTests extends ESTestCase {
private TransformRegistry transformRegistry() {
IndicesQueriesRegistry queryRegistry = new IndicesQueriesRegistry();
QueryParser<MatchAllQueryBuilder> queryParser = MatchAllQueryBuilder::fromXContent;
queryRegistry.register(queryParser, MatchAllQueryBuilder.QUERY_NAME_FIELD);
queryRegistry.register(queryParser, MatchAllQueryBuilder.NAME);
Map<String, TransformFactory> factories = new HashMap<>();
factories.put(ScriptTransform.TYPE, new ScriptTransformFactory(settings, scriptService));
factories.put(SearchTransform.TYPE, new SearchTransformFactory(settings, client, queryRegistry, null, null, scriptService));