From 94b9b332d482f846f1a0a36b93b229ace6526f72 Mon Sep 17 00:00:00 2001 From: Ryan Ernst Date: Tue, 19 Jul 2016 14:38:51 -0700 Subject: [PATCH] Internal: Remove interfaces for auth services Both AuthenticationService and AuthorizationService are currently interfaces with single implementations. This is unnecessary, and makes it harder to deguice. This change removes the abstractions and leaves just AuthenticationService and AuthorizationService. Original commit: elastic/x-pack-elasticsearch@d04c897ae4240699875a5dd72d63414b54f0a6ec --- .../xpack/security/InternalClient.java | 4 +- .../xpack/security/Security.java | 9 +- .../xpack/security/SecurityContext.java | 4 +- .../action/filter/SecurityActionFilter.java | 4 +- .../interceptor/BulkRequestInterceptor.java | 4 +- ...cumentLevelSecurityRequestInterceptor.java | 4 +- .../security/authc/AuthenticationModule.java | 2 +- .../security/authc/AuthenticationService.java | 371 ++++++++++++++++- .../authc/InternalAuthenticationService.java | 387 ------------------ .../security/authz/AuthorizationModule.java | 2 +- .../security/authz/AuthorizationService.java | 346 +++++++++++++++- .../security/authz/AuthorizationUtils.java | 4 +- .../authz/InternalAuthorizationService.java | 366 ----------------- .../authz/accesscontrol/OptOutQueryCache.java | 4 +- .../SecurityIndexSearcherWrapper.java | 4 +- .../DefaultIndicesAndAliasesResolver.java | 4 +- .../transport/ServerTransportFilter.java | 30 +- ...s.java => AuthenticationServiceTests.java} | 40 +- .../xpack/security/authc/RunAsIntegTests.java | 16 +- ...ts.java => AuthorizationServiceTests.java} | 14 +- .../authz/AuthorizationUtilsTests.java | 4 +- .../DefaultIndicesResolverTests.java | 4 +- .../rest/SecurityRestFilterTests.java | 2 +- .../action/RestAuthenticateActionTests.java | 4 +- .../transport/ClientTransportFilterTests.java | 2 +- .../transport/ServerTransportFilterTests.java | 4 +- .../transport/TransportFilterTests.java | 4 +- .../user/AnonymousUserIntegTests.java | 4 +- .../org/elasticsearch/xpack/XPackPlugin.java | 6 +- 29 files changed, 797 insertions(+), 856 deletions(-) delete mode 100644 elasticsearch/x-pack/security/src/main/java/org/elasticsearch/xpack/security/authc/InternalAuthenticationService.java delete mode 100644 elasticsearch/x-pack/security/src/main/java/org/elasticsearch/xpack/security/authz/InternalAuthorizationService.java rename elasticsearch/x-pack/security/src/test/java/org/elasticsearch/xpack/security/authc/{InternalAuthenticationServiceTests.java => AuthenticationServiceTests.java} (94%) rename elasticsearch/x-pack/security/src/test/java/org/elasticsearch/xpack/security/authz/{InternalAuthorizationServiceTests.java => AuthorizationServiceTests.java} (98%) diff --git a/elasticsearch/x-pack/security/src/main/java/org/elasticsearch/xpack/security/InternalClient.java b/elasticsearch/x-pack/security/src/main/java/org/elasticsearch/xpack/security/InternalClient.java index e5de9537f5f..b6112beb514 100644 --- a/elasticsearch/x-pack/security/src/main/java/org/elasticsearch/xpack/security/InternalClient.java +++ b/elasticsearch/x-pack/security/src/main/java/org/elasticsearch/xpack/security/InternalClient.java @@ -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); } diff --git a/elasticsearch/x-pack/security/src/main/java/org/elasticsearch/xpack/security/Security.java b/elasticsearch/x-pack/security/src/main/java/org/elasticsearch/xpack/security/Security.java index b2697c9bb06..b41a1c2b854 100644 --- a/elasticsearch/x-pack/security/src/main/java/org/elasticsearch/xpack/security/Security.java +++ b/elasticsearch/x-pack/security/src/main/java/org/elasticsearch/xpack/security/Security.java @@ -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; @@ -76,7 +75,7 @@ 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.AuthenticationService; import org.elasticsearch.xpack.security.authc.Realm; import org.elasticsearch.xpack.security.authc.Realms; import org.elasticsearch.xpack.security.authc.activedirectory.ActiveDirectoryRealm; @@ -90,7 +89,7 @@ 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; @@ -358,8 +357,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); diff --git a/elasticsearch/x-pack/security/src/main/java/org/elasticsearch/xpack/security/SecurityContext.java b/elasticsearch/x-pack/security/src/main/java/org/elasticsearch/xpack/security/SecurityContext.java index 6b5ebcb2cc6..2942d135272 100644 --- a/elasticsearch/x-pack/security/src/main/java/org/elasticsearch/xpack/security/SecurityContext.java +++ b/elasticsearch/x-pack/security/src/main/java/org/elasticsearch/xpack/security/SecurityContext.java @@ -13,7 +13,7 @@ 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.InternalAuthenticationService; +import org.elasticsearch.xpack.security.authc.AuthenticationService; import org.elasticsearch.xpack.security.crypto.CryptoService; import org.elasticsearch.xpack.security.user.User; @@ -36,7 +36,7 @@ public class SecurityContext { this.logger = Loggers.getLogger(getClass(), settings); this.threadContext = threadPool.getThreadContext(); this.cryptoService = cryptoService; - this.signUserHeader = InternalAuthenticationService.SIGN_USER_HEADER.get(settings); + this.signUserHeader = AuthenticationService.SIGN_USER_HEADER.get(settings); } /** Returns the current user information, or null if the current request has no authentication info. */ diff --git a/elasticsearch/x-pack/security/src/main/java/org/elasticsearch/xpack/security/action/filter/SecurityActionFilter.java b/elasticsearch/x-pack/security/src/main/java/org/elasticsearch/xpack/security/action/filter/SecurityActionFilter.java index ad7c4e12559..10c0bf70ff1 100644 --- a/elasticsearch/x-pack/security/src/main/java/org/elasticsearch/xpack/security/action/filter/SecurityActionFilter.java +++ b/elasticsearch/x-pack/security/src/main/java/org/elasticsearch/xpack/security/action/filter/SecurityActionFilter.java @@ -24,12 +24,12 @@ 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; diff --git a/elasticsearch/x-pack/security/src/main/java/org/elasticsearch/xpack/security/action/interceptor/BulkRequestInterceptor.java b/elasticsearch/x-pack/security/src/main/java/org/elasticsearch/xpack/security/action/interceptor/BulkRequestInterceptor.java index ee6db9b477d..8f974e688fe 100644 --- a/elasticsearch/x-pack/security/src/main/java/org/elasticsearch/xpack/security/action/interceptor/BulkRequestInterceptor.java +++ b/elasticsearch/x-pack/security/src/main/java/org/elasticsearch/xpack/security/action/interceptor/BulkRequestInterceptor.java @@ -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); diff --git a/elasticsearch/x-pack/security/src/main/java/org/elasticsearch/xpack/security/action/interceptor/FieldAndDocumentLevelSecurityRequestInterceptor.java b/elasticsearch/x-pack/security/src/main/java/org/elasticsearch/xpack/security/action/interceptor/FieldAndDocumentLevelSecurityRequestInterceptor.java index e81e7e4cd15..b2a1c159708 100644 --- a/elasticsearch/x-pack/security/src/main/java/org/elasticsearch/xpack/security/action/interceptor/FieldAndDocumentLevelSecurityRequestInterceptor.java +++ b/elasticsearch/x-pack/security/src/main/java/org/elasticsearch/xpack/security/action/interceptor/FieldAndDocumentLevelSecurityRequestInterceptor.java @@ -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 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); diff --git a/elasticsearch/x-pack/security/src/main/java/org/elasticsearch/xpack/security/authc/AuthenticationModule.java b/elasticsearch/x-pack/security/src/main/java/org/elasticsearch/xpack/security/authc/AuthenticationModule.java index 57491d0c12e..c77680e998c 100644 --- a/elasticsearch/x-pack/security/src/main/java/org/elasticsearch/xpack/security/authc/AuthenticationModule.java +++ b/elasticsearch/x-pack/security/src/main/java/org/elasticsearch/xpack/security/authc/AuthenticationModule.java @@ -34,7 +34,7 @@ public class AuthenticationModule extends AbstractSecurityModule.Node { } else { bind(AuthenticationFailureHandler.class).to(authcFailureHandler).asEagerSingleton(); } - bind(AuthenticationService.class).to(InternalAuthenticationService.class).asEagerSingleton(); + bind(AuthenticationService.class).asEagerSingleton(); } /** diff --git a/elasticsearch/x-pack/security/src/main/java/org/elasticsearch/xpack/security/authc/AuthenticationService.java b/elasticsearch/x-pack/security/src/main/java/org/elasticsearch/xpack/security/authc/AuthenticationService.java index ec6d2e49e0b..b63b56d050a 100644 --- a/elasticsearch/x-pack/security/src/main/java/org/elasticsearch/xpack/security/authc/AuthenticationService.java +++ b/elasticsearch/x-pack/security/src/main/java/org/elasticsearch/xpack/security/authc/AuthenticationService.java @@ -6,16 +6,66 @@ 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.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 java.util.List; + +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 SIGN_USER_HEADER = + Setting.boolSetting(setting("authc.sign_user_header"), true, Property.NodeScope); + public static final Setting 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 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 +78,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 +99,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,5 +111,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); + } + + 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> settings) { + settings.add(SIGN_USER_HEADER); + settings.add(RUN_AS_ENABLED); + } } diff --git a/elasticsearch/x-pack/security/src/main/java/org/elasticsearch/xpack/security/authc/InternalAuthenticationService.java b/elasticsearch/x-pack/security/src/main/java/org/elasticsearch/xpack/security/authc/InternalAuthenticationService.java deleted file mode 100644 index 13bc0ca86f5..00000000000 --- a/elasticsearch/x-pack/security/src/main/java/org/elasticsearch/xpack/security/authc/InternalAuthenticationService.java +++ /dev/null @@ -1,387 +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.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 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 SIGN_USER_HEADER = - Setting.boolSetting(setting("authc.sign_user_header"), true, Property.NodeScope); - public static final Setting 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, 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); - } - - @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); - } - - 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> settings) { - settings.add(SIGN_USER_HEADER); - settings.add(RUN_AS_ENABLED); - } -} diff --git a/elasticsearch/x-pack/security/src/main/java/org/elasticsearch/xpack/security/authz/AuthorizationModule.java b/elasticsearch/x-pack/security/src/main/java/org/elasticsearch/xpack/security/authz/AuthorizationModule.java index 81b584f0d81..0494bfb52ba 100644 --- a/elasticsearch/x-pack/security/src/main/java/org/elasticsearch/xpack/security/authz/AuthorizationModule.java +++ b/elasticsearch/x-pack/security/src/main/java/org/elasticsearch/xpack/security/authz/AuthorizationModule.java @@ -36,7 +36,7 @@ public class AuthorizationModule extends AbstractSecurityModule.Node { 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(); + bind(AuthorizationService.class).asEagerSingleton(); } } diff --git a/elasticsearch/x-pack/security/src/main/java/org/elasticsearch/xpack/security/authz/AuthorizationService.java b/elasticsearch/x-pack/security/src/main/java/org/elasticsearch/xpack/security/authz/AuthorizationService.java index d80f693f2d5..7a7edf4b54d 100644 --- a/elasticsearch/x-pack/security/src/main/java/org/elasticsearch/xpack/security/authz/AuthorizationService.java +++ b/elasticsearch/x-pack/security/src/main/java/org/elasticsearch/xpack/security/authz/AuthorizationService.java @@ -6,16 +6,94 @@ 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.audit.AuditTrailService; 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 interface AuthorizationService { +public class AuthorizationService extends AbstractComponent { + + public static final Setting 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 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 AuthorizationService(Settings settings, RolesStore rolesStore, ClusterService clusterService, + AuditTrailService 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); + } /** * Returns all indices and aliases the given user is allowed to execute the given action on. @@ -23,7 +101,49 @@ public interface AuthorizationService { * @param user The user * @param action The action */ - List authorizedIndicesAndAliases(User user, String action); + public List 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> 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 predicate = predicates.stream().reduce(s -> false, (p1, p2) -> p1.or(p2)); + + List 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 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 +155,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 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 aliases = ((CreateIndexRequest) request).aliases(); + if (!aliases.isEmpty()) { + Set 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 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> settings) { + settings.add(ANONYMOUS_AUTHORIZATION_EXCEPTION_SETTING); + } } diff --git a/elasticsearch/x-pack/security/src/main/java/org/elasticsearch/xpack/security/authz/AuthorizationUtils.java b/elasticsearch/x-pack/security/src/main/java/org/elasticsearch/xpack/security/authz/AuthorizationUtils.java index 955e64f2258..b3c7344e68e 100644 --- a/elasticsearch/x-pack/security/src/main/java/org/elasticsearch/xpack/security/authz/AuthorizationUtils.java +++ b/elasticsearch/x-pack/security/src/main/java/org/elasticsearch/xpack/security/authz/AuthorizationUtils.java @@ -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; } diff --git a/elasticsearch/x-pack/security/src/main/java/org/elasticsearch/xpack/security/authz/InternalAuthorizationService.java b/elasticsearch/x-pack/security/src/main/java/org/elasticsearch/xpack/security/authz/InternalAuthorizationService.java deleted file mode 100644 index 0e350fc565a..00000000000 --- a/elasticsearch/x-pack/security/src/main/java/org/elasticsearch/xpack/security/authz/InternalAuthorizationService.java +++ /dev/null @@ -1,366 +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.audit.AuditTrailService; -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 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 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, - AuditTrailService 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 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> 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 predicate = predicates.stream().reduce(s -> false, (p1, p2) -> p1.or(p2)); - - List 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 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 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 aliases = ((CreateIndexRequest) request).aliases(); - if (!aliases.isEmpty()) { - Set 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 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> settings) { - settings.add(ANONYMOUS_AUTHORIZATION_EXCEPTION_SETTING); - } -} diff --git a/elasticsearch/x-pack/security/src/main/java/org/elasticsearch/xpack/security/authz/accesscontrol/OptOutQueryCache.java b/elasticsearch/x-pack/security/src/main/java/org/elasticsearch/xpack/security/authz/accesscontrol/OptOutQueryCache.java index 7cf8a0e0e83..ad4f0d7823e 100644 --- a/elasticsearch/x-pack/security/src/main/java/org/elasticsearch/xpack/security/authz/accesscontrol/OptOutQueryCache.java +++ b/elasticsearch/x-pack/security/src/main/java/org/elasticsearch/xpack/security/authz/accesscontrol/OptOutQueryCache.java @@ -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; diff --git a/elasticsearch/x-pack/security/src/main/java/org/elasticsearch/xpack/security/authz/accesscontrol/SecurityIndexSearcherWrapper.java b/elasticsearch/x-pack/security/src/main/java/org/elasticsearch/xpack/security/authz/accesscontrol/SecurityIndexSearcherWrapper.java index 2e133336eea..5a938235b02 100644 --- a/elasticsearch/x-pack/security/src/main/java/org/elasticsearch/xpack/security/authz/accesscontrol/SecurityIndexSearcherWrapper.java +++ b/elasticsearch/x-pack/security/src/main/java/org/elasticsearch/xpack/security/authz/accesscontrol/SecurityIndexSearcherWrapper.java @@ -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"); } diff --git a/elasticsearch/x-pack/security/src/main/java/org/elasticsearch/xpack/security/authz/indicesresolver/DefaultIndicesAndAliasesResolver.java b/elasticsearch/x-pack/security/src/main/java/org/elasticsearch/xpack/security/authz/indicesresolver/DefaultIndicesAndAliasesResolver.java index 5ee3d53cf94..440ad73eab7 100644 --- a/elasticsearch/x-pack/security/src/main/java/org/elasticsearch/xpack/security/authz/indicesresolver/DefaultIndicesAndAliasesResolver.java +++ b/elasticsearch/x-pack/security/src/main/java/org/elasticsearch/xpack/security/authz/indicesresolver/DefaultIndicesAndAliasesResolver.java @@ -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; diff --git a/elasticsearch/x-pack/security/src/main/java/org/elasticsearch/xpack/security/transport/ServerTransportFilter.java b/elasticsearch/x-pack/security/src/main/java/org/elasticsearch/xpack/security/transport/ServerTransportFilter.java index ebc923e6ad8..bc17f7fe4ea 100644 --- a/elasticsearch/x-pack/security/src/main/java/org/elasticsearch/xpack/security/transport/ServerTransportFilter.java +++ b/elasticsearch/x-pack/security/src/main/java/org/elasticsearch/xpack/security/transport/ServerTransportFilter.java @@ -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; /** diff --git a/elasticsearch/x-pack/security/src/test/java/org/elasticsearch/xpack/security/authc/InternalAuthenticationServiceTests.java b/elasticsearch/x-pack/security/src/test/java/org/elasticsearch/xpack/security/authc/AuthenticationServiceTests.java similarity index 94% rename from elasticsearch/x-pack/security/src/test/java/org/elasticsearch/xpack/security/authc/InternalAuthenticationServiceTests.java rename to elasticsearch/x-pack/security/src/test/java/org/elasticsearch/xpack/security/authc/AuthenticationServiceTests.java index dbca9ce2b91..b53277f96b3 100644 --- a/elasticsearch/x-pack/security/src/test/java/org/elasticsearch/xpack/security/authc/InternalAuthenticationServiceTests.java +++ b/elasticsearch/x-pack/security/src/test/java/org/elasticsearch/xpack/security/authc/AuthenticationServiceTests.java @@ -25,7 +25,7 @@ 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.InternalAuthenticationService.Authenticator; +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; @@ -59,9 +59,9 @@ 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; @@ -109,7 +109,7 @@ public class InternalAuthenticationServiceTests extends ESTestCase { 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); } @@ -308,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)); @@ -322,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()); @@ -334,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()); @@ -343,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"); @@ -361,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)); @@ -381,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()); @@ -444,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(); @@ -460,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(); @@ -475,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(); @@ -564,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"})); @@ -582,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"})); @@ -600,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"})); @@ -627,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"})); @@ -656,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); @@ -674,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); diff --git a/elasticsearch/x-pack/security/src/test/java/org/elasticsearch/xpack/security/authc/RunAsIntegTests.java b/elasticsearch/x-pack/security/src/test/java/org/elasticsearch/xpack/security/authc/RunAsIntegTests.java index bf72fb46915..19d9b77676d 100644 --- a/elasticsearch/x-pack/security/src/test/java/org/elasticsearch/xpack/security/authc/RunAsIntegTests.java +++ b/elasticsearch/x-pack/security/src/test/java/org/elasticsearch/xpack/security/authc/RunAsIntegTests.java @@ -95,7 +95,7 @@ public class RunAsIntegTests extends SecurityIntegTestCase { // let's run as without authorization try { - Map headers = Collections.singletonMap(InternalAuthenticationService.RUN_AS_USER_HEADER, + Map 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 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)); } } @@ -161,7 +161,7 @@ public class RunAsIntegTests extends SecurityIntegTestCase { Map 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"); @@ -177,7 +177,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)); @@ -196,7 +196,7 @@ public class RunAsIntegTests extends SecurityIntegTestCase { Map 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"); @@ -212,7 +212,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)); diff --git a/elasticsearch/x-pack/security/src/test/java/org/elasticsearch/xpack/security/authz/InternalAuthorizationServiceTests.java b/elasticsearch/x-pack/security/src/test/java/org/elasticsearch/xpack/security/authz/AuthorizationServiceTests.java similarity index 98% rename from elasticsearch/x-pack/security/src/test/java/org/elasticsearch/xpack/security/authz/InternalAuthorizationServiceTests.java rename to elasticsearch/x-pack/security/src/test/java/org/elasticsearch/xpack/security/authz/AuthorizationServiceTests.java index d546218ecd8..7979c5e4059 100644 --- a/elasticsearch/x-pack/security/src/test/java/org/elasticsearch/xpack/security/authz/InternalAuthorizationServiceTests.java +++ b/elasticsearch/x-pack/security/src/test/java/org/elasticsearch/xpack/security/authz/AuthorizationServiceTests.java @@ -93,11 +93,11 @@ import static org.mockito.Mockito.verify; import static org.mockito.Mockito.verifyNoMoreInteractions; import static org.mockito.Mockito.when; -public class InternalAuthorizationServiceTests extends ESTestCase { +public class AuthorizationServiceTests extends ESTestCase { private AuditTrailService auditTrail; private RolesStore rolesStore; private ClusterService clusterService; - private InternalAuthorizationService internalAuthorizationService; + private AuthorizationService internalAuthorizationService; private ThreadContext threadContext; private ThreadPool threadPool; @@ -112,7 +112,7 @@ public class InternalAuthorizationServiceTests extends ESTestCase { IndexNameExpressionResolver nameExpressionResolver = mock(IndexNameExpressionResolver.class); when(nameExpressionResolver.resolveDateMathExpression(any(String.class))).thenAnswer(returnsFirstArg()); - internalAuthorizationService = new InternalAuthorizationService(Settings.EMPTY, rolesStore, clusterService, + internalAuthorizationService = new AuthorizationService(Settings.EMPTY, rolesStore, clusterService, auditTrail, new DefaultAuthenticationFailureHandler(), threadPool, nameExpressionResolver); } @@ -359,7 +359,7 @@ public class InternalAuthorizationServiceTests extends ESTestCase { 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, + internalAuthorizationService = new AuthorizationService(Settings.EMPTY, rolesStore, clusterService, auditTrail, new DefaultAuthenticationFailureHandler(), threadPool, nameExpressionResolver); when(rolesStore.role("a_all")).thenReturn(Role.builder("a_all").add(IndexPrivilege.ALL, "a").build()); @@ -384,13 +384,13 @@ 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(), + internalAuthorizationService = new AuthorizationService( + Settings.builder().put(AuthorizationService.ANONYMOUS_AUTHORIZATION_EXCEPTION_SETTING.getKey(), false).build(), rolesStore, clusterService, auditTrail, new DefaultAuthenticationFailureHandler(), threadPool, nameExpressionResolver); when(rolesStore.role("a_all")).thenReturn(Role.builder("a_all").add(IndexPrivilege.ALL, "a").build()); diff --git a/elasticsearch/x-pack/security/src/test/java/org/elasticsearch/xpack/security/authz/AuthorizationUtilsTests.java b/elasticsearch/x-pack/security/src/test/java/org/elasticsearch/xpack/security/authz/AuthorizationUtilsTests.java index 540af489890..fdaa0eb50e5 100644 --- a/elasticsearch/x-pack/security/src/test/java/org/elasticsearch/xpack/security/authz/AuthorizationUtilsTests.java +++ b/elasticsearch/x-pack/security/src/test/java/org/elasticsearch/xpack/security/authz/AuthorizationUtilsTests.java @@ -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)); } } diff --git a/elasticsearch/x-pack/security/src/test/java/org/elasticsearch/xpack/security/authz/indicesresolver/DefaultIndicesResolverTests.java b/elasticsearch/x-pack/security/src/test/java/org/elasticsearch/xpack/security/authz/indicesresolver/DefaultIndicesResolverTests.java index 011aff9ebb6..83ae40a1442 100644 --- a/elasticsearch/x-pack/security/src/test/java/org/elasticsearch/xpack/security/authz/indicesresolver/DefaultIndicesResolverTests.java +++ b/elasticsearch/x-pack/security/src/test/java/org/elasticsearch/xpack/security/authz/indicesresolver/DefaultIndicesResolverTests.java @@ -36,7 +36,7 @@ import org.elasticsearch.threadpool.ThreadPool; import org.elasticsearch.xpack.security.SecurityTemplateService; 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; @@ -101,7 +101,7 @@ public class DefaultIndicesResolverTests extends ESTestCase { when(clusterService.state()).thenReturn(state); when(state.metaData()).thenReturn(metaData); - InternalAuthorizationService authzService = new InternalAuthorizationService(settings, rolesStore, clusterService, + AuthorizationService authzService = new AuthorizationService(settings, rolesStore, clusterService, mock(AuditTrailService.class), new DefaultAuthenticationFailureHandler(), mock(ThreadPool.class), indexNameExpressionResolver); defaultIndicesResolver = new DefaultIndicesAndAliasesResolver(authzService, indexNameExpressionResolver); diff --git a/elasticsearch/x-pack/security/src/test/java/org/elasticsearch/xpack/security/rest/SecurityRestFilterTests.java b/elasticsearch/x-pack/security/src/test/java/org/elasticsearch/xpack/security/rest/SecurityRestFilterTests.java index bde8c10079b..badc05f9d2c 100644 --- a/elasticsearch/x-pack/security/src/test/java/org/elasticsearch/xpack/security/rest/SecurityRestFilterTests.java +++ b/elasticsearch/x-pack/security/src/test/java/org/elasticsearch/xpack/security/rest/SecurityRestFilterTests.java @@ -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; diff --git a/elasticsearch/x-pack/security/src/test/java/org/elasticsearch/xpack/security/rest/action/RestAuthenticateActionTests.java b/elasticsearch/x-pack/security/src/test/java/org/elasticsearch/xpack/security/rest/action/RestAuthenticateActionTests.java index b48fec3e5f8..e678d696f59 100644 --- a/elasticsearch/x-pack/security/src/test/java/org/elasticsearch/xpack/security/rest/action/RestAuthenticateActionTests.java +++ b/elasticsearch/x-pack/security/src/test/java/org/elasticsearch/xpack/security/rest/action/RestAuthenticateActionTests.java @@ -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(); } diff --git a/elasticsearch/x-pack/security/src/test/java/org/elasticsearch/xpack/security/transport/ClientTransportFilterTests.java b/elasticsearch/x-pack/security/src/test/java/org/elasticsearch/xpack/security/transport/ClientTransportFilterTests.java index 9d2f78e6af8..15951ec09a7 100644 --- a/elasticsearch/x-pack/security/src/test/java/org/elasticsearch/xpack/security/transport/ClientTransportFilterTests.java +++ b/elasticsearch/x-pack/security/src/test/java/org/elasticsearch/xpack/security/transport/ClientTransportFilterTests.java @@ -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; diff --git a/elasticsearch/x-pack/security/src/test/java/org/elasticsearch/xpack/security/transport/ServerTransportFilterTests.java b/elasticsearch/x-pack/security/src/test/java/org/elasticsearch/xpack/security/transport/ServerTransportFilterTests.java index 376f7456d55..1075f1ae2b0 100644 --- a/elasticsearch/x-pack/security/src/test/java/org/elasticsearch/xpack/security/transport/ServerTransportFilterTests.java +++ b/elasticsearch/x-pack/security/src/test/java/org/elasticsearch/xpack/security/transport/ServerTransportFilterTests.java @@ -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; diff --git a/elasticsearch/x-pack/security/src/test/java/org/elasticsearch/xpack/security/transport/TransportFilterTests.java b/elasticsearch/x-pack/security/src/test/java/org/elasticsearch/xpack/security/transport/TransportFilterTests.java index 18aa09574df..f6ad400e782 100644 --- a/elasticsearch/x-pack/security/src/test/java/org/elasticsearch/xpack/security/transport/TransportFilterTests.java +++ b/elasticsearch/x-pack/security/src/test/java/org/elasticsearch/xpack/security/transport/TransportFilterTests.java @@ -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; diff --git a/elasticsearch/x-pack/security/src/test/java/org/elasticsearch/xpack/security/user/AnonymousUserIntegTests.java b/elasticsearch/x-pack/security/src/test/java/org/elasticsearch/xpack/security/user/AnonymousUserIntegTests.java index 85f72ef525d..d249390fe4b 100644 --- a/elasticsearch/x-pack/security/src/test/java/org/elasticsearch/xpack/security/user/AnonymousUserIntegTests.java +++ b/elasticsearch/x-pack/security/src/test/java/org/elasticsearch/xpack/security/user/AnonymousUserIntegTests.java @@ -10,7 +10,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; @@ -26,7 +26,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(); } diff --git a/elasticsearch/x-pack/src/main/java/org/elasticsearch/xpack/XPackPlugin.java b/elasticsearch/x-pack/src/main/java/org/elasticsearch/xpack/XPackPlugin.java index 78e6b22f86e..a3be4582f3b 100644 --- a/elasticsearch/x-pack/src/main/java/org/elasticsearch/xpack/XPackPlugin.java +++ b/elasticsearch/x-pack/src/main/java/org/elasticsearch/xpack/XPackPlugin.java @@ -70,7 +70,7 @@ 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; @@ -223,8 +223,8 @@ public class XPackPlugin extends Plugin implements ScriptPlugin, ActionPlugin, I } Set 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()));