Merge pull request elastic/elasticsearch#2870 from rjernst/deguice14
Remove interfaces for auth services Original commit: elastic/x-pack-elasticsearch@e10798b9aa
This commit is contained in:
commit
4b4e7158eb
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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. */
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -12,7 +12,7 @@ import org.elasticsearch.common.logging.LoggerMessageFormat;
|
|||
import org.elasticsearch.common.settings.Settings;
|
||||
import org.elasticsearch.common.util.concurrent.ThreadContext;
|
||||
import org.elasticsearch.xpack.security.user.User;
|
||||
import org.elasticsearch.xpack.security.authz.InternalAuthorizationService;
|
||||
import org.elasticsearch.xpack.security.authz.AuthorizationService;
|
||||
import org.elasticsearch.xpack.security.authz.accesscontrol.IndicesAccessControl;
|
||||
|
||||
import java.util.Collections;
|
||||
|
@ -42,7 +42,7 @@ public abstract class FieldAndDocumentLevelSecurityRequestInterceptor<Request> e
|
|||
throw new IllegalArgumentException(LoggerMessageFormat.format("Expected a request of type [{}] or [{}] but got [{}] instead",
|
||||
CompositeIndicesRequest.class, IndicesRequest.class, request.getClass()));
|
||||
}
|
||||
IndicesAccessControl indicesAccessControl = threadContext.getTransient(InternalAuthorizationService.INDICES_PERMISSIONS_KEY);
|
||||
IndicesAccessControl indicesAccessControl = threadContext.getTransient(AuthorizationService.INDICES_PERMISSIONS_KEY);
|
||||
for (IndicesRequest indicesRequest : indicesRequests) {
|
||||
for (String index : indicesRequest.indices()) {
|
||||
IndicesAccessControl.IndexAccessControl indexAccessControl = indicesAccessControl.getIndexPermissions(index);
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -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<Boolean> SIGN_USER_HEADER =
|
||||
Setting.boolSetting(setting("authc.sign_user_header"), true, Property.NodeScope);
|
||||
public static final Setting<Boolean> RUN_AS_ENABLED =
|
||||
Setting.boolSetting(setting("authc.run_as.enabled"), true, Property.NodeScope);
|
||||
public static final String RUN_AS_USER_HEADER = "es-security-runas-user";
|
||||
|
||||
private final Realms realms;
|
||||
private final AuditTrail auditTrail;
|
||||
private final CryptoService cryptoService;
|
||||
private final AuthenticationFailureHandler failureHandler;
|
||||
private final ThreadContext threadContext;
|
||||
private final String nodeName;
|
||||
private final boolean signUserHeader;
|
||||
private final boolean runAsEnabled;
|
||||
|
||||
@Inject
|
||||
public 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<Setting<?>> settings) {
|
||||
settings.add(SIGN_USER_HEADER);
|
||||
settings.add(RUN_AS_ENABLED);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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<Boolean> SIGN_USER_HEADER =
|
||||
Setting.boolSetting(setting("authc.sign_user_header"), true, Property.NodeScope);
|
||||
public static final Setting<Boolean> RUN_AS_ENABLED =
|
||||
Setting.boolSetting(setting("authc.run_as.enabled"), true, Property.NodeScope);
|
||||
public static final String RUN_AS_USER_HEADER = "es-security-runas-user";
|
||||
|
||||
private final Realms realms;
|
||||
private final AuditTrail auditTrail;
|
||||
private final CryptoService cryptoService;
|
||||
private final AuthenticationFailureHandler failureHandler;
|
||||
private final ThreadContext threadContext;
|
||||
private final String nodeName;
|
||||
private final boolean signUserHeader;
|
||||
private final boolean runAsEnabled;
|
||||
|
||||
@Inject
|
||||
public InternalAuthenticationService(Settings settings, Realms realms, 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<Setting<?>> settings) {
|
||||
settings.add(SIGN_USER_HEADER);
|
||||
settings.add(RUN_AS_ENABLED);
|
||||
}
|
||||
}
|
|
@ -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();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -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<Boolean> ANONYMOUS_AUTHORIZATION_EXCEPTION_SETTING =
|
||||
Setting.boolSetting(setting("authc.anonymous.authz_exception"), true, Property.NodeScope);
|
||||
public static final String INDICES_PERMISSIONS_KEY = "_indices_permissions";
|
||||
static final String ORIGINATING_ACTION_KEY = "_originating_action_name";
|
||||
|
||||
private static final Predicate<String> MONITOR_INDEX_PREDICATE = IndexPrivilege.MONITOR.predicate();
|
||||
|
||||
private final ClusterService clusterService;
|
||||
private final RolesStore rolesStore;
|
||||
private final AuditTrail auditTrail;
|
||||
private final IndicesAndAliasesResolver[] indicesAndAliasesResolvers;
|
||||
private final AuthenticationFailureHandler authcFailureHandler;
|
||||
private final ThreadContext threadContext;
|
||||
private final boolean anonymousAuthzExceptionEnabled;
|
||||
|
||||
@Inject
|
||||
public 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<String> authorizedIndicesAndAliases(User user, String action);
|
||||
public List<String> authorizedIndicesAndAliases(User user, String action) {
|
||||
final String[] anonymousRoles = AnonymousUser.enabled() ? AnonymousUser.getRoles() : Strings.EMPTY_ARRAY;
|
||||
String[] rolesNames = user.roles();
|
||||
if (rolesNames.length == 0 && anonymousRoles.length == 0) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
List<Predicate<String>> predicates = new ArrayList<>();
|
||||
for (String roleName : rolesNames) {
|
||||
Role role = rolesStore.role(roleName);
|
||||
if (role != null) {
|
||||
predicates.add(role.indices().allowedIndicesMatcher(action));
|
||||
}
|
||||
}
|
||||
if (AnonymousUser.is(user) == false) {
|
||||
for (String roleName : anonymousRoles) {
|
||||
Role role = rolesStore.role(roleName);
|
||||
if (role != null) {
|
||||
predicates.add(role.indices().allowedIndicesMatcher(action));
|
||||
}
|
||||
}
|
||||
}
|
||||
Predicate<String> predicate = predicates.stream().reduce(s -> false, (p1, p2) -> p1.or(p2));
|
||||
|
||||
List<String> indicesAndAliases = new ArrayList<>();
|
||||
MetaData metaData = clusterService.state().metaData();
|
||||
// TODO: can this be done smarter? I think there are usually more indices/aliases in the cluster then indices defined a roles?
|
||||
for (Map.Entry<String, AliasOrIndex> entry : metaData.getAliasAndIndexLookup().entrySet()) {
|
||||
String aliasOrIndex = entry.getKey();
|
||||
if (predicate.test(aliasOrIndex)) {
|
||||
indicesAndAliases.add(aliasOrIndex);
|
||||
}
|
||||
}
|
||||
|
||||
if (XPackUser.is(user) == false) {
|
||||
// we should filter out the .security index from wildcards
|
||||
if (indicesAndAliases.remove(SecurityTemplateService.SECURITY_INDEX_NAME)) {
|
||||
logger.debug("removed [{}] from user [{}] list of authorized indices",
|
||||
SecurityTemplateService.SECURITY_INDEX_NAME, user.principal());
|
||||
}
|
||||
}
|
||||
return Collections.unmodifiableList(indicesAndAliases);
|
||||
}
|
||||
|
||||
/**
|
||||
* Verifies that the given user can execute the given request (and action). If the user doesn't
|
||||
|
@ -35,6 +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<String> indexNames = resolveIndices(authentication, action, request, clusterState);
|
||||
assert !indexNames.isEmpty() : "every indices request needs to have its indices set thus the resolved indices must not be empty";
|
||||
MetaData metaData = clusterState.metaData();
|
||||
IndicesAccessControl indicesAccessControl = permission.authorize(action, indexNames, metaData);
|
||||
if (!indicesAccessControl.isGranted()) {
|
||||
throw denial(authentication, action, request);
|
||||
} else if (indicesAccessControl.getIndexPermissions(SecurityTemplateService.SECURITY_INDEX_NAME) != null
|
||||
&& indicesAccessControl.getIndexPermissions(SecurityTemplateService.SECURITY_INDEX_NAME).isGranted()
|
||||
&& XPackUser.is(authentication.getRunAsUser()) == false
|
||||
&& MONITOR_INDEX_PREDICATE.test(action) == false) {
|
||||
// only the XPackUser is allowed to work with this index, but we should allow indices monitoring actions through for debugging
|
||||
// purposes. These monitor requests also sometimes resolve indices concretely and then requests them
|
||||
// FIXME its not just the XPackUser. We said the elastic user and superusers could access this!
|
||||
logger.debug("user [{}] attempted to directly perform [{}] against the security index [{}]",
|
||||
authentication.getRunAsUser().principal(), action, SecurityTemplateService.SECURITY_INDEX_NAME);
|
||||
throw denial(authentication, action, request);
|
||||
} else {
|
||||
setIndicesAccessControl(indicesAccessControl);
|
||||
}
|
||||
|
||||
//if we are creating an index we need to authorize potential aliases created at the same time
|
||||
if (IndexPrivilege.CREATE_INDEX_MATCHER.test(action)) {
|
||||
assert request instanceof CreateIndexRequest;
|
||||
Set<Alias> aliases = ((CreateIndexRequest) request).aliases();
|
||||
if (!aliases.isEmpty()) {
|
||||
Set<String> aliasesAndIndices = Sets.newHashSet(indexNames);
|
||||
for (Alias alias : aliases) {
|
||||
aliasesAndIndices.add(alias.name());
|
||||
}
|
||||
indicesAccessControl = permission.authorize("indices:admin/aliases", aliasesAndIndices, metaData);
|
||||
if (!indicesAccessControl.isGranted()) {
|
||||
throw denial(authentication, "indices:admin/aliases", request);
|
||||
}
|
||||
// no need to re-add the indicesAccessControl in the context,
|
||||
// because the create index call doesn't do anything FLS or DLS
|
||||
}
|
||||
}
|
||||
|
||||
grant(authentication, action, request);
|
||||
}
|
||||
|
||||
private void setIndicesAccessControl(IndicesAccessControl accessControl) {
|
||||
if (threadContext.getTransient(INDICES_PERMISSIONS_KEY) == null) {
|
||||
threadContext.putTransient(INDICES_PERMISSIONS_KEY, accessControl);
|
||||
}
|
||||
}
|
||||
|
||||
private void setOriginatingAction(String action) {
|
||||
String originatingAction = threadContext.getTransient(ORIGINATING_ACTION_KEY);
|
||||
if (originatingAction == null) {
|
||||
threadContext.putTransient(ORIGINATING_ACTION_KEY, action);
|
||||
}
|
||||
}
|
||||
|
||||
private GlobalPermission permission(String[] roleNames) {
|
||||
if (roleNames.length == 0) {
|
||||
return DefaultRole.INSTANCE;
|
||||
}
|
||||
|
||||
if (roleNames.length == 1) {
|
||||
Role role = rolesStore.role(roleNames[0]);
|
||||
return role == null ? DefaultRole.INSTANCE : GlobalPermission.Compound.builder().add(DefaultRole.INSTANCE).add(role).build();
|
||||
}
|
||||
|
||||
// we'll take all the roles and combine their associated permissions
|
||||
|
||||
GlobalPermission.Compound.Builder roles = GlobalPermission.Compound.builder().add(DefaultRole.INSTANCE);
|
||||
for (String roleName : roleNames) {
|
||||
Role role = rolesStore.role(roleName);
|
||||
if (role != null) {
|
||||
roles.add(role);
|
||||
}
|
||||
}
|
||||
return roles.build();
|
||||
}
|
||||
|
||||
private Set<String> resolveIndices(Authentication authentication, String action, TransportRequest request, ClusterState clusterState) {
|
||||
MetaData metaData = clusterState.metaData();
|
||||
for (IndicesAndAliasesResolver resolver : indicesAndAliasesResolvers) {
|
||||
if (resolver.requestType().isInstance(request)) {
|
||||
return resolver.resolve(authentication.getRunAsUser(), action, request, metaData);
|
||||
}
|
||||
}
|
||||
assert false : "we should be able to resolve indices for any known request that requires indices privileges";
|
||||
throw denial(authentication, action, request);
|
||||
}
|
||||
|
||||
private static boolean isScrollRelatedAction(String action) {
|
||||
return action.equals(SearchScrollAction.NAME) ||
|
||||
action.equals(SearchTransportService.FETCH_ID_SCROLL_ACTION_NAME) ||
|
||||
action.equals(SearchTransportService.QUERY_FETCH_SCROLL_ACTION_NAME) ||
|
||||
action.equals(SearchTransportService.QUERY_SCROLL_ACTION_NAME) ||
|
||||
action.equals(SearchTransportService.FREE_CONTEXT_SCROLL_ACTION_NAME) ||
|
||||
action.equals(ClearScrollAction.NAME) ||
|
||||
action.equals(SearchTransportService.CLEAR_SCROLL_CONTEXTS_ACTION_NAME);
|
||||
}
|
||||
|
||||
private ElasticsearchSecurityException denial(Authentication authentication, String action, TransportRequest request) {
|
||||
auditTrail.accessDenied(authentication.getUser(), action, request);
|
||||
return denialException(authentication, action);
|
||||
}
|
||||
|
||||
private ElasticsearchSecurityException denyRunAs(Authentication authentication, String action, TransportRequest request) {
|
||||
auditTrail.runAsDenied(authentication.getUser(), action, request);
|
||||
return denialException(authentication, action);
|
||||
}
|
||||
|
||||
private void grant(Authentication authentication, String action, TransportRequest request) {
|
||||
auditTrail.accessGranted(authentication.getUser(), action, request);
|
||||
}
|
||||
|
||||
private void grantRunAs(Authentication authentication, String action, TransportRequest request) {
|
||||
auditTrail.runAsGranted(authentication.getUser(), action, request);
|
||||
}
|
||||
|
||||
private ElasticsearchSecurityException denialException(Authentication authentication, String action) {
|
||||
final User user = authentication.getUser();
|
||||
// Special case for anonymous user
|
||||
if (AnonymousUser.enabled() && AnonymousUser.is(user)) {
|
||||
if (anonymousAuthzExceptionEnabled == false) {
|
||||
throw authcFailureHandler.authenticationRequired(action, threadContext);
|
||||
}
|
||||
}
|
||||
// check for run as
|
||||
if (user != authentication.getRunAsUser()) {
|
||||
return authorizationError("action [{}] is unauthorized for user [{}] run as [{}]", action, user.principal(),
|
||||
authentication.getRunAsUser().principal());
|
||||
}
|
||||
return authorizationError("action [{}] is unauthorized for user [{}]", action, user.principal());
|
||||
}
|
||||
|
||||
public static void addSettings(List<Setting<?>> settings) {
|
||||
settings.add(ANONYMOUS_AUTHORIZATION_EXCEPTION_SETTING);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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<Boolean> ANONYMOUS_AUTHORIZATION_EXCEPTION_SETTING =
|
||||
Setting.boolSetting(setting("authc.anonymous.authz_exception"), true, Property.NodeScope);
|
||||
public static final String INDICES_PERMISSIONS_KEY = "_indices_permissions";
|
||||
static final String ORIGINATING_ACTION_KEY = "_originating_action_name";
|
||||
|
||||
private static final Predicate<String> MONITOR_INDEX_PREDICATE = IndexPrivilege.MONITOR.predicate();
|
||||
|
||||
private final ClusterService clusterService;
|
||||
private final RolesStore rolesStore;
|
||||
private final AuditTrail auditTrail;
|
||||
private final IndicesAndAliasesResolver[] indicesAndAliasesResolvers;
|
||||
private final AuthenticationFailureHandler authcFailureHandler;
|
||||
private final ThreadContext threadContext;
|
||||
private final boolean anonymousAuthzExceptionEnabled;
|
||||
|
||||
@Inject
|
||||
public InternalAuthorizationService(Settings settings, RolesStore rolesStore, ClusterService clusterService,
|
||||
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<String> authorizedIndicesAndAliases(User user, String action) {
|
||||
final String[] anonymousRoles = AnonymousUser.enabled() ? AnonymousUser.getRoles() : Strings.EMPTY_ARRAY;
|
||||
String[] rolesNames = user.roles();
|
||||
if (rolesNames.length == 0 && anonymousRoles.length == 0) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
List<Predicate<String>> predicates = new ArrayList<>();
|
||||
for (String roleName : rolesNames) {
|
||||
Role role = rolesStore.role(roleName);
|
||||
if (role != null) {
|
||||
predicates.add(role.indices().allowedIndicesMatcher(action));
|
||||
}
|
||||
}
|
||||
if (AnonymousUser.is(user) == false) {
|
||||
for (String roleName : anonymousRoles) {
|
||||
Role role = rolesStore.role(roleName);
|
||||
if (role != null) {
|
||||
predicates.add(role.indices().allowedIndicesMatcher(action));
|
||||
}
|
||||
}
|
||||
}
|
||||
Predicate<String> predicate = predicates.stream().reduce(s -> false, (p1, p2) -> p1.or(p2));
|
||||
|
||||
List<String> indicesAndAliases = new ArrayList<>();
|
||||
MetaData metaData = clusterService.state().metaData();
|
||||
// TODO: can this be done smarter? I think there are usually more indices/aliases in the cluster then indices defined a roles?
|
||||
for (Map.Entry<String, AliasOrIndex> entry : metaData.getAliasAndIndexLookup().entrySet()) {
|
||||
String aliasOrIndex = entry.getKey();
|
||||
if (predicate.test(aliasOrIndex)) {
|
||||
indicesAndAliases.add(aliasOrIndex);
|
||||
}
|
||||
}
|
||||
|
||||
if (XPackUser.is(user) == false) {
|
||||
// we should filter out the .security index from wildcards
|
||||
if (indicesAndAliases.remove(SecurityTemplateService.SECURITY_INDEX_NAME)) {
|
||||
logger.debug("removed [{}] from user [{}] list of authorized indices",
|
||||
SecurityTemplateService.SECURITY_INDEX_NAME, user.principal());
|
||||
}
|
||||
}
|
||||
return Collections.unmodifiableList(indicesAndAliases);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void authorize(Authentication authentication, String action, TransportRequest request) throws ElasticsearchSecurityException {
|
||||
// prior to doing any authorization lets set the originating action in the context only
|
||||
setOriginatingAction(action);
|
||||
|
||||
// first we need to check if the user is the system. If it is, we'll just authorize the system access
|
||||
if (SystemUser.is(authentication.getRunAsUser())) {
|
||||
if (SystemUser.isAuthorized(action) && SystemUser.is(authentication.getUser())) {
|
||||
setIndicesAccessControl(IndicesAccessControl.ALLOW_ALL);
|
||||
grant(authentication, action, request);
|
||||
return;
|
||||
}
|
||||
throw denial(authentication, action, request);
|
||||
}
|
||||
|
||||
// get the roles of the authenticated user, which may be different than the effective
|
||||
GlobalPermission permission = permission(authentication.getUser().roles());
|
||||
|
||||
final boolean isRunAs = authentication.getUser() != authentication.getRunAsUser();
|
||||
// permission can be null as it might be that the user's role
|
||||
// is unknown
|
||||
if (permission == null || permission.isEmpty()) {
|
||||
if (isRunAs) {
|
||||
// the request is a run as request so we should call the specific audit event for a denied run as attempt
|
||||
throw denyRunAs(authentication, action, request);
|
||||
} else {
|
||||
throw denial(authentication, action, request);
|
||||
}
|
||||
}
|
||||
|
||||
// check if the request is a run as request
|
||||
if (isRunAs) {
|
||||
// first we must authorize for the RUN_AS action
|
||||
RunAsPermission runAs = permission.runAs();
|
||||
if (runAs != null && runAs.check(authentication.getRunAsUser().principal())) {
|
||||
grantRunAs(authentication, action, request);
|
||||
permission = permission(authentication.getRunAsUser().roles());
|
||||
|
||||
// permission can be null as it might be that the user's role
|
||||
// is unknown
|
||||
if (permission == null || permission.isEmpty()) {
|
||||
throw denial(authentication, action, request);
|
||||
}
|
||||
} else {
|
||||
throw denyRunAs(authentication, action, request);
|
||||
}
|
||||
}
|
||||
|
||||
// first, we'll check if the action is a cluster action. If it is, we'll only check it
|
||||
// against the cluster permissions
|
||||
if (ClusterPrivilege.ACTION_MATCHER.test(action)) {
|
||||
ClusterPermission cluster = permission.cluster();
|
||||
// we use the effectiveUser for permission checking since we are running as a user!
|
||||
if (cluster != null && cluster.check(action, request, authentication)) {
|
||||
setIndicesAccessControl(IndicesAccessControl.ALLOW_ALL);
|
||||
grant(authentication, action, request);
|
||||
return;
|
||||
}
|
||||
throw denial(authentication, action, request);
|
||||
}
|
||||
|
||||
// ok... this is not a cluster action, let's verify it's an indices action
|
||||
if (!IndexPrivilege.ACTION_MATCHER.test(action)) {
|
||||
throw denial(authentication, action, request);
|
||||
}
|
||||
|
||||
// some APIs are indices requests that are not actually associated with indices. For example,
|
||||
// search scroll request, is categorized under the indices context, but doesn't hold indices names
|
||||
// (in this case, the security check on the indices was done on the search request that initialized
|
||||
// the scroll... and we rely on the signed scroll id to provide security over this request).
|
||||
// so we only check indices if indeed the request is an actual IndicesRequest, if it's not,
|
||||
// we just grant it if it's a scroll, deny otherwise
|
||||
if (!(request instanceof IndicesRequest) && !(request instanceof CompositeIndicesRequest)) {
|
||||
if (isScrollRelatedAction(action)) {
|
||||
//note that clear scroll shard level actions can originate from a clear scroll all, which doesn't require any
|
||||
//indices permission as it's categorized under cluster. This is why the scroll check is performed
|
||||
//even before checking if the user has any indices permission.
|
||||
grant(authentication, action, request);
|
||||
return;
|
||||
}
|
||||
assert false : "only scroll related requests are known indices api that don't support retrieving the indices they relate to";
|
||||
throw denial(authentication, action, request);
|
||||
}
|
||||
|
||||
if (permission.indices() == null || permission.indices().isEmpty()) {
|
||||
throw denial(authentication, action, request);
|
||||
}
|
||||
|
||||
ClusterState clusterState = clusterService.state();
|
||||
Set<String> indexNames = resolveIndices(authentication, action, request, clusterState);
|
||||
assert !indexNames.isEmpty() : "every indices request needs to have its indices set thus the resolved indices must not be empty";
|
||||
MetaData metaData = clusterState.metaData();
|
||||
IndicesAccessControl indicesAccessControl = permission.authorize(action, indexNames, metaData);
|
||||
if (!indicesAccessControl.isGranted()) {
|
||||
throw denial(authentication, action, request);
|
||||
} else if (indicesAccessControl.getIndexPermissions(SecurityTemplateService.SECURITY_INDEX_NAME) != null
|
||||
&& indicesAccessControl.getIndexPermissions(SecurityTemplateService.SECURITY_INDEX_NAME).isGranted()
|
||||
&& XPackUser.is(authentication.getRunAsUser()) == false
|
||||
&& MONITOR_INDEX_PREDICATE.test(action) == false) {
|
||||
// only the XPackUser is allowed to work with this index, but we should allow indices monitoring actions through for debugging
|
||||
// purposes. These monitor requests also sometimes resolve indices concretely and then requests them
|
||||
// FIXME its not just the XPackUser. We said the elastic user and superusers could access this!
|
||||
logger.debug("user [{}] attempted to directly perform [{}] against the security index [{}]",
|
||||
authentication.getRunAsUser().principal(), action, SecurityTemplateService.SECURITY_INDEX_NAME);
|
||||
throw denial(authentication, action, request);
|
||||
} else {
|
||||
setIndicesAccessControl(indicesAccessControl);
|
||||
}
|
||||
|
||||
//if we are creating an index we need to authorize potential aliases created at the same time
|
||||
if (IndexPrivilege.CREATE_INDEX_MATCHER.test(action)) {
|
||||
assert request instanceof CreateIndexRequest;
|
||||
Set<Alias> aliases = ((CreateIndexRequest) request).aliases();
|
||||
if (!aliases.isEmpty()) {
|
||||
Set<String> aliasesAndIndices = Sets.newHashSet(indexNames);
|
||||
for (Alias alias : aliases) {
|
||||
aliasesAndIndices.add(alias.name());
|
||||
}
|
||||
indicesAccessControl = permission.authorize("indices:admin/aliases", aliasesAndIndices, metaData);
|
||||
if (!indicesAccessControl.isGranted()) {
|
||||
throw denial(authentication, "indices:admin/aliases", request);
|
||||
}
|
||||
// no need to re-add the indicesAccessControl in the context,
|
||||
// because the create index call doesn't do anything FLS or DLS
|
||||
}
|
||||
}
|
||||
|
||||
grant(authentication, action, request);
|
||||
}
|
||||
|
||||
private void setIndicesAccessControl(IndicesAccessControl accessControl) {
|
||||
if (threadContext.getTransient(INDICES_PERMISSIONS_KEY) == null) {
|
||||
threadContext.putTransient(INDICES_PERMISSIONS_KEY, accessControl);
|
||||
}
|
||||
}
|
||||
|
||||
private void setOriginatingAction(String action) {
|
||||
String originatingAction = threadContext.getTransient(ORIGINATING_ACTION_KEY);
|
||||
if (originatingAction == null) {
|
||||
threadContext.putTransient(ORIGINATING_ACTION_KEY, action);
|
||||
}
|
||||
}
|
||||
|
||||
private GlobalPermission permission(String[] roleNames) {
|
||||
if (roleNames.length == 0) {
|
||||
return DefaultRole.INSTANCE;
|
||||
}
|
||||
|
||||
if (roleNames.length == 1) {
|
||||
Role role = rolesStore.role(roleNames[0]);
|
||||
return role == null ? DefaultRole.INSTANCE : GlobalPermission.Compound.builder().add(DefaultRole.INSTANCE).add(role).build();
|
||||
}
|
||||
|
||||
// we'll take all the roles and combine their associated permissions
|
||||
|
||||
GlobalPermission.Compound.Builder roles = GlobalPermission.Compound.builder().add(DefaultRole.INSTANCE);
|
||||
for (String roleName : roleNames) {
|
||||
Role role = rolesStore.role(roleName);
|
||||
if (role != null) {
|
||||
roles.add(role);
|
||||
}
|
||||
}
|
||||
return roles.build();
|
||||
}
|
||||
|
||||
private Set<String> resolveIndices(Authentication authentication, String action, TransportRequest request, ClusterState clusterState) {
|
||||
MetaData metaData = clusterState.metaData();
|
||||
for (IndicesAndAliasesResolver resolver : indicesAndAliasesResolvers) {
|
||||
if (resolver.requestType().isInstance(request)) {
|
||||
return resolver.resolve(authentication.getRunAsUser(), action, request, metaData);
|
||||
}
|
||||
}
|
||||
assert false : "we should be able to resolve indices for any known request that requires indices privileges";
|
||||
throw denial(authentication, action, request);
|
||||
}
|
||||
|
||||
private static boolean isScrollRelatedAction(String action) {
|
||||
return action.equals(SearchScrollAction.NAME) ||
|
||||
action.equals(SearchTransportService.FETCH_ID_SCROLL_ACTION_NAME) ||
|
||||
action.equals(SearchTransportService.QUERY_FETCH_SCROLL_ACTION_NAME) ||
|
||||
action.equals(SearchTransportService.QUERY_SCROLL_ACTION_NAME) ||
|
||||
action.equals(SearchTransportService.FREE_CONTEXT_SCROLL_ACTION_NAME) ||
|
||||
action.equals(ClearScrollAction.NAME) ||
|
||||
action.equals(SearchTransportService.CLEAR_SCROLL_CONTEXTS_ACTION_NAME);
|
||||
}
|
||||
|
||||
private ElasticsearchSecurityException denial(Authentication authentication, String action, TransportRequest request) {
|
||||
auditTrail.accessDenied(authentication.getUser(), action, request);
|
||||
return denialException(authentication, action);
|
||||
}
|
||||
|
||||
private ElasticsearchSecurityException denyRunAs(Authentication authentication, String action, TransportRequest request) {
|
||||
auditTrail.runAsDenied(authentication.getUser(), action, request);
|
||||
return denialException(authentication, action);
|
||||
}
|
||||
|
||||
private void grant(Authentication authentication, String action, TransportRequest request) {
|
||||
auditTrail.accessGranted(authentication.getUser(), action, request);
|
||||
}
|
||||
|
||||
private void grantRunAs(Authentication authentication, String action, TransportRequest request) {
|
||||
auditTrail.runAsGranted(authentication.getUser(), action, request);
|
||||
}
|
||||
|
||||
private ElasticsearchSecurityException denialException(Authentication authentication, String action) {
|
||||
final User user = authentication.getUser();
|
||||
// Special case for anonymous user
|
||||
if (AnonymousUser.enabled() && AnonymousUser.is(user)) {
|
||||
if (anonymousAuthzExceptionEnabled == false) {
|
||||
throw authcFailureHandler.authenticationRequired(action, threadContext);
|
||||
}
|
||||
}
|
||||
// check for run as
|
||||
if (user != authentication.getRunAsUser()) {
|
||||
return authorizationError("action [{}] is unauthorized for user [{}] run as [{}]", action, user.principal(),
|
||||
authentication.getRunAsUser().principal());
|
||||
}
|
||||
return authorizationError("action [{}] is unauthorized for user [{}]", action, user.principal());
|
||||
}
|
||||
|
||||
public static void addSettings(List<Setting<?>> settings) {
|
||||
settings.add(ANONYMOUS_AUTHORIZATION_EXCEPTION_SETTING);
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
|
|
|
@ -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");
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
||||
/**
|
||||
|
|
|
@ -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);
|
|
@ -95,7 +95,7 @@ public class RunAsIntegTests extends SecurityIntegTestCase {
|
|||
|
||||
// let's run as without authorization
|
||||
try {
|
||||
Map<String, String> headers = Collections.singletonMap(InternalAuthenticationService.RUN_AS_USER_HEADER,
|
||||
Map<String, String> headers = Collections.singletonMap(AuthenticationService.RUN_AS_USER_HEADER,
|
||||
SecuritySettingsSource.DEFAULT_USER_NAME);
|
||||
client.filterWithHeader(headers)
|
||||
.admin().cluster().prepareHealth().get();
|
||||
|
@ -108,7 +108,7 @@ public class RunAsIntegTests extends SecurityIntegTestCase {
|
|||
Map<String, String> headers = new HashMap<>();
|
||||
headers.put("Authorization", UsernamePasswordToken.basicAuthHeaderValue(RUN_AS_USER,
|
||||
new SecuredString(SecuritySettingsSource.DEFAULT_PASSWORD.toCharArray())));
|
||||
headers.put(InternalAuthenticationService.RUN_AS_USER_HEADER, SecuritySettingsSource.DEFAULT_USER_NAME);
|
||||
headers.put(AuthenticationService.RUN_AS_USER_HEADER, SecuritySettingsSource.DEFAULT_USER_NAME);
|
||||
// lets set the user
|
||||
ClusterHealthResponse response = client.filterWithHeader(headers).admin().cluster().prepareHealth().get();
|
||||
assertThat(response.isTimedOut(), is(false));
|
||||
|
@ -122,7 +122,7 @@ public class RunAsIntegTests extends SecurityIntegTestCase {
|
|||
new BasicHeader(UsernamePasswordToken.BASIC_AUTH_HEADER,
|
||||
UsernamePasswordToken.basicAuthHeaderValue(TRANSPORT_CLIENT_USER,
|
||||
SecuredStringTests.build(SecuritySettingsSource.DEFAULT_PASSWORD))),
|
||||
new BasicHeader(InternalAuthenticationService.RUN_AS_USER_HEADER, SecuritySettingsSource.DEFAULT_USER_NAME));
|
||||
new BasicHeader(AuthenticationService.RUN_AS_USER_HEADER, SecuritySettingsSource.DEFAULT_USER_NAME));
|
||||
fail("request should have failed");
|
||||
} catch(ResponseException e) {
|
||||
assertThat(e.getResponse().getStatusLine().getStatusCode(), is(403));
|
||||
|
@ -144,7 +144,7 @@ public class RunAsIntegTests extends SecurityIntegTestCase {
|
|||
new BasicHeader(UsernamePasswordToken.BASIC_AUTH_HEADER,
|
||||
UsernamePasswordToken.basicAuthHeaderValue(RUN_AS_USER,
|
||||
SecuredStringTests.build(SecuritySettingsSource.DEFAULT_PASSWORD))),
|
||||
new BasicHeader(InternalAuthenticationService.RUN_AS_USER_HEADER, SecuritySettingsSource.DEFAULT_USER_NAME))) {
|
||||
new BasicHeader(AuthenticationService.RUN_AS_USER_HEADER, SecuritySettingsSource.DEFAULT_USER_NAME))) {
|
||||
assertThat(response.getStatusLine().getStatusCode(), is(200));
|
||||
}
|
||||
}
|
||||
|
@ -161,7 +161,7 @@ public class RunAsIntegTests extends SecurityIntegTestCase {
|
|||
Map<String, String> headers = new HashMap<>();
|
||||
headers.put("Authorization", UsernamePasswordToken.basicAuthHeaderValue(RUN_AS_USER,
|
||||
new SecuredString(SecuritySettingsSource.DEFAULT_PASSWORD.toCharArray())));
|
||||
headers.put(InternalAuthenticationService.RUN_AS_USER_HEADER, "");
|
||||
headers.put(AuthenticationService.RUN_AS_USER_HEADER, "");
|
||||
|
||||
client.filterWithHeader(headers).admin().cluster().prepareHealth().get();
|
||||
fail("run as header should not be allowed to be empty");
|
||||
|
@ -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<String, String> headers = new HashMap<>();
|
||||
headers.put("Authorization", UsernamePasswordToken.basicAuthHeaderValue(RUN_AS_USER,
|
||||
new SecuredString(SecuritySettingsSource.DEFAULT_PASSWORD.toCharArray())));
|
||||
headers.put(InternalAuthenticationService.RUN_AS_USER_HEADER, "idontexist");
|
||||
headers.put(AuthenticationService.RUN_AS_USER_HEADER, "idontexist");
|
||||
|
||||
client.filterWithHeader(headers).admin().cluster().prepareHealth().get();
|
||||
fail("run as header should not accept non-existent users");
|
||||
|
@ -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));
|
||||
|
|
|
@ -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());
|
|
@ -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));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
|
||||
|
|
|
@ -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<String> headers = new HashSet<>();
|
||||
headers.add(UsernamePasswordToken.BASIC_AUTH_HEADER);
|
||||
if (InternalAuthenticationService.RUN_AS_ENABLED.get(settings)) {
|
||||
headers.add(InternalAuthenticationService.RUN_AS_USER_HEADER);
|
||||
if (AuthenticationService.RUN_AS_ENABLED.get(settings)) {
|
||||
headers.add(AuthenticationService.RUN_AS_USER_HEADER);
|
||||
}
|
||||
headers.addAll(extensionsService.getExtensions().stream()
|
||||
.flatMap(e -> e.getRestHeaders().stream()).collect(Collectors.toList()));
|
||||
|
|
Loading…
Reference in New Issue