mirror of
https://github.com/honeymoose/OpenSearch.git
synced 2025-02-26 06:46:10 +00:00
Extract class to store Authentication in context (#52183)
This change extracts the code that previously existed in the "Authentication" class that was responsible for reading and writing authentication objects to/from the ThreadContext. This is needed to support multiple authentication objects under separate keys. This refactoring highlighted that there were a large number of places where we extracted the Authentication/User objects from the thread context, in a variety of ways. These have been consolidated to rely on the SecurityContext object. Backport of: #52032
This commit is contained in:
parent
6086fadf00
commit
b0b1b13311
@ -14,6 +14,7 @@ import org.elasticsearch.common.util.concurrent.ThreadContext.StoredContext;
|
||||
import org.elasticsearch.node.Node;
|
||||
import org.elasticsearch.xpack.core.security.authc.Authentication;
|
||||
import org.elasticsearch.xpack.core.security.authc.Authentication.AuthenticationType;
|
||||
import org.elasticsearch.xpack.core.security.authc.support.AuthenticationContextSerializer;
|
||||
import org.elasticsearch.xpack.core.security.user.User;
|
||||
|
||||
import java.io.IOException;
|
||||
@ -29,17 +30,12 @@ public class SecurityContext {
|
||||
private final Logger logger = LogManager.getLogger(SecurityContext.class);
|
||||
|
||||
private final ThreadContext threadContext;
|
||||
private final UserSettings userSettings;
|
||||
private final AuthenticationContextSerializer authenticationSerializer;
|
||||
private final String nodeName;
|
||||
|
||||
/**
|
||||
* Creates a new security context.
|
||||
* If cryptoService is null, security is disabled and {@link UserSettings#getUser()}
|
||||
* and {@link UserSettings#getAuthentication()} will always return null.
|
||||
*/
|
||||
public SecurityContext(Settings settings, ThreadContext threadContext) {
|
||||
this.threadContext = threadContext;
|
||||
this.userSettings = new UserSettings(threadContext);
|
||||
this.authenticationSerializer = new AuthenticationContextSerializer();
|
||||
this.nodeName = Node.NODE_NAME_SETTING.get(settings);
|
||||
}
|
||||
|
||||
@ -52,13 +48,17 @@ public class SecurityContext {
|
||||
/** Returns the authentication information, or null if the current request has no authentication info. */
|
||||
public Authentication getAuthentication() {
|
||||
try {
|
||||
return Authentication.readFromContext(threadContext);
|
||||
return authenticationSerializer.readFromContext(threadContext);
|
||||
} catch (IOException e) {
|
||||
logger.error("failed to read authentication", e);
|
||||
throw new UncheckedIOException(e);
|
||||
}
|
||||
}
|
||||
|
||||
public ThreadContext getThreadContext() {
|
||||
return threadContext;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the user forcefully to the provided user. There must not be an existing user in the ThreadContext otherwise an exception
|
||||
* will be thrown. This method is package private for testing.
|
||||
@ -103,7 +103,7 @@ public class SecurityContext {
|
||||
*/
|
||||
public void executeAfterRewritingAuthentication(Consumer<StoredContext> consumer, Version version) {
|
||||
final StoredContext original = threadContext.newStoredContext(true);
|
||||
final Authentication authentication = Objects.requireNonNull(userSettings.getAuthentication());
|
||||
final Authentication authentication = getAuthentication();
|
||||
try (ThreadContext.StoredContext ignore = threadContext.stashContext()) {
|
||||
setAuthentication(new Authentication(authentication.getUser(), authentication.getAuthenticatedBy(),
|
||||
authentication.getLookedUpBy(), version, authentication.getAuthenticationType(), authentication.getMetadata()));
|
||||
|
@ -1,46 +0,0 @@
|
||||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License;
|
||||
* you may not use this file except in compliance with the Elastic License.
|
||||
*/
|
||||
package org.elasticsearch.xpack.core.security;
|
||||
|
||||
import org.apache.logging.log4j.Logger;
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.elasticsearch.common.util.concurrent.ThreadContext;
|
||||
import org.elasticsearch.xpack.core.security.authc.Authentication;
|
||||
import org.elasticsearch.xpack.core.security.user.User;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
public final class UserSettings {
|
||||
private final Logger logger = LogManager.getLogger(UserSettings.class);
|
||||
|
||||
private final ThreadContext threadContext;
|
||||
|
||||
UserSettings(ThreadContext threadContext) {
|
||||
this.threadContext = threadContext;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the current user information, or null if the current request has no authentication info.
|
||||
*/
|
||||
public User getUser() {
|
||||
Authentication authentication = getAuthentication();
|
||||
return authentication == null ? null : authentication.getUser();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the authentication information, or null if the current request has no authentication info.
|
||||
*/
|
||||
public Authentication getAuthentication() {
|
||||
try {
|
||||
return Authentication.readFromContext(threadContext);
|
||||
} catch (IOException e) {
|
||||
// TODO: this seems bogus, the only way to get an ioexception here is from a corrupt or tampered
|
||||
// auth header, which should be be audited?
|
||||
logger.error("failed to read authentication", e);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
@ -13,6 +13,7 @@ import org.elasticsearch.common.io.stream.StreamOutput;
|
||||
import org.elasticsearch.common.util.concurrent.ThreadContext;
|
||||
import org.elasticsearch.common.xcontent.ToXContentObject;
|
||||
import org.elasticsearch.common.xcontent.XContentBuilder;
|
||||
import org.elasticsearch.xpack.core.security.authc.support.AuthenticationContextSerializer;
|
||||
import org.elasticsearch.xpack.core.security.user.InternalUserSerializationHelper;
|
||||
import org.elasticsearch.xpack.core.security.user.User;
|
||||
|
||||
@ -93,59 +94,12 @@ public class Authentication implements ToXContentObject {
|
||||
return metadata;
|
||||
}
|
||||
|
||||
public static Authentication readFromContext(ThreadContext ctx) throws IOException, IllegalArgumentException {
|
||||
Authentication authentication = ctx.getTransient(AuthenticationField.AUTHENTICATION_KEY);
|
||||
if (authentication != null) {
|
||||
assert ctx.getHeader(AuthenticationField.AUTHENTICATION_KEY) != null;
|
||||
return authentication;
|
||||
}
|
||||
|
||||
String authenticationHeader = ctx.getHeader(AuthenticationField.AUTHENTICATION_KEY);
|
||||
if (authenticationHeader == null) {
|
||||
return null;
|
||||
}
|
||||
return deserializeHeaderAndPutInContext(authenticationHeader, ctx);
|
||||
}
|
||||
|
||||
public static Authentication getAuthentication(ThreadContext context) {
|
||||
return context.getTransient(AuthenticationField.AUTHENTICATION_KEY);
|
||||
}
|
||||
|
||||
static Authentication deserializeHeaderAndPutInContext(String header, ThreadContext ctx)
|
||||
throws IOException, IllegalArgumentException {
|
||||
assert ctx.getTransient(AuthenticationField.AUTHENTICATION_KEY) == null;
|
||||
|
||||
Authentication authentication = decode(header);
|
||||
ctx.putTransient(AuthenticationField.AUTHENTICATION_KEY, authentication);
|
||||
return authentication;
|
||||
}
|
||||
|
||||
public static Authentication decode(String header) throws IOException {
|
||||
byte[] bytes = Base64.getDecoder().decode(header);
|
||||
StreamInput input = StreamInput.wrap(bytes);
|
||||
Version version = Version.readVersion(input);
|
||||
input.setVersion(version);
|
||||
return new Authentication(input);
|
||||
}
|
||||
|
||||
/**
|
||||
* Writes the authentication to the context. There must not be an existing authentication in the context and if there is an
|
||||
* {@link IllegalStateException} will be thrown
|
||||
*/
|
||||
public void writeToContext(ThreadContext ctx) throws IOException, IllegalArgumentException {
|
||||
ensureContextDoesNotContainAuthentication(ctx);
|
||||
String header = encode();
|
||||
ctx.putTransient(AuthenticationField.AUTHENTICATION_KEY, this);
|
||||
ctx.putHeader(AuthenticationField.AUTHENTICATION_KEY, header);
|
||||
}
|
||||
|
||||
void ensureContextDoesNotContainAuthentication(ThreadContext ctx) {
|
||||
if (ctx.getTransient(AuthenticationField.AUTHENTICATION_KEY) != null) {
|
||||
if (ctx.getHeader(AuthenticationField.AUTHENTICATION_KEY) == null) {
|
||||
throw new IllegalStateException("authentication present as a transient but not a header");
|
||||
}
|
||||
throw new IllegalStateException("authentication is already present in the context");
|
||||
}
|
||||
new AuthenticationContextSerializer().writeToContext(this, ctx);
|
||||
}
|
||||
|
||||
public String encode() throws IOException {
|
||||
|
@ -0,0 +1,90 @@
|
||||
/*
|
||||
* 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.core.security.authc.support;
|
||||
|
||||
import org.elasticsearch.Version;
|
||||
import org.elasticsearch.common.Nullable;
|
||||
import org.elasticsearch.common.io.stream.StreamInput;
|
||||
import org.elasticsearch.common.util.concurrent.ThreadContext;
|
||||
import org.elasticsearch.xpack.core.security.authc.Authentication;
|
||||
import org.elasticsearch.xpack.core.security.authc.AuthenticationField;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.Base64;
|
||||
|
||||
/**
|
||||
* A class from reading/writing {@link org.elasticsearch.xpack.core.security.authc.Authentication} objects to/from a
|
||||
* {@link org.elasticsearch.common.util.concurrent.ThreadContext} under a specified key
|
||||
*/
|
||||
public class AuthenticationContextSerializer {
|
||||
|
||||
private final String contextKey;
|
||||
|
||||
public AuthenticationContextSerializer() {
|
||||
this(AuthenticationField.AUTHENTICATION_KEY);
|
||||
}
|
||||
|
||||
public AuthenticationContextSerializer(String contextKey) {
|
||||
this.contextKey = contextKey;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public Authentication readFromContext(ThreadContext ctx) throws IOException {
|
||||
Authentication authentication = ctx.getTransient(contextKey);
|
||||
if (authentication != null) {
|
||||
assert ctx.getHeader(contextKey) != null;
|
||||
return authentication;
|
||||
}
|
||||
|
||||
String authenticationHeader = ctx.getHeader(contextKey);
|
||||
if (authenticationHeader == null) {
|
||||
return null;
|
||||
}
|
||||
return deserializeHeaderAndPutInContext(authenticationHeader, ctx);
|
||||
}
|
||||
|
||||
Authentication deserializeHeaderAndPutInContext(String headerValue, ThreadContext ctx)
|
||||
throws IOException, IllegalArgumentException {
|
||||
assert ctx.getTransient(contextKey) == null;
|
||||
|
||||
Authentication authentication = decode(headerValue);
|
||||
ctx.putTransient(contextKey, authentication);
|
||||
return authentication;
|
||||
}
|
||||
|
||||
public static Authentication decode(String header) throws IOException {
|
||||
byte[] bytes = Base64.getDecoder().decode(header);
|
||||
StreamInput input = StreamInput.wrap(bytes);
|
||||
Version version = Version.readVersion(input);
|
||||
input.setVersion(version);
|
||||
return new Authentication(input);
|
||||
}
|
||||
|
||||
public Authentication getAuthentication(ThreadContext context) {
|
||||
return context.getTransient(contextKey);
|
||||
}
|
||||
|
||||
/**
|
||||
* Writes the authentication to the context. There must not be an existing authentication in the context and if there is an
|
||||
* {@link IllegalStateException} will be thrown
|
||||
*/
|
||||
public void writeToContext(Authentication authentication, ThreadContext ctx) throws IOException {
|
||||
ensureContextDoesNotContainAuthentication(ctx);
|
||||
String header = authentication.encode();
|
||||
ctx.putTransient(contextKey, authentication);
|
||||
ctx.putHeader(contextKey, header);
|
||||
}
|
||||
|
||||
void ensureContextDoesNotContainAuthentication(ThreadContext ctx) {
|
||||
if (ctx.getTransient(contextKey) != null) {
|
||||
if (ctx.getHeader(contextKey) == null) {
|
||||
throw new IllegalStateException("authentication present as a transient ([" + contextKey + "]) but not a header");
|
||||
}
|
||||
throw new IllegalStateException("authentication ([" + contextKey + "]) is already present in the context");
|
||||
}
|
||||
}
|
||||
}
|
@ -19,13 +19,14 @@ import org.elasticsearch.index.shard.ShardId;
|
||||
import org.elasticsearch.index.shard.ShardUtils;
|
||||
import org.elasticsearch.license.XPackLicenseState;
|
||||
import org.elasticsearch.script.ScriptService;
|
||||
import org.elasticsearch.xpack.core.security.authc.Authentication;
|
||||
import org.elasticsearch.xpack.core.security.SecurityContext;
|
||||
import org.elasticsearch.xpack.core.security.authz.AuthorizationServiceField;
|
||||
import org.elasticsearch.xpack.core.security.authz.permission.DocumentPermissions;
|
||||
import org.elasticsearch.xpack.core.security.support.Exceptions;
|
||||
import org.elasticsearch.xpack.core.security.user.User;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.Objects;
|
||||
import java.util.function.Function;
|
||||
|
||||
/**
|
||||
@ -45,16 +46,16 @@ public class SecurityIndexReaderWrapper implements CheckedFunction<DirectoryRead
|
||||
private final Function<ShardId, QueryShardContext> queryShardContextProvider;
|
||||
private final DocumentSubsetBitsetCache bitsetCache;
|
||||
private final XPackLicenseState licenseState;
|
||||
private final ThreadContext threadContext;
|
||||
private final SecurityContext securityContext;
|
||||
private final ScriptService scriptService;
|
||||
|
||||
public SecurityIndexReaderWrapper(Function<ShardId, QueryShardContext> queryShardContextProvider,
|
||||
DocumentSubsetBitsetCache bitsetCache, ThreadContext threadContext, XPackLicenseState licenseState,
|
||||
ScriptService scriptService) {
|
||||
DocumentSubsetBitsetCache bitsetCache, SecurityContext securityContext,
|
||||
XPackLicenseState licenseState, ScriptService scriptService) {
|
||||
this.scriptService = scriptService;
|
||||
this.queryShardContextProvider = queryShardContextProvider;
|
||||
this.bitsetCache = bitsetCache;
|
||||
this.threadContext = threadContext;
|
||||
this.securityContext = securityContext;
|
||||
this.licenseState = licenseState;
|
||||
}
|
||||
|
||||
@ -95,6 +96,7 @@ public class SecurityIndexReaderWrapper implements CheckedFunction<DirectoryRead
|
||||
}
|
||||
|
||||
protected IndicesAccessControl getIndicesAccessControl() {
|
||||
final ThreadContext threadContext = securityContext.getThreadContext();
|
||||
IndicesAccessControl indicesAccessControl = threadContext.getTransient(AuthorizationServiceField.INDICES_PERMISSIONS_KEY);
|
||||
if (indicesAccessControl == null) {
|
||||
throw Exceptions.authorizationError("no indices permissions found");
|
||||
@ -102,9 +104,8 @@ public class SecurityIndexReaderWrapper implements CheckedFunction<DirectoryRead
|
||||
return indicesAccessControl;
|
||||
}
|
||||
|
||||
protected User getUser(){
|
||||
Authentication authentication = Authentication.getAuthentication(threadContext);
|
||||
return authentication.getUser();
|
||||
protected User getUser() {
|
||||
return Objects.requireNonNull(securityContext.getUser());
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -10,6 +10,7 @@ import org.elasticsearch.common.unit.TimeValue;
|
||||
import org.elasticsearch.common.util.concurrent.ConcurrentCollections;
|
||||
import org.elasticsearch.xpack.core.security.authc.Authentication;
|
||||
import org.elasticsearch.xpack.core.security.authc.AuthenticationField;
|
||||
import org.elasticsearch.xpack.core.security.authc.support.AuthenticationContextSerializer;
|
||||
import org.elasticsearch.xpack.core.watcher.actions.ActionWrapperResult;
|
||||
import org.elasticsearch.xpack.core.watcher.condition.Condition;
|
||||
import org.elasticsearch.xpack.core.watcher.history.WatchRecord;
|
||||
@ -262,7 +263,7 @@ public abstract class WatchExecutionContext {
|
||||
if (watch != null && watch.status() != null && watch.status().getHeaders() != null) {
|
||||
String header = watch.status().getHeaders().get(AuthenticationField.AUTHENTICATION_KEY);
|
||||
if (header != null) {
|
||||
Authentication auth = Authentication.decode(header);
|
||||
Authentication auth = AuthenticationContextSerializer.decode(header);
|
||||
return auth.getUser().principal();
|
||||
}
|
||||
}
|
||||
|
@ -39,8 +39,9 @@ import org.elasticsearch.script.ScriptService;
|
||||
import org.elasticsearch.search.internal.ContextIndexSearcher;
|
||||
import org.elasticsearch.test.AbstractBuilderTestCase;
|
||||
import org.elasticsearch.test.IndexSettingsModule;
|
||||
import org.elasticsearch.xpack.core.security.SecurityContext;
|
||||
import org.elasticsearch.xpack.core.security.authc.Authentication;
|
||||
import org.elasticsearch.xpack.core.security.authc.AuthenticationField;
|
||||
import org.elasticsearch.xpack.core.security.authc.support.AuthenticationContextSerializer;
|
||||
import org.elasticsearch.xpack.core.security.authz.permission.DocumentPermissions;
|
||||
import org.elasticsearch.xpack.core.security.authz.permission.FieldPermissions;
|
||||
import org.elasticsearch.xpack.core.security.user.User;
|
||||
@ -69,10 +70,14 @@ public class SecurityIndexReaderWrapperIntegrationTests extends AbstractBuilderT
|
||||
when(mapperService.simpleMatchToFullName(anyString()))
|
||||
.then(invocationOnMock -> Collections.singletonList((String) invocationOnMock.getArguments()[0]));
|
||||
|
||||
ThreadContext threadContext = new ThreadContext(Settings.EMPTY);
|
||||
final ThreadContext threadContext = new ThreadContext(Settings.EMPTY);
|
||||
final SecurityContext securityContext = new SecurityContext(Settings.EMPTY, threadContext);
|
||||
|
||||
final Authentication authentication = mock(Authentication.class);
|
||||
when(authentication.getUser()).thenReturn(mock(User.class));
|
||||
threadContext.putTransient(AuthenticationField.AUTHENTICATION_KEY, authentication);
|
||||
when(authentication.encode()).thenReturn(randomAlphaOfLength(24)); // don't care as long as it's not null
|
||||
new AuthenticationContextSerializer().writeToContext(authentication, threadContext);
|
||||
|
||||
IndexSettings indexSettings = IndexSettingsModule.newIndexSettings(shardId.getIndex(), Settings.EMPTY);
|
||||
Client client = mock(Client.class);
|
||||
when(client.settings()).thenReturn(Settings.EMPTY);
|
||||
@ -135,7 +140,7 @@ public class SecurityIndexReaderWrapperIntegrationTests extends AbstractBuilderT
|
||||
FieldPermissions(),
|
||||
DocumentPermissions.filteredBy(singleton(new BytesArray(termQuery))));
|
||||
SecurityIndexReaderWrapper wrapper = new SecurityIndexReaderWrapper(s -> queryShardContext,
|
||||
bitsetCache, threadContext, licenseState, scriptService) {
|
||||
bitsetCache, securityContext, licenseState, scriptService) {
|
||||
|
||||
@Override
|
||||
protected IndicesAccessControl getIndicesAccessControl() {
|
||||
@ -173,10 +178,13 @@ public class SecurityIndexReaderWrapperIntegrationTests extends AbstractBuilderT
|
||||
when(mapperService.simpleMatchToFullName(anyString()))
|
||||
.then(invocationOnMock -> Collections.singletonList((String) invocationOnMock.getArguments()[0]));
|
||||
|
||||
ThreadContext threadContext = new ThreadContext(Settings.EMPTY);
|
||||
final ThreadContext threadContext = new ThreadContext(Settings.EMPTY);
|
||||
final SecurityContext securityContext = new SecurityContext(Settings.EMPTY, threadContext);
|
||||
final Authentication authentication = mock(Authentication.class);
|
||||
when(authentication.getUser()).thenReturn(mock(User.class));
|
||||
threadContext.putTransient(AuthenticationField.AUTHENTICATION_KEY, authentication);
|
||||
when(authentication.encode()).thenReturn(randomAlphaOfLength(24)); // don't care as long as it's not null
|
||||
new AuthenticationContextSerializer().writeToContext(authentication, threadContext);
|
||||
|
||||
final boolean noFilteredIndexPermissions = randomBoolean();
|
||||
boolean restrictiveLimitedIndexPermissions = false;
|
||||
if (noFilteredIndexPermissions == false) {
|
||||
@ -208,7 +216,7 @@ public class SecurityIndexReaderWrapperIntegrationTests extends AbstractBuilderT
|
||||
XPackLicenseState licenseState = mock(XPackLicenseState.class);
|
||||
when(licenseState.isDocumentAndFieldLevelSecurityAllowed()).thenReturn(true);
|
||||
SecurityIndexReaderWrapper wrapper = new SecurityIndexReaderWrapper(s -> queryShardContext,
|
||||
bitsetCache, threadContext, licenseState, scriptService) {
|
||||
bitsetCache, securityContext, licenseState, scriptService) {
|
||||
|
||||
@Override
|
||||
protected IndicesAccessControl getIndicesAccessControl() {
|
||||
|
@ -22,6 +22,7 @@ import org.elasticsearch.index.shard.ShardId;
|
||||
import org.elasticsearch.license.XPackLicenseState;
|
||||
import org.elasticsearch.script.ScriptService;
|
||||
import org.elasticsearch.test.ESTestCase;
|
||||
import org.elasticsearch.xpack.core.security.SecurityContext;
|
||||
import org.elasticsearch.xpack.core.security.authz.permission.DocumentPermissions;
|
||||
import org.elasticsearch.xpack.core.security.authz.permission.FieldPermissions;
|
||||
import org.elasticsearch.xpack.core.security.authz.permission.FieldPermissionsDefinition;
|
||||
@ -50,7 +51,7 @@ public class SecurityIndexReaderWrapperUnitTests extends ESTestCase {
|
||||
META_FIELDS = Collections.unmodifiableSet(metaFields);
|
||||
}
|
||||
|
||||
private ThreadContext threadContext;
|
||||
private SecurityContext securityContext;
|
||||
private ScriptService scriptService;
|
||||
private SecurityIndexReaderWrapper securityIndexReaderWrapper;
|
||||
private ElasticsearchDirectoryReader esIn;
|
||||
@ -64,7 +65,7 @@ public class SecurityIndexReaderWrapperUnitTests extends ESTestCase {
|
||||
ShardId shardId = new ShardId(index, 0);
|
||||
licenseState = mock(XPackLicenseState.class);
|
||||
when(licenseState.isDocumentAndFieldLevelSecurityAllowed()).thenReturn(true);
|
||||
threadContext = new ThreadContext(Settings.EMPTY);
|
||||
securityContext = new SecurityContext(Settings.EMPTY, new ThreadContext(Settings.EMPTY));
|
||||
IndexShard indexShard = mock(IndexShard.class);
|
||||
when(indexShard.shardId()).thenReturn(shardId);
|
||||
|
||||
@ -84,7 +85,7 @@ public class SecurityIndexReaderWrapperUnitTests extends ESTestCase {
|
||||
|
||||
public void testDefaultMetaFields() throws Exception {
|
||||
securityIndexReaderWrapper =
|
||||
new SecurityIndexReaderWrapper(null, null, threadContext, licenseState, scriptService) {
|
||||
new SecurityIndexReaderWrapper(null, null, securityContext, licenseState, scriptService) {
|
||||
@Override
|
||||
protected IndicesAccessControl getIndicesAccessControl() {
|
||||
IndicesAccessControl.IndexAccessControl indexAccessControl = new IndicesAccessControl.IndexAccessControl(true,
|
||||
@ -114,7 +115,7 @@ public class SecurityIndexReaderWrapperUnitTests extends ESTestCase {
|
||||
public void testWrapReaderWhenFeatureDisabled() throws Exception {
|
||||
when(licenseState.isDocumentAndFieldLevelSecurityAllowed()).thenReturn(false);
|
||||
securityIndexReaderWrapper =
|
||||
new SecurityIndexReaderWrapper(null, null, threadContext, licenseState, scriptService);
|
||||
new SecurityIndexReaderWrapper(null, null, securityContext, licenseState, scriptService);
|
||||
DirectoryReader reader = securityIndexReaderWrapper.apply(esIn);
|
||||
assertThat(reader, sameInstance(esIn));
|
||||
}
|
||||
@ -148,7 +149,7 @@ public class SecurityIndexReaderWrapperUnitTests extends ESTestCase {
|
||||
|
||||
public void testFieldPermissionsWithFieldExceptions() throws Exception {
|
||||
securityIndexReaderWrapper =
|
||||
new SecurityIndexReaderWrapper(null, null, threadContext, licenseState, null);
|
||||
new SecurityIndexReaderWrapper(null, null, securityContext, licenseState, null);
|
||||
String[] grantedFields = new String[]{};
|
||||
String[] deniedFields;
|
||||
Set<String> expected = new HashSet<>(META_FIELDS);
|
||||
|
@ -427,8 +427,8 @@ public class Security extends Plugin implements SystemIndexPlugin, IngestPlugin,
|
||||
|
||||
securityIndex.set(SecurityIndexManager.buildSecurityMainIndexManager(client, clusterService));
|
||||
|
||||
final TokenService tokenService = new TokenService(settings, Clock.systemUTC(), client, getLicenseState(),
|
||||
securityIndex.get(), SecurityIndexManager.buildSecurityTokensIndexManager(client, clusterService), clusterService);
|
||||
final TokenService tokenService = new TokenService(settings, Clock.systemUTC(), client, getLicenseState(), securityContext.get(),
|
||||
securityIndex.get(), SecurityIndexManager.buildSecurityTokensIndexManager(client, clusterService), clusterService);
|
||||
this.tokenService.set(tokenService);
|
||||
components.add(tokenService);
|
||||
|
||||
@ -726,7 +726,8 @@ public class Security extends Plugin implements SystemIndexPlugin, IngestPlugin,
|
||||
|
||||
}, null),
|
||||
dlsBitsetCache.get(),
|
||||
indexService.getThreadPool().getThreadContext(), getLicenseState(),
|
||||
securityContext.get(),
|
||||
getLicenseState(),
|
||||
indexService.getScriptService()));
|
||||
/*
|
||||
* We need to forcefully overwrite the query cache implementation to use security's opt-out query cache implementation. This
|
||||
@ -746,7 +747,7 @@ public class Security extends Plugin implements SystemIndexPlugin, IngestPlugin,
|
||||
// attaches information to the scroll context so that we can validate the user that created the scroll against
|
||||
// the user that is executing a scroll operation
|
||||
module.addSearchOperationListener(
|
||||
new SecuritySearchOperationListener(threadContext.get(), getLicenseState(), auditTrailService.get()));
|
||||
new SecuritySearchOperationListener(securityContext.get(), getLicenseState(), auditTrailService.get()));
|
||||
}
|
||||
}
|
||||
|
||||
@ -854,7 +855,7 @@ public class Security extends Plugin implements SystemIndexPlugin, IngestPlugin,
|
||||
|
||||
@Override
|
||||
public Map<String, Processor.Factory> getProcessors(Processor.Parameters parameters) {
|
||||
return Collections.singletonMap(SetSecurityUserProcessor.TYPE, new SetSecurityUserProcessor.Factory(parameters.threadContext));
|
||||
return Collections.singletonMap(SetSecurityUserProcessor.TYPE, new SetSecurityUserProcessor.Factory(securityContext::get));
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -19,6 +19,7 @@ import org.elasticsearch.common.util.concurrent.ThreadContext;
|
||||
import org.elasticsearch.tasks.Task;
|
||||
import org.elasticsearch.threadpool.ThreadPool;
|
||||
import org.elasticsearch.transport.TransportService;
|
||||
import org.elasticsearch.xpack.core.security.SecurityContext;
|
||||
import org.elasticsearch.xpack.core.security.action.DelegatePkiAuthenticationAction;
|
||||
import org.elasticsearch.xpack.core.security.action.DelegatePkiAuthenticationRequest;
|
||||
import org.elasticsearch.xpack.core.security.action.DelegatePkiAuthenticationResponse;
|
||||
@ -38,7 +39,7 @@ import java.util.Collections;
|
||||
* {@code PkiRealmSettings#DELEGATION_ENABLED_SETTING} set to {@code true} (default is {@code false}). A successfully trusted target
|
||||
* certificate is also subject to the validation of the subject distinguished name according to that respective's realm
|
||||
* {@code PkiRealmSettings#USERNAME_PATTERN_SETTING}.
|
||||
*
|
||||
*
|
||||
* IMPORTANT: The association between the subject public key in the target certificate and the corresponding private key is <b>not</b>
|
||||
* validated. This is part of the TLS authentication process and it is delegated to the proxy calling this API. The proxy is <b>trusted</b>
|
||||
* to have performed the TLS authentication, and this API translates that authentication into an Elasticsearch access token.
|
||||
@ -51,21 +52,24 @@ public final class TransportDelegatePkiAuthenticationAction
|
||||
private final ThreadPool threadPool;
|
||||
private final AuthenticationService authenticationService;
|
||||
private final TokenService tokenService;
|
||||
private final SecurityContext securityContext;
|
||||
|
||||
@Inject
|
||||
public TransportDelegatePkiAuthenticationAction(ThreadPool threadPool, TransportService transportService, ActionFilters actionFilters,
|
||||
AuthenticationService authenticationService, TokenService tokenService) {
|
||||
AuthenticationService authenticationService, TokenService tokenService,
|
||||
SecurityContext securityContext) {
|
||||
super(DelegatePkiAuthenticationAction.NAME, transportService, actionFilters, DelegatePkiAuthenticationRequest::new);
|
||||
this.threadPool = threadPool;
|
||||
this.authenticationService = authenticationService;
|
||||
this.tokenService = tokenService;
|
||||
this.securityContext = securityContext;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void doExecute(Task task, DelegatePkiAuthenticationRequest request,
|
||||
ActionListener<DelegatePkiAuthenticationResponse> listener) {
|
||||
final ThreadContext threadContext = threadPool.getThreadContext();
|
||||
Authentication delegateeAuthentication = Authentication.getAuthentication(threadContext);
|
||||
Authentication delegateeAuthentication = securityContext.getAuthentication();
|
||||
if (delegateeAuthentication == null) {
|
||||
listener.onFailure(new IllegalStateException("Delegatee authentication cannot be null"));
|
||||
return;
|
||||
|
@ -20,6 +20,7 @@ import org.elasticsearch.common.util.concurrent.ThreadContext;
|
||||
import org.elasticsearch.tasks.Task;
|
||||
import org.elasticsearch.threadpool.ThreadPool;
|
||||
import org.elasticsearch.transport.TransportService;
|
||||
import org.elasticsearch.xpack.core.security.SecurityContext;
|
||||
import org.elasticsearch.xpack.core.security.action.oidc.OpenIdConnectAuthenticateRequest;
|
||||
import org.elasticsearch.xpack.core.security.action.oidc.OpenIdConnectAuthenticateResponse;
|
||||
import org.elasticsearch.xpack.core.security.action.oidc.OpenIdConnectAuthenticateAction;
|
||||
@ -38,17 +39,19 @@ public class TransportOpenIdConnectAuthenticateAction
|
||||
private final ThreadPool threadPool;
|
||||
private final AuthenticationService authenticationService;
|
||||
private final TokenService tokenService;
|
||||
private final SecurityContext securityContext;
|
||||
private static final Logger logger = LogManager.getLogger(TransportOpenIdConnectAuthenticateAction.class);
|
||||
|
||||
@Inject
|
||||
public TransportOpenIdConnectAuthenticateAction(ThreadPool threadPool, TransportService transportService,
|
||||
ActionFilters actionFilters, AuthenticationService authenticationService,
|
||||
TokenService tokenService) {
|
||||
TokenService tokenService, SecurityContext securityContext) {
|
||||
super(OpenIdConnectAuthenticateAction.NAME, transportService, actionFilters,
|
||||
(Writeable.Reader<OpenIdConnectAuthenticateRequest>) OpenIdConnectAuthenticateRequest::new);
|
||||
this.threadPool = threadPool;
|
||||
this.authenticationService = authenticationService;
|
||||
this.tokenService = tokenService;
|
||||
this.securityContext = securityContext;
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -57,7 +60,7 @@ public class TransportOpenIdConnectAuthenticateAction
|
||||
final OpenIdConnectToken token = new OpenIdConnectToken(request.getRedirectUri(), new State(request.getState()),
|
||||
new Nonce(request.getNonce()), request.getRealm());
|
||||
final ThreadContext threadContext = threadPool.getThreadContext();
|
||||
Authentication originatingAuthentication = Authentication.getAuthentication(threadContext);
|
||||
Authentication originatingAuthentication = securityContext.getAuthentication();
|
||||
try (ThreadContext.StoredContext ignore = threadContext.stashContext()) {
|
||||
authenticationService.authenticate(OpenIdConnectAuthenticateAction.NAME, request, token, ActionListener.wrap(
|
||||
authentication -> {
|
||||
|
@ -15,6 +15,7 @@ import org.elasticsearch.common.util.concurrent.ThreadContext;
|
||||
import org.elasticsearch.tasks.Task;
|
||||
import org.elasticsearch.threadpool.ThreadPool;
|
||||
import org.elasticsearch.transport.TransportService;
|
||||
import org.elasticsearch.xpack.core.security.SecurityContext;
|
||||
import org.elasticsearch.xpack.core.security.action.saml.SamlAuthenticateAction;
|
||||
import org.elasticsearch.xpack.core.security.action.saml.SamlAuthenticateRequest;
|
||||
import org.elasticsearch.xpack.core.security.action.saml.SamlAuthenticateResponse;
|
||||
@ -35,15 +36,17 @@ public final class TransportSamlAuthenticateAction extends HandledTransportActio
|
||||
private final ThreadPool threadPool;
|
||||
private final AuthenticationService authenticationService;
|
||||
private final TokenService tokenService;
|
||||
private final SecurityContext securityContext;
|
||||
|
||||
@Inject
|
||||
public TransportSamlAuthenticateAction(ThreadPool threadPool, TransportService transportService,
|
||||
ActionFilters actionFilters, AuthenticationService authenticationService,
|
||||
TokenService tokenService) {
|
||||
TokenService tokenService, SecurityContext securityContext) {
|
||||
super(SamlAuthenticateAction.NAME, transportService, actionFilters, SamlAuthenticateRequest::new);
|
||||
this.threadPool = threadPool;
|
||||
this.authenticationService = authenticationService;
|
||||
this.tokenService = tokenService;
|
||||
this.securityContext = securityContext;
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -51,7 +54,7 @@ public final class TransportSamlAuthenticateAction extends HandledTransportActio
|
||||
final SamlToken saml = new SamlToken(request.getSaml(), request.getValidRequestIds(), request.getRealm());
|
||||
logger.trace("Attempting to authenticate SamlToken [{}]", saml);
|
||||
final ThreadContext threadContext = threadPool.getThreadContext();
|
||||
Authentication originatingAuthentication = Authentication.getAuthentication(threadContext);
|
||||
Authentication originatingAuthentication = securityContext.getAuthentication();
|
||||
try (ThreadContext.StoredContext ignore = threadContext.stashContext()) {
|
||||
authenticationService.authenticate(SamlAuthenticateAction.NAME, request, saml, ActionListener.wrap(authentication -> {
|
||||
AuthenticationResult result = threadContext.getTransient(AuthenticationResult.THREAD_CONTEXT_KEY);
|
||||
|
@ -14,6 +14,7 @@ import org.elasticsearch.common.util.concurrent.ThreadContext;
|
||||
import org.elasticsearch.tasks.Task;
|
||||
import org.elasticsearch.threadpool.ThreadPool;
|
||||
import org.elasticsearch.transport.TransportService;
|
||||
import org.elasticsearch.xpack.core.security.SecurityContext;
|
||||
import org.elasticsearch.xpack.core.security.action.token.CreateTokenAction;
|
||||
import org.elasticsearch.xpack.core.security.action.token.CreateTokenRequest;
|
||||
import org.elasticsearch.xpack.core.security.action.token.CreateTokenRequest.GrantType;
|
||||
@ -41,14 +42,17 @@ public final class TransportCreateTokenAction extends HandledTransportAction<Cre
|
||||
private final ThreadPool threadPool;
|
||||
private final TokenService tokenService;
|
||||
private final AuthenticationService authenticationService;
|
||||
private final SecurityContext securityContext;
|
||||
|
||||
@Inject
|
||||
public TransportCreateTokenAction(ThreadPool threadPool, TransportService transportService, ActionFilters actionFilters,
|
||||
TokenService tokenService, AuthenticationService authenticationService) {
|
||||
TokenService tokenService, AuthenticationService authenticationService,
|
||||
SecurityContext securityContext) {
|
||||
super(CreateTokenAction.NAME, transportService, actionFilters, CreateTokenRequest::new);
|
||||
this.threadPool = threadPool;
|
||||
this.tokenService = tokenService;
|
||||
this.authenticationService = authenticationService;
|
||||
this.securityContext = securityContext;
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -61,7 +65,7 @@ public final class TransportCreateTokenAction extends HandledTransportAction<Cre
|
||||
authenticateAndCreateToken(type, request, listener);
|
||||
break;
|
||||
case CLIENT_CREDENTIALS:
|
||||
Authentication authentication = Authentication.getAuthentication(threadPool.getThreadContext());
|
||||
Authentication authentication = securityContext.getAuthentication();
|
||||
createToken(type, request, authentication, authentication, false, listener);
|
||||
break;
|
||||
default:
|
||||
@ -72,7 +76,7 @@ public final class TransportCreateTokenAction extends HandledTransportAction<Cre
|
||||
}
|
||||
|
||||
private void authenticateAndCreateToken(GrantType grantType, CreateTokenRequest request, ActionListener<CreateTokenResponse> listener) {
|
||||
Authentication originatingAuthentication = Authentication.getAuthentication(threadPool.getThreadContext());
|
||||
Authentication originatingAuthentication = securityContext.getAuthentication();
|
||||
try (ThreadContext.StoredContext ignore = threadPool.getThreadContext().stashContext()) {
|
||||
final AuthenticationToken authToken = extractAuthenticationToken(grantType, request, listener);
|
||||
if (authToken == null) {
|
||||
|
@ -12,6 +12,7 @@ import org.elasticsearch.common.inject.Inject;
|
||||
import org.elasticsearch.tasks.Task;
|
||||
import org.elasticsearch.threadpool.ThreadPool;
|
||||
import org.elasticsearch.transport.TransportService;
|
||||
import org.elasticsearch.xpack.core.security.SecurityContext;
|
||||
import org.elasticsearch.xpack.core.security.action.user.GetUserPrivilegesAction;
|
||||
import org.elasticsearch.xpack.core.security.action.user.GetUserPrivilegesRequest;
|
||||
import org.elasticsearch.xpack.core.security.action.user.GetUserPrivilegesResponse;
|
||||
@ -26,21 +27,28 @@ public class TransportGetUserPrivilegesAction extends HandledTransportAction<Get
|
||||
|
||||
private final ThreadPool threadPool;
|
||||
private final AuthorizationService authorizationService;
|
||||
private final SecurityContext securityContext;
|
||||
|
||||
@Inject
|
||||
public TransportGetUserPrivilegesAction(ThreadPool threadPool, TransportService transportService,
|
||||
ActionFilters actionFilters, AuthorizationService authorizationService) {
|
||||
ActionFilters actionFilters, AuthorizationService authorizationService,
|
||||
SecurityContext securityContext) {
|
||||
super(GetUserPrivilegesAction.NAME, transportService, actionFilters, GetUserPrivilegesRequest::new);
|
||||
this.threadPool = threadPool;
|
||||
this.authorizationService = authorizationService;
|
||||
this.securityContext = securityContext;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void doExecute(Task task, GetUserPrivilegesRequest request, ActionListener<GetUserPrivilegesResponse> listener) {
|
||||
final String username = request.username();
|
||||
|
||||
final Authentication authentication = Authentication.getAuthentication(threadPool.getThreadContext());
|
||||
final User user = authentication.getUser();
|
||||
final Authentication authentication = securityContext.getAuthentication();
|
||||
final User user = securityContext.getUser();
|
||||
if (authentication == null || user == null) {
|
||||
listener.onFailure(new IllegalArgumentException("cannot list privileges as there is no active user"));
|
||||
return;
|
||||
}
|
||||
if (user.principal().equals(username) == false) {
|
||||
listener.onFailure(new IllegalArgumentException("users may only list the privileges of their own account"));
|
||||
return;
|
||||
|
@ -58,8 +58,7 @@ public class TransportHasPrivilegesAction extends HandledTransportAction<HasPriv
|
||||
@Override
|
||||
protected void doExecute(Task task, HasPrivilegesRequest request, ActionListener<HasPrivilegesResponse> listener) {
|
||||
final String username = request.username();
|
||||
|
||||
final Authentication authentication = Authentication.getAuthentication(threadPool.getThreadContext());
|
||||
final Authentication authentication = securityContext.getAuthentication();
|
||||
final User user = authentication.getUser();
|
||||
if (user.principal().equals(username) == false) {
|
||||
listener.onFailure(new IllegalArgumentException("users may only check the privileges of their own account"));
|
||||
|
@ -13,10 +13,10 @@ import org.elasticsearch.common.settings.Settings;
|
||||
import org.elasticsearch.tasks.Task;
|
||||
import org.elasticsearch.threadpool.ThreadPool;
|
||||
import org.elasticsearch.transport.TransportService;
|
||||
import org.elasticsearch.xpack.core.security.SecurityContext;
|
||||
import org.elasticsearch.xpack.core.security.action.user.SetEnabledAction;
|
||||
import org.elasticsearch.xpack.core.security.action.user.SetEnabledRequest;
|
||||
import org.elasticsearch.xpack.core.security.action.user.SetEnabledResponse;
|
||||
import org.elasticsearch.xpack.core.security.authc.Authentication;
|
||||
import org.elasticsearch.xpack.core.security.user.AnonymousUser;
|
||||
import org.elasticsearch.xpack.core.security.user.SystemUser;
|
||||
import org.elasticsearch.xpack.core.security.user.XPackUser;
|
||||
@ -29,14 +29,16 @@ public class TransportSetEnabledAction extends HandledTransportAction<SetEnabled
|
||||
|
||||
private final Settings settings;
|
||||
private final ThreadPool threadPool;
|
||||
private final SecurityContext securityContext;
|
||||
private final NativeUsersStore usersStore;
|
||||
|
||||
@Inject
|
||||
public TransportSetEnabledAction(Settings settings, ThreadPool threadPool, TransportService transportService,
|
||||
ActionFilters actionFilters, NativeUsersStore usersStore) {
|
||||
ActionFilters actionFilters, SecurityContext securityContext, NativeUsersStore usersStore) {
|
||||
super(SetEnabledAction.NAME, transportService, actionFilters, SetEnabledRequest::new);
|
||||
this.settings = settings;
|
||||
this.threadPool = threadPool;
|
||||
this.securityContext = securityContext;
|
||||
this.usersStore = usersStore;
|
||||
}
|
||||
|
||||
@ -44,7 +46,7 @@ public class TransportSetEnabledAction extends HandledTransportAction<SetEnabled
|
||||
protected void doExecute(Task task, SetEnabledRequest request, ActionListener<SetEnabledResponse> listener) {
|
||||
final String username = request.username();
|
||||
// make sure the user is not disabling themselves
|
||||
if (Authentication.getAuthentication(threadPool.getThreadContext()).getUser().principal().equals(request.username())) {
|
||||
if (securityContext.getUser().principal().equals(request.username())) {
|
||||
listener.onFailure(new IllegalArgumentException("users may not update the enabled status of their own account"));
|
||||
return;
|
||||
} else if (SystemUser.NAME.equals(username) || XPackUser.NAME.equals(username)) {
|
||||
|
@ -36,6 +36,7 @@ import org.elasticsearch.xpack.core.security.authc.AuthenticationResult;
|
||||
import org.elasticsearch.xpack.core.security.authc.AuthenticationServiceField;
|
||||
import org.elasticsearch.xpack.core.security.authc.AuthenticationToken;
|
||||
import org.elasticsearch.xpack.core.security.authc.Realm;
|
||||
import org.elasticsearch.xpack.core.security.authc.support.AuthenticationContextSerializer;
|
||||
import org.elasticsearch.xpack.core.security.authz.AuthorizationEngine.EmptyAuthorizationInfo;
|
||||
import org.elasticsearch.xpack.core.security.support.Exceptions;
|
||||
import org.elasticsearch.xpack.core.security.user.AnonymousUser;
|
||||
@ -87,6 +88,7 @@ public class AuthenticationService {
|
||||
private final ApiKeyService apiKeyService;
|
||||
private final boolean runAsEnabled;
|
||||
private final boolean isAnonymousUserEnabled;
|
||||
private final AuthenticationContextSerializer authenticationSerializer;
|
||||
|
||||
public AuthenticationService(Settings settings, Realms realms, AuditTrailService auditTrail,
|
||||
AuthenticationFailureHandler failureHandler, ThreadPool threadPool,
|
||||
@ -109,6 +111,7 @@ public class AuthenticationService {
|
||||
this.lastSuccessfulAuthCache = null;
|
||||
}
|
||||
this.apiKeyService = apiKeyService;
|
||||
this.authenticationSerializer = new AuthenticationContextSerializer();
|
||||
}
|
||||
|
||||
/**
|
||||
@ -303,7 +306,7 @@ public class AuthenticationService {
|
||||
private void lookForExistingAuthentication(Consumer<Authentication> authenticationConsumer) {
|
||||
Runnable action;
|
||||
try {
|
||||
final Authentication authentication = Authentication.readFromContext(threadContext);
|
||||
final Authentication authentication = authenticationSerializer.readFromContext(threadContext);
|
||||
if (authentication != null && request instanceof AuditableRestRequest) {
|
||||
action = () -> listener.onFailure(request.tamperedRequest());
|
||||
} else {
|
||||
@ -611,7 +614,7 @@ public class AuthenticationService {
|
||||
listener.onResponse(authentication);
|
||||
};
|
||||
try {
|
||||
authentication.writeToContext(threadContext);
|
||||
authenticationSerializer.writeToContext(authentication, threadContext);
|
||||
} catch (Exception e) {
|
||||
action = () -> {
|
||||
logger.debug(
|
||||
|
@ -82,6 +82,7 @@ import org.elasticsearch.xpack.core.XPackField;
|
||||
import org.elasticsearch.xpack.core.XPackPlugin;
|
||||
import org.elasticsearch.xpack.core.XPackSettings;
|
||||
import org.elasticsearch.xpack.core.security.ScrollHelper;
|
||||
import org.elasticsearch.xpack.core.security.SecurityContext;
|
||||
import org.elasticsearch.xpack.core.security.authc.Authentication;
|
||||
import org.elasticsearch.xpack.core.security.authc.Authentication.AuthenticationType;
|
||||
import org.elasticsearch.xpack.core.security.authc.KeyAndTimestamp;
|
||||
@ -208,6 +209,7 @@ public final class TokenService {
|
||||
private final ExpiredTokenRemover expiredTokenRemover;
|
||||
private final boolean enabled;
|
||||
private final XPackLicenseState licenseState;
|
||||
private final SecurityContext securityContext;
|
||||
private volatile TokenKeys keyCache;
|
||||
private volatile long lastExpirationRunMs;
|
||||
private final AtomicLong createdTimeStamps = new AtomicLong(-1);
|
||||
@ -215,7 +217,7 @@ public final class TokenService {
|
||||
/**
|
||||
* Creates a new token service
|
||||
*/
|
||||
public TokenService(Settings settings, Clock clock, Client client, XPackLicenseState licenseState,
|
||||
public TokenService(Settings settings, Clock clock, Client client, XPackLicenseState licenseState, SecurityContext securityContext,
|
||||
SecurityIndexManager securityMainIndex, SecurityIndexManager securityTokensIndex,
|
||||
ClusterService clusterService) throws GeneralSecurityException {
|
||||
byte[] saltArr = new byte[SALT_BYTES];
|
||||
@ -226,6 +228,7 @@ public final class TokenService {
|
||||
this.expirationDelay = TOKEN_EXPIRATION.get(settings);
|
||||
this.client = client;
|
||||
this.licenseState = licenseState;
|
||||
this.securityContext = securityContext;
|
||||
this.securityMainIndex = securityMainIndex;
|
||||
this.securityTokensIndex = securityTokensIndex;
|
||||
this.lastExpirationRunMs = client.threadPool().relativeTimeInMillis();
|
||||
@ -801,7 +804,7 @@ public final class TokenService {
|
||||
findTokenFromRefreshToken(refreshToken,
|
||||
backoff,
|
||||
ActionListener.wrap(tokenDocHit -> {
|
||||
final Authentication clientAuth = Authentication.readFromContext(client.threadPool().getThreadContext());
|
||||
final Authentication clientAuth = securityContext.getAuthentication();
|
||||
innerRefresh(refreshToken, tokenDocHit.getId(), tokenDocHit.getSourceAsMap(), tokenDocHit.getSeqNo(),
|
||||
tokenDocHit.getPrimaryTerm(),
|
||||
clientAuth, backoff, refreshRequested, listener);
|
||||
|
@ -12,11 +12,12 @@ import org.elasticsearch.search.SearchContextMissingException;
|
||||
import org.elasticsearch.search.internal.ScrollContext;
|
||||
import org.elasticsearch.search.internal.SearchContext;
|
||||
import org.elasticsearch.transport.TransportRequest;
|
||||
import org.elasticsearch.xpack.security.audit.AuditTrailService;
|
||||
import org.elasticsearch.xpack.core.security.SecurityContext;
|
||||
import org.elasticsearch.xpack.core.security.authc.Authentication;
|
||||
import org.elasticsearch.xpack.core.security.authc.AuthenticationField;
|
||||
import org.elasticsearch.xpack.security.audit.AuditUtil;
|
||||
import org.elasticsearch.xpack.core.security.authz.AuthorizationEngine.AuthorizationInfo;
|
||||
import org.elasticsearch.xpack.security.audit.AuditTrailService;
|
||||
import org.elasticsearch.xpack.security.audit.AuditUtil;
|
||||
|
||||
import static org.elasticsearch.xpack.security.authz.AuthorizationService.AUTHORIZATION_INFO_KEY;
|
||||
import static org.elasticsearch.xpack.security.authz.AuthorizationService.ORIGINATING_ACTION_KEY;
|
||||
@ -32,12 +33,12 @@ import static org.elasticsearch.xpack.security.authz.AuthorizationService.ORIGIN
|
||||
*/
|
||||
public final class SecuritySearchOperationListener implements SearchOperationListener {
|
||||
|
||||
private final ThreadContext threadContext;
|
||||
private final SecurityContext securityContext;
|
||||
private final XPackLicenseState licenseState;
|
||||
private final AuditTrailService auditTrailService;
|
||||
|
||||
public SecuritySearchOperationListener(ThreadContext threadContext, XPackLicenseState licenseState, AuditTrailService auditTrail) {
|
||||
this.threadContext = threadContext;
|
||||
public SecuritySearchOperationListener(SecurityContext securityContext, XPackLicenseState licenseState, AuditTrailService auditTrail) {
|
||||
this.securityContext = securityContext;
|
||||
this.licenseState = licenseState;
|
||||
this.auditTrailService = auditTrail;
|
||||
}
|
||||
@ -48,8 +49,7 @@ public final class SecuritySearchOperationListener implements SearchOperationLis
|
||||
@Override
|
||||
public void onNewScrollContext(SearchContext searchContext) {
|
||||
if (licenseState.isAuthAllowed()) {
|
||||
searchContext.scrollContext().putInContext(AuthenticationField.AUTHENTICATION_KEY,
|
||||
Authentication.getAuthentication(threadContext));
|
||||
searchContext.scrollContext().putInContext(AuthenticationField.AUTHENTICATION_KEY, securityContext.getAuthentication());
|
||||
}
|
||||
}
|
||||
|
||||
@ -62,7 +62,8 @@ public final class SecuritySearchOperationListener implements SearchOperationLis
|
||||
if (licenseState.isAuthAllowed()) {
|
||||
if (searchContext.scrollContext() != null) {
|
||||
final Authentication originalAuth = searchContext.scrollContext().getFromContext(AuthenticationField.AUTHENTICATION_KEY);
|
||||
final Authentication current = Authentication.getAuthentication(threadContext);
|
||||
final Authentication current = securityContext.getAuthentication();
|
||||
final ThreadContext threadContext = securityContext.getThreadContext();
|
||||
final String action = threadContext.getTransient(ORIGINATING_ACTION_KEY);
|
||||
ensureAuthenticatedUserIsSame(originalAuth, current, auditTrailService, searchContext.id(), action, request,
|
||||
AuditUtil.extractRequestId(threadContext), threadContext.getTransient(AUTHORIZATION_INFO_KEY));
|
||||
|
@ -5,10 +5,10 @@
|
||||
*/
|
||||
package org.elasticsearch.xpack.security.ingest;
|
||||
|
||||
import org.elasticsearch.common.util.concurrent.ThreadContext;
|
||||
import org.elasticsearch.ingest.AbstractProcessor;
|
||||
import org.elasticsearch.ingest.IngestDocument;
|
||||
import org.elasticsearch.ingest.Processor;
|
||||
import org.elasticsearch.xpack.core.security.SecurityContext;
|
||||
import org.elasticsearch.xpack.core.security.authc.Authentication;
|
||||
import org.elasticsearch.xpack.core.security.user.User;
|
||||
|
||||
@ -18,7 +18,9 @@ import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.Set;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
import static org.elasticsearch.ingest.ConfigurationUtils.newConfigurationException;
|
||||
import static org.elasticsearch.ingest.ConfigurationUtils.readOptionalList;
|
||||
@ -31,20 +33,21 @@ public final class SetSecurityUserProcessor extends AbstractProcessor {
|
||||
|
||||
public static final String TYPE = "set_security_user";
|
||||
|
||||
private final ThreadContext threadContext;
|
||||
private final SecurityContext securityContext;
|
||||
private final String field;
|
||||
private final Set<Property> properties;
|
||||
|
||||
public SetSecurityUserProcessor(String tag, ThreadContext threadContext, String field, Set<Property> properties) {
|
||||
public
|
||||
SetSecurityUserProcessor(String tag, SecurityContext securityContext, String field, Set<Property> properties) {
|
||||
super(tag);
|
||||
this.threadContext = threadContext;
|
||||
this.securityContext = Objects.requireNonNull(securityContext, "security context must be provided");
|
||||
this.field = field;
|
||||
this.properties = properties;
|
||||
}
|
||||
|
||||
@Override
|
||||
public IngestDocument execute(IngestDocument ingestDocument) throws Exception {
|
||||
Authentication authentication = Authentication.getAuthentication(threadContext);
|
||||
Authentication authentication = securityContext.getAuthentication();
|
||||
if (authentication == null) {
|
||||
throw new IllegalStateException("No user authenticated, only use this processor via authenticated user");
|
||||
}
|
||||
@ -108,10 +111,10 @@ public final class SetSecurityUserProcessor extends AbstractProcessor {
|
||||
|
||||
public static final class Factory implements Processor.Factory {
|
||||
|
||||
private final ThreadContext threadContext;
|
||||
private final Supplier<SecurityContext> securityContext;
|
||||
|
||||
public Factory(ThreadContext threadContext) {
|
||||
this.threadContext = threadContext;
|
||||
public Factory(Supplier<SecurityContext> securityContext) {
|
||||
this.securityContext = securityContext;
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -128,7 +131,7 @@ public final class SetSecurityUserProcessor extends AbstractProcessor {
|
||||
} else {
|
||||
properties = EnumSet.allOf(Property.class);
|
||||
}
|
||||
return new SetSecurityUserProcessor(tag, threadContext, field, properties);
|
||||
return new SetSecurityUserProcessor(tag, securityContext.get(), field, properties);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -123,7 +123,7 @@ public interface ServerTransportFilter {
|
||||
if (securityAction.equals(TransportService.HANDSHAKE_ACTION_NAME) &&
|
||||
SystemUser.is(authentication.getUser()) == false) {
|
||||
securityContext.executeAsUser(SystemUser.INSTANCE, (ctx) -> {
|
||||
final Authentication replaced = Authentication.getAuthentication(threadContext);
|
||||
final Authentication replaced = securityContext.getAuthentication();
|
||||
authzService.authorize(replaced, securityAction, request, listener);
|
||||
}, version);
|
||||
} else {
|
||||
|
@ -74,7 +74,7 @@ public class SecurityContextTests extends ESTestCase {
|
||||
|
||||
IllegalStateException e = expectThrows(IllegalStateException.class,
|
||||
() -> securityContext.setUser(randomFrom(user, SystemUser.INSTANCE), Version.CURRENT));
|
||||
assertEquals("authentication is already present in the context", e.getMessage());
|
||||
assertEquals("authentication ([_xpack_security_authentication]) is already present in the context", e.getMessage());
|
||||
}
|
||||
|
||||
public void testExecuteAsUser() throws IOException {
|
||||
|
@ -40,6 +40,7 @@ import org.elasticsearch.transport.Transport;
|
||||
import org.elasticsearch.transport.TransportService;
|
||||
import org.elasticsearch.watcher.ResourceWatcherService;
|
||||
import org.elasticsearch.xpack.core.XPackSettings;
|
||||
import org.elasticsearch.xpack.core.security.SecurityContext;
|
||||
import org.elasticsearch.xpack.core.security.action.oidc.OpenIdConnectLogoutRequest;
|
||||
import org.elasticsearch.xpack.core.security.action.oidc.OpenIdConnectLogoutResponse;
|
||||
import org.elasticsearch.xpack.core.security.authc.Authentication;
|
||||
@ -177,8 +178,8 @@ public class TransportOpenIdConnectLogoutActionTests extends OpenIdConnectTestCa
|
||||
final XPackLicenseState licenseState = mock(XPackLicenseState.class);
|
||||
when(licenseState.isTokenServiceAllowed()).thenReturn(true);
|
||||
|
||||
tokenService = new TokenService(settings, Clock.systemUTC(), client, licenseState,
|
||||
securityIndex, securityIndex, clusterService);
|
||||
tokenService = new TokenService(settings, Clock.systemUTC(), client, licenseState, new SecurityContext(settings, threadContext),
|
||||
securityIndex, securityIndex, clusterService);
|
||||
|
||||
final TransportService transportService = new TransportService(Settings.EMPTY, mock(Transport.class), null,
|
||||
TransportService.NOOP_TRANSPORT_INTERCEPTOR, x -> null, null, Collections.emptySet());
|
||||
|
@ -57,6 +57,7 @@ import org.elasticsearch.threadpool.ThreadPool;
|
||||
import org.elasticsearch.transport.Transport;
|
||||
import org.elasticsearch.transport.TransportService;
|
||||
import org.elasticsearch.xpack.core.XPackSettings;
|
||||
import org.elasticsearch.xpack.core.security.SecurityContext;
|
||||
import org.elasticsearch.xpack.core.security.action.saml.SamlInvalidateSessionRequest;
|
||||
import org.elasticsearch.xpack.core.security.action.saml.SamlInvalidateSessionResponse;
|
||||
import org.elasticsearch.xpack.core.security.authc.Authentication;
|
||||
@ -206,7 +207,9 @@ public class TransportSamlInvalidateSessionActionTests extends SamlTestCase {
|
||||
when(licenseState.isTokenServiceAllowed()).thenReturn(true);
|
||||
|
||||
final ClusterService clusterService = ClusterServiceUtils.createClusterService(threadPool);
|
||||
tokenService = new TokenService(settings, Clock.systemUTC(), client, licenseState, securityIndex, securityIndex, clusterService);
|
||||
final SecurityContext securityContext = new SecurityContext(settings, threadContext);
|
||||
tokenService = new TokenService(settings, Clock.systemUTC(), client, licenseState, securityContext, securityIndex, securityIndex,
|
||||
clusterService);
|
||||
|
||||
final TransportService transportService = new TransportService(Settings.EMPTY, mock(Transport.class), null,
|
||||
TransportService.NOOP_TRANSPORT_INTERCEPTOR, x -> null, null, Collections.emptySet());
|
||||
|
@ -47,6 +47,7 @@ import org.elasticsearch.transport.Transport;
|
||||
import org.elasticsearch.transport.TransportService;
|
||||
import org.elasticsearch.watcher.ResourceWatcherService;
|
||||
import org.elasticsearch.xpack.core.XPackSettings;
|
||||
import org.elasticsearch.xpack.core.security.SecurityContext;
|
||||
import org.elasticsearch.xpack.core.security.action.saml.SamlLogoutRequest;
|
||||
import org.elasticsearch.xpack.core.security.action.saml.SamlLogoutResponse;
|
||||
import org.elasticsearch.xpack.core.security.authc.Authentication;
|
||||
@ -207,7 +208,9 @@ public class TransportSamlLogoutActionTests extends SamlTestCase {
|
||||
final XPackLicenseState licenseState = mock(XPackLicenseState.class);
|
||||
when(licenseState.isTokenServiceAllowed()).thenReturn(true);
|
||||
final ClusterService clusterService = ClusterServiceUtils.createClusterService(threadPool);
|
||||
tokenService = new TokenService(settings, Clock.systemUTC(), client, licenseState, securityIndex, securityIndex, clusterService);
|
||||
final SecurityContext securityContext = new SecurityContext(settings, threadContext);
|
||||
tokenService = new TokenService(settings, Clock.systemUTC(), client, licenseState, securityContext, securityIndex, securityIndex,
|
||||
clusterService);
|
||||
|
||||
final TransportService transportService = new TransportService(Settings.EMPTY, mock(Transport.class), null,
|
||||
TransportService.NOOP_TRANSPORT_INTERCEPTOR, x -> null, null, Collections.emptySet());
|
||||
|
@ -39,6 +39,7 @@ import org.elasticsearch.threadpool.TestThreadPool;
|
||||
import org.elasticsearch.threadpool.ThreadPool;
|
||||
import org.elasticsearch.transport.TransportService;
|
||||
import org.elasticsearch.xpack.core.XPackSettings;
|
||||
import org.elasticsearch.xpack.core.security.SecurityContext;
|
||||
import org.elasticsearch.xpack.core.security.action.token.CreateTokenAction;
|
||||
import org.elasticsearch.xpack.core.security.action.token.CreateTokenRequest;
|
||||
import org.elasticsearch.xpack.core.security.action.token.CreateTokenResponse;
|
||||
@ -81,6 +82,7 @@ public class TransportCreateTokenActionTests extends ESTestCase {
|
||||
private AtomicReference<IndexRequest> idxReqReference;
|
||||
private AuthenticationService authenticationService;
|
||||
private XPackLicenseState license;
|
||||
private SecurityContext securityContext;
|
||||
|
||||
@Before
|
||||
public void setupClient() {
|
||||
@ -126,6 +128,8 @@ public class TransportCreateTokenActionTests extends ESTestCase {
|
||||
return null;
|
||||
}).when(client).execute(eq(IndexAction.INSTANCE), any(IndexRequest.class), any(ActionListener.class));
|
||||
|
||||
securityContext = new SecurityContext(Settings.EMPTY, threadPool.getThreadContext());
|
||||
|
||||
// setup lifecycle service
|
||||
securityIndex = mock(SecurityIndexManager.class);
|
||||
doAnswer(invocationOnMock -> {
|
||||
@ -175,14 +179,14 @@ public class TransportCreateTokenActionTests extends ESTestCase {
|
||||
}
|
||||
|
||||
public void testClientCredentialsCreatesWithoutRefreshToken() throws Exception {
|
||||
final TokenService tokenService = new TokenService(SETTINGS, Clock.systemUTC(), client, license,
|
||||
final TokenService tokenService = new TokenService(SETTINGS, Clock.systemUTC(), client, license, securityContext,
|
||||
securityIndex, securityIndex, clusterService);
|
||||
Authentication authentication = new Authentication(new User("joe"), new Authentication.RealmRef("realm", "type", "node"), null);
|
||||
authentication.writeToContext(threadPool.getThreadContext());
|
||||
|
||||
final TransportCreateTokenAction action = new TransportCreateTokenAction(threadPool,
|
||||
mock(TransportService.class), new ActionFilters(Collections.emptySet()), tokenService,
|
||||
authenticationService);
|
||||
authenticationService, securityContext);
|
||||
final CreateTokenRequest createTokenRequest = new CreateTokenRequest();
|
||||
createTokenRequest.setGrantType("client_credentials");
|
||||
|
||||
@ -200,14 +204,14 @@ public class TransportCreateTokenActionTests extends ESTestCase {
|
||||
}
|
||||
|
||||
public void testPasswordGrantTypeCreatesWithRefreshToken() throws Exception {
|
||||
final TokenService tokenService = new TokenService(SETTINGS, Clock.systemUTC(), client, license,
|
||||
final TokenService tokenService = new TokenService(SETTINGS, Clock.systemUTC(), client, license, securityContext,
|
||||
securityIndex, securityIndex, clusterService);
|
||||
Authentication authentication = new Authentication(new User("joe"), new Authentication.RealmRef("realm", "type", "node"), null);
|
||||
authentication.writeToContext(threadPool.getThreadContext());
|
||||
|
||||
final TransportCreateTokenAction action = new TransportCreateTokenAction(threadPool,
|
||||
mock(TransportService.class), new ActionFilters(Collections.emptySet()), tokenService,
|
||||
authenticationService);
|
||||
authenticationService, securityContext);
|
||||
final CreateTokenRequest createTokenRequest = new CreateTokenRequest();
|
||||
createTokenRequest.setGrantType("password");
|
||||
createTokenRequest.setUsername("user");
|
||||
@ -227,14 +231,14 @@ public class TransportCreateTokenActionTests extends ESTestCase {
|
||||
}
|
||||
|
||||
public void testKerberosGrantTypeCreatesWithRefreshToken() throws Exception {
|
||||
final TokenService tokenService = new TokenService(SETTINGS, Clock.systemUTC(), client, license,
|
||||
final TokenService tokenService = new TokenService(SETTINGS, Clock.systemUTC(), client, license, securityContext,
|
||||
securityIndex, securityIndex, clusterService);
|
||||
Authentication authentication = new Authentication(new User("joe"), new Authentication.RealmRef("realm", "type", "node"), null);
|
||||
authentication.writeToContext(threadPool.getThreadContext());
|
||||
|
||||
final TransportCreateTokenAction action = new TransportCreateTokenAction(threadPool,
|
||||
mock(TransportService.class), new ActionFilters(Collections.emptySet()), tokenService,
|
||||
authenticationService);
|
||||
authenticationService, securityContext);
|
||||
final CreateTokenRequest createTokenRequest = new CreateTokenRequest();
|
||||
createTokenRequest.setGrantType("_kerberos");
|
||||
String failOrSuccess = randomBoolean() ? "fail" : "success";
|
||||
|
@ -16,10 +16,11 @@ import org.elasticsearch.test.ESTestCase;
|
||||
import org.elasticsearch.threadpool.ThreadPool;
|
||||
import org.elasticsearch.transport.Transport;
|
||||
import org.elasticsearch.transport.TransportService;
|
||||
import org.elasticsearch.xpack.core.security.SecurityContext;
|
||||
import org.elasticsearch.xpack.core.security.action.user.SetEnabledRequest;
|
||||
import org.elasticsearch.xpack.core.security.action.user.SetEnabledResponse;
|
||||
import org.elasticsearch.xpack.core.security.authc.Authentication;
|
||||
import org.elasticsearch.xpack.core.security.authc.AuthenticationField;
|
||||
import org.elasticsearch.xpack.core.security.authc.support.AuthenticationContextSerializer;
|
||||
import org.elasticsearch.xpack.core.security.user.AnonymousUser;
|
||||
import org.elasticsearch.xpack.core.security.user.ElasticUser;
|
||||
import org.elasticsearch.xpack.core.security.user.KibanaUser;
|
||||
@ -53,20 +54,23 @@ import static org.mockito.Mockito.when;
|
||||
*/
|
||||
public class TransportSetEnabledActionTests extends ESTestCase {
|
||||
|
||||
public void testAnonymousUser() {
|
||||
public void testAnonymousUser() throws Exception {
|
||||
Settings settings = Settings.builder().put(AnonymousUser.ROLES_SETTING.getKey(), "superuser").build();
|
||||
final User user = randomFrom(new ElasticUser(true), new KibanaUser(true), new User("joe"));
|
||||
ThreadPool threadPool = mock(ThreadPool.class);
|
||||
ThreadContext threadContext = new ThreadContext(Settings.EMPTY);
|
||||
Authentication authentication = mock(Authentication.class);
|
||||
when(threadPool.getThreadContext()).thenReturn(threadContext);
|
||||
threadContext.putTransient(AuthenticationField.AUTHENTICATION_KEY, authentication);
|
||||
Authentication authentication = mock(Authentication.class);
|
||||
when(authentication.getUser()).thenReturn(user);
|
||||
when(authentication.encode()).thenReturn(randomAlphaOfLength(24)); // just can't be null
|
||||
new AuthenticationContextSerializer().writeToContext(authentication, threadContext);
|
||||
|
||||
NativeUsersStore usersStore = mock(NativeUsersStore.class);
|
||||
TransportService transportService = new TransportService(Settings.EMPTY, mock(Transport.class), null,
|
||||
TransportService.NOOP_TRANSPORT_INTERCEPTOR, x -> null, null, Collections.emptySet());
|
||||
final SecurityContext securityContext = new SecurityContext(Settings.EMPTY, threadContext);
|
||||
TransportSetEnabledAction action = new TransportSetEnabledAction(settings, threadPool, transportService, mock(ActionFilters.class),
|
||||
usersStore);
|
||||
securityContext, usersStore);
|
||||
|
||||
SetEnabledRequest request = new SetEnabledRequest();
|
||||
request.username(new AnonymousUser(settings).principal());
|
||||
@ -92,19 +96,23 @@ public class TransportSetEnabledActionTests extends ESTestCase {
|
||||
verifyZeroInteractions(usersStore);
|
||||
}
|
||||
|
||||
public void testInternalUser() {
|
||||
public void testInternalUser() throws Exception {
|
||||
final User user = randomFrom(new ElasticUser(true), new KibanaUser(true), new User("joe"));
|
||||
ThreadPool threadPool = mock(ThreadPool.class);
|
||||
ThreadContext threadContext = new ThreadContext(Settings.EMPTY);
|
||||
Authentication authentication = mock(Authentication.class);
|
||||
when(threadPool.getThreadContext()).thenReturn(threadContext);
|
||||
threadContext.putTransient(AuthenticationField.AUTHENTICATION_KEY, authentication);
|
||||
|
||||
Authentication authentication = mock(Authentication.class);
|
||||
when(authentication.getUser()).thenReturn(user);
|
||||
when(authentication.encode()).thenReturn(randomAlphaOfLength(24)); // just can't be null
|
||||
new AuthenticationContextSerializer().writeToContext(authentication, threadContext);
|
||||
|
||||
NativeUsersStore usersStore = mock(NativeUsersStore.class);
|
||||
TransportService transportService = new TransportService(Settings.EMPTY, mock(Transport.class), null,
|
||||
TransportService.NOOP_TRANSPORT_INTERCEPTOR, x -> null, null, Collections.emptySet());
|
||||
final SecurityContext securityContext = new SecurityContext(Settings.EMPTY, threadContext);
|
||||
TransportSetEnabledAction action = new TransportSetEnabledAction(Settings.EMPTY, threadPool, transportService,
|
||||
mock(ActionFilters.class), usersStore);
|
||||
mock(ActionFilters.class), securityContext, usersStore);
|
||||
|
||||
SetEnabledRequest request = new SetEnabledRequest();
|
||||
request.username(randomFrom(SystemUser.INSTANCE.principal(), XPackUser.INSTANCE.principal()));
|
||||
@ -130,13 +138,15 @@ public class TransportSetEnabledActionTests extends ESTestCase {
|
||||
verifyZeroInteractions(usersStore);
|
||||
}
|
||||
|
||||
public void testValidUser() {
|
||||
public void testValidUser() throws Exception {
|
||||
ThreadPool threadPool = mock(ThreadPool.class);
|
||||
ThreadContext threadContext = new ThreadContext(Settings.EMPTY);
|
||||
Authentication authentication = mock(Authentication.class);
|
||||
when(threadPool.getThreadContext()).thenReturn(threadContext);
|
||||
threadContext.putTransient(AuthenticationField.AUTHENTICATION_KEY, authentication);
|
||||
|
||||
Authentication authentication = mock(Authentication.class);
|
||||
when(authentication.getUser()).thenReturn(new User("the runner"));
|
||||
when(authentication.encode()).thenReturn(randomAlphaOfLength(24)); // just can't be null
|
||||
new AuthenticationContextSerializer().writeToContext(authentication, threadContext);
|
||||
|
||||
final User user = randomFrom(new ElasticUser(true), new KibanaUser(true), new User("joe"));
|
||||
NativeUsersStore usersStore = mock(NativeUsersStore.class);
|
||||
@ -157,8 +167,9 @@ public class TransportSetEnabledActionTests extends ESTestCase {
|
||||
.setEnabled(eq(user.principal()), eq(request.enabled()), eq(request.getRefreshPolicy()), any(ActionListener.class));
|
||||
TransportService transportService = new TransportService(Settings.EMPTY, mock(Transport.class), null,
|
||||
TransportService.NOOP_TRANSPORT_INTERCEPTOR, x -> null, null, Collections.emptySet());
|
||||
final SecurityContext securityContext = new SecurityContext(Settings.EMPTY, threadContext);
|
||||
TransportSetEnabledAction action = new TransportSetEnabledAction(Settings.EMPTY, threadPool, transportService,
|
||||
mock(ActionFilters.class), usersStore);
|
||||
mock(ActionFilters.class), securityContext, usersStore);
|
||||
|
||||
final AtomicReference<Throwable> throwableRef = new AtomicReference<>();
|
||||
final AtomicReference<SetEnabledResponse> responseRef = new AtomicReference<>();
|
||||
@ -181,13 +192,15 @@ public class TransportSetEnabledActionTests extends ESTestCase {
|
||||
.setEnabled(eq(user.principal()), eq(request.enabled()), eq(request.getRefreshPolicy()), any(ActionListener.class));
|
||||
}
|
||||
|
||||
public void testException() {
|
||||
public void testException() throws Exception {
|
||||
ThreadPool threadPool = mock(ThreadPool.class);
|
||||
ThreadContext threadContext = new ThreadContext(Settings.EMPTY);
|
||||
Authentication authentication = mock(Authentication.class);
|
||||
when(threadPool.getThreadContext()).thenReturn(threadContext);
|
||||
threadContext.putTransient(AuthenticationField.AUTHENTICATION_KEY, authentication);
|
||||
|
||||
Authentication authentication = mock(Authentication.class);
|
||||
when(authentication.getUser()).thenReturn(new User("the runner"));
|
||||
when(authentication.encode()).thenReturn(randomAlphaOfLength(24)); // just can't be null
|
||||
new AuthenticationContextSerializer().writeToContext(authentication, threadContext);
|
||||
|
||||
final User user = randomFrom(new ElasticUser(true), new KibanaUser(true), new User("joe"));
|
||||
NativeUsersStore usersStore = mock(NativeUsersStore.class);
|
||||
@ -209,8 +222,9 @@ public class TransportSetEnabledActionTests extends ESTestCase {
|
||||
.setEnabled(eq(user.principal()), eq(request.enabled()), eq(request.getRefreshPolicy()), any(ActionListener.class));
|
||||
TransportService transportService = new TransportService(Settings.EMPTY, mock(Transport.class), null,
|
||||
TransportService.NOOP_TRANSPORT_INTERCEPTOR, x -> null, null, Collections.emptySet());
|
||||
final SecurityContext securityContext = new SecurityContext(Settings.EMPTY, threadContext);
|
||||
TransportSetEnabledAction action = new TransportSetEnabledAction(Settings.EMPTY, threadPool, transportService,
|
||||
mock(ActionFilters.class), usersStore);
|
||||
mock(ActionFilters.class), securityContext, usersStore);
|
||||
|
||||
final AtomicReference<Throwable> throwableRef = new AtomicReference<>();
|
||||
final AtomicReference<SetEnabledResponse> responseRef = new AtomicReference<>();
|
||||
@ -233,14 +247,16 @@ public class TransportSetEnabledActionTests extends ESTestCase {
|
||||
.setEnabled(eq(user.principal()), eq(request.enabled()), eq(request.getRefreshPolicy()), any(ActionListener.class));
|
||||
}
|
||||
|
||||
public void testUserModifyingThemselves() {
|
||||
public void testUserModifyingThemselves() throws Exception {
|
||||
final User user = randomFrom(new ElasticUser(true), new KibanaUser(true), new User("joe"));
|
||||
ThreadPool threadPool = mock(ThreadPool.class);
|
||||
ThreadContext threadContext = new ThreadContext(Settings.EMPTY);
|
||||
Authentication authentication = mock(Authentication.class);
|
||||
when(threadPool.getThreadContext()).thenReturn(threadContext);
|
||||
threadContext.putTransient(AuthenticationField.AUTHENTICATION_KEY, authentication);
|
||||
|
||||
Authentication authentication = mock(Authentication.class);
|
||||
when(authentication.getUser()).thenReturn(user);
|
||||
when(authentication.encode()).thenReturn(randomAlphaOfLength(24)); // just can't be null
|
||||
new AuthenticationContextSerializer().writeToContext(authentication, threadContext);
|
||||
|
||||
NativeUsersStore usersStore = mock(NativeUsersStore.class);
|
||||
SetEnabledRequest request = new SetEnabledRequest();
|
||||
@ -249,8 +265,9 @@ public class TransportSetEnabledActionTests extends ESTestCase {
|
||||
request.setRefreshPolicy(randomFrom(RefreshPolicy.values()));
|
||||
TransportService transportService = new TransportService(Settings.EMPTY, mock(Transport.class), null,
|
||||
TransportService.NOOP_TRANSPORT_INTERCEPTOR, x -> null, null, Collections.emptySet());
|
||||
final SecurityContext securityContext = new SecurityContext(Settings.EMPTY, threadContext);
|
||||
TransportSetEnabledAction action = new TransportSetEnabledAction(Settings.EMPTY, threadPool, transportService,
|
||||
mock(ActionFilters.class), usersStore);
|
||||
mock(ActionFilters.class), securityContext, usersStore);
|
||||
|
||||
final AtomicReference<Throwable> throwableRef = new AtomicReference<>();
|
||||
final AtomicReference<SetEnabledResponse> responseRef = new AtomicReference<>();
|
||||
|
@ -57,6 +57,7 @@ import org.elasticsearch.threadpool.ThreadPool;
|
||||
import org.elasticsearch.transport.TransportMessage;
|
||||
import org.elasticsearch.xpack.core.XPackField;
|
||||
import org.elasticsearch.xpack.core.XPackSettings;
|
||||
import org.elasticsearch.xpack.core.security.SecurityContext;
|
||||
import org.elasticsearch.xpack.core.security.authc.Authentication;
|
||||
import org.elasticsearch.xpack.core.security.authc.Authentication.AuthenticationType;
|
||||
import org.elasticsearch.xpack.core.security.authc.Authentication.RealmRef;
|
||||
@ -231,8 +232,10 @@ public class AuthenticationServiceTests extends ESTestCase {
|
||||
return null;
|
||||
}).when(securityIndex).checkIndexVersionThenExecute(any(Consumer.class), any(Runnable.class));
|
||||
ClusterService clusterService = ClusterServiceUtils.createClusterService(threadPool);
|
||||
final SecurityContext securityContext = new SecurityContext(settings, threadContext);
|
||||
apiKeyService = new ApiKeyService(settings, Clock.systemUTC(), client, licenseState, securityIndex, clusterService, threadPool);
|
||||
tokenService = new TokenService(settings, Clock.systemUTC(), client, licenseState, securityIndex, securityIndex, clusterService);
|
||||
tokenService = new TokenService(settings, Clock.systemUTC(), client, licenseState, securityContext, securityIndex, securityIndex,
|
||||
clusterService);
|
||||
service = new AuthenticationService(settings, realms, auditTrail, new DefaultAuthenticationFailureHandler(Collections.emptyMap()),
|
||||
threadPool, new AnonymousUser(settings), tokenService, apiKeyService);
|
||||
}
|
||||
|
@ -46,6 +46,7 @@ import org.elasticsearch.test.EqualsHashCodeTestUtils;
|
||||
import org.elasticsearch.threadpool.FixedExecutorBuilder;
|
||||
import org.elasticsearch.threadpool.ThreadPool;
|
||||
import org.elasticsearch.xpack.core.XPackSettings;
|
||||
import org.elasticsearch.xpack.core.security.SecurityContext;
|
||||
import org.elasticsearch.xpack.core.security.authc.Authentication;
|
||||
import org.elasticsearch.xpack.core.security.authc.Authentication.AuthenticationType;
|
||||
import org.elasticsearch.xpack.core.security.authc.Authentication.RealmRef;
|
||||
@ -103,6 +104,7 @@ public class TokenServiceTests extends ESTestCase {
|
||||
private Settings tokenServiceEnabledSettings = Settings.builder()
|
||||
.put(XPackSettings.TOKEN_SERVICE_ENABLED_SETTING.getKey(), true).build();
|
||||
private XPackLicenseState licenseState;
|
||||
private SecurityContext securityContext;
|
||||
|
||||
@Before
|
||||
public void setupClient() {
|
||||
@ -127,6 +129,7 @@ public class TokenServiceTests extends ESTestCase {
|
||||
return null;
|
||||
}).when(client).execute(eq(IndexAction.INSTANCE), any(IndexRequest.class), any(ActionListener.class));
|
||||
|
||||
this.securityContext = new SecurityContext(settings, threadPool.getThreadContext());
|
||||
// setup lifecycle service
|
||||
this.securityMainIndex = SecurityMocks.mockSecurityIndexManager();
|
||||
this.securityTokensIndex = SecurityMocks.mockSecurityIndexManager();
|
||||
@ -557,7 +560,7 @@ public class TokenServiceTests extends ESTestCase {
|
||||
TokenService tokenService = new TokenService(Settings.builder()
|
||||
.put(XPackSettings.TOKEN_SERVICE_ENABLED_SETTING.getKey(), false)
|
||||
.build(),
|
||||
Clock.systemUTC(), client, licenseState, securityMainIndex, securityTokensIndex, clusterService);
|
||||
Clock.systemUTC(), client, licenseState, securityContext, securityMainIndex, securityTokensIndex, clusterService);
|
||||
IllegalStateException e = expectThrows(IllegalStateException.class,
|
||||
() -> tokenService.createOAuth2Tokens(null, null, null, true, null));
|
||||
assertEquals("security tokens are not enabled", e.getMessage());
|
||||
@ -763,7 +766,8 @@ public class TokenServiceTests extends ESTestCase {
|
||||
}
|
||||
|
||||
private TokenService createTokenService(Settings settings, Clock clock) throws GeneralSecurityException {
|
||||
return new TokenService(settings, clock, client, licenseState, securityMainIndex, securityTokensIndex, clusterService);
|
||||
return new TokenService(settings, clock, client, licenseState, securityContext, securityMainIndex, securityTokensIndex,
|
||||
clusterService);
|
||||
}
|
||||
|
||||
private void mockGetTokenFromId(TokenService tokenService, String accessToken, Authentication authentication, boolean isExpired) {
|
||||
|
@ -19,6 +19,7 @@ import org.elasticsearch.test.ESTestCase;
|
||||
import org.elasticsearch.test.TestSearchContext;
|
||||
import org.elasticsearch.transport.TransportRequest;
|
||||
import org.elasticsearch.transport.TransportRequest.Empty;
|
||||
import org.elasticsearch.xpack.core.security.SecurityContext;
|
||||
import org.elasticsearch.xpack.core.security.authc.Authentication;
|
||||
import org.elasticsearch.xpack.core.security.authc.Authentication.RealmRef;
|
||||
import org.elasticsearch.xpack.core.security.authc.AuthenticationField;
|
||||
@ -47,11 +48,12 @@ public class SecuritySearchOperationListenerTests extends ESTestCase {
|
||||
XPackLicenseState licenseState = mock(XPackLicenseState.class);
|
||||
when(licenseState.isAuthAllowed()).thenReturn(false);
|
||||
ThreadContext threadContext = new ThreadContext(Settings.EMPTY);
|
||||
final SecurityContext securityContext = new SecurityContext(Settings.EMPTY, threadContext);
|
||||
AuditTrailService auditTrailService = mock(AuditTrailService.class);
|
||||
SearchContext searchContext = mock(SearchContext.class);
|
||||
when(searchContext.scrollContext()).thenReturn(new ScrollContext());
|
||||
|
||||
SecuritySearchOperationListener listener = new SecuritySearchOperationListener(threadContext, licenseState, auditTrailService);
|
||||
SecuritySearchOperationListener listener = new SecuritySearchOperationListener(securityContext, licenseState, auditTrailService);
|
||||
listener.onNewScrollContext(searchContext);
|
||||
listener.validateSearchContext(searchContext, Empty.INSTANCE);
|
||||
verify(licenseState, times(2)).isAuthAllowed();
|
||||
@ -66,11 +68,12 @@ public class SecuritySearchOperationListenerTests extends ESTestCase {
|
||||
XPackLicenseState licenseState = mock(XPackLicenseState.class);
|
||||
when(licenseState.isAuthAllowed()).thenReturn(true);
|
||||
ThreadContext threadContext = new ThreadContext(Settings.EMPTY);
|
||||
final SecurityContext securityContext = new SecurityContext(Settings.EMPTY, threadContext);
|
||||
AuditTrailService auditTrailService = mock(AuditTrailService.class);
|
||||
Authentication authentication = new Authentication(new User("test", "role"), new RealmRef("realm", "file", "node"), null);
|
||||
authentication.writeToContext(threadContext);
|
||||
|
||||
SecuritySearchOperationListener listener = new SecuritySearchOperationListener(threadContext, licenseState, auditTrailService);
|
||||
SecuritySearchOperationListener listener = new SecuritySearchOperationListener(securityContext, licenseState, auditTrailService);
|
||||
listener.onNewScrollContext(testSearchContext);
|
||||
|
||||
Authentication contextAuth = testSearchContext.scrollContext().getFromContext(AuthenticationField.AUTHENTICATION_KEY);
|
||||
@ -90,9 +93,10 @@ public class SecuritySearchOperationListenerTests extends ESTestCase {
|
||||
XPackLicenseState licenseState = mock(XPackLicenseState.class);
|
||||
when(licenseState.isAuthAllowed()).thenReturn(true);
|
||||
ThreadContext threadContext = new ThreadContext(Settings.EMPTY);
|
||||
final SecurityContext securityContext = new SecurityContext(Settings.EMPTY, threadContext);
|
||||
AuditTrailService auditTrailService = mock(AuditTrailService.class);
|
||||
|
||||
SecuritySearchOperationListener listener = new SecuritySearchOperationListener(threadContext, licenseState, auditTrailService);
|
||||
SecuritySearchOperationListener listener = new SecuritySearchOperationListener(securityContext, licenseState, auditTrailService);
|
||||
try (StoredContext ignore = threadContext.newStoredContext(false)) {
|
||||
Authentication authentication = new Authentication(new User("test", "role"), new RealmRef("realm", "file", "node"), null);
|
||||
authentication.writeToContext(threadContext);
|
||||
|
@ -6,20 +6,33 @@
|
||||
package org.elasticsearch.xpack.security.ingest;
|
||||
|
||||
import org.elasticsearch.ElasticsearchParseException;
|
||||
import org.elasticsearch.common.settings.Settings;
|
||||
import org.elasticsearch.common.util.concurrent.ThreadContext;
|
||||
import org.elasticsearch.test.ESTestCase;
|
||||
import org.elasticsearch.xpack.core.security.SecurityContext;
|
||||
import org.elasticsearch.xpack.security.ingest.SetSecurityUserProcessor.Property;
|
||||
import org.junit.Before;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.EnumSet;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import static org.elasticsearch.test.TestMatchers.throwableWithMessage;
|
||||
import static org.hamcrest.Matchers.containsString;
|
||||
import static org.hamcrest.Matchers.equalTo;
|
||||
|
||||
public class SetSecurityUserProcessorFactoryTests extends ESTestCase {
|
||||
|
||||
private SecurityContext securityContext;
|
||||
|
||||
@Before
|
||||
public void setupContext() {
|
||||
securityContext = new SecurityContext(Settings.EMPTY, new ThreadContext(Settings.EMPTY));
|
||||
}
|
||||
|
||||
public void testProcessor() throws Exception {
|
||||
SetSecurityUserProcessor.Factory factory = new SetSecurityUserProcessor.Factory(null);
|
||||
SetSecurityUserProcessor.Factory factory = new SetSecurityUserProcessor.Factory(() -> securityContext);
|
||||
Map<String, Object> config = new HashMap<>();
|
||||
config.put("field", "_field");
|
||||
SetSecurityUserProcessor processor = factory.create(null, "_tag", config);
|
||||
@ -28,7 +41,7 @@ public class SetSecurityUserProcessorFactoryTests extends ESTestCase {
|
||||
}
|
||||
|
||||
public void testProcessor_noField() throws Exception {
|
||||
SetSecurityUserProcessor.Factory factory = new SetSecurityUserProcessor.Factory(null);
|
||||
SetSecurityUserProcessor.Factory factory = new SetSecurityUserProcessor.Factory(() -> securityContext);
|
||||
Map<String, Object> config = new HashMap<>();
|
||||
ElasticsearchParseException e = expectThrows(ElasticsearchParseException.class, () -> factory.create(null, "_tag", config));
|
||||
assertThat(e.getMetadata("es.property_name").get(0), equalTo("field"));
|
||||
@ -37,7 +50,7 @@ public class SetSecurityUserProcessorFactoryTests extends ESTestCase {
|
||||
}
|
||||
|
||||
public void testProcessor_validProperties() throws Exception {
|
||||
SetSecurityUserProcessor.Factory factory = new SetSecurityUserProcessor.Factory(null);
|
||||
SetSecurityUserProcessor.Factory factory = new SetSecurityUserProcessor.Factory(() -> securityContext);
|
||||
Map<String, Object> config = new HashMap<>();
|
||||
config.put("field", "_field");
|
||||
config.put("properties", Arrays.asList(Property.USERNAME.name(), Property.ROLES.name()));
|
||||
@ -47,7 +60,7 @@ public class SetSecurityUserProcessorFactoryTests extends ESTestCase {
|
||||
}
|
||||
|
||||
public void testProcessor_invalidProperties() throws Exception {
|
||||
SetSecurityUserProcessor.Factory factory = new SetSecurityUserProcessor.Factory(null);
|
||||
SetSecurityUserProcessor.Factory factory = new SetSecurityUserProcessor.Factory(() -> securityContext);
|
||||
Map<String, Object> config = new HashMap<>();
|
||||
config.put("field", "_field");
|
||||
config.put("properties", Arrays.asList("invalid"));
|
||||
@ -57,4 +70,12 @@ public class SetSecurityUserProcessorFactoryTests extends ESTestCase {
|
||||
assertThat(e.getMetadata("es.processor_tag").get(0), equalTo("_tag"));
|
||||
}
|
||||
|
||||
public void testNullSecurityContextThrowsException() throws Exception {
|
||||
SetSecurityUserProcessor.Factory factory = new SetSecurityUserProcessor.Factory(() -> null);
|
||||
Map<String, Object> config = new HashMap<>();
|
||||
config.put("field", "_field");
|
||||
NullPointerException e = expectThrows(NullPointerException.class, () -> factory.create(null, "_tag", config));
|
||||
assertThat(e, throwableWithMessage(containsString("security context")));
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -9,10 +9,13 @@ import org.elasticsearch.common.settings.Settings;
|
||||
import org.elasticsearch.common.util.concurrent.ThreadContext;
|
||||
import org.elasticsearch.ingest.IngestDocument;
|
||||
import org.elasticsearch.test.ESTestCase;
|
||||
import org.elasticsearch.xpack.core.security.SecurityContext;
|
||||
import org.elasticsearch.xpack.core.security.authc.Authentication;
|
||||
import org.elasticsearch.xpack.core.security.authc.AuthenticationField;
|
||||
import org.elasticsearch.xpack.core.security.authc.Authentication.AuthenticationType;
|
||||
import org.elasticsearch.xpack.core.security.authc.support.AuthenticationContextSerializer;
|
||||
import org.elasticsearch.xpack.core.security.user.User;
|
||||
import org.elasticsearch.xpack.security.ingest.SetSecurityUserProcessor.Property;
|
||||
import org.junit.Before;
|
||||
import org.mockito.Mockito;
|
||||
|
||||
import java.util.Collections;
|
||||
@ -25,15 +28,23 @@ import static org.hamcrest.Matchers.equalTo;
|
||||
|
||||
public class SetSecurityUserProcessorTests extends ESTestCase {
|
||||
|
||||
public void testProcessor() throws Exception {
|
||||
User user = new User("_username", new String[]{"role1", "role2"}, "firstname lastname", "_email",
|
||||
Collections.singletonMap("key", "value"), true);
|
||||
private ThreadContext threadContext;
|
||||
private SecurityContext securityContext;
|
||||
|
||||
@Before
|
||||
public void setupObjects() {
|
||||
threadContext = new ThreadContext(Settings.EMPTY);
|
||||
securityContext = new SecurityContext(Settings.EMPTY, threadContext);
|
||||
}
|
||||
|
||||
public void testProcessorWithData() throws Exception {
|
||||
User user = new User("_username", new String[] { "role1", "role2" }, "firstname lastname", "_email",
|
||||
Collections.singletonMap("key", "value"), true);
|
||||
Authentication.RealmRef realmRef = new Authentication.RealmRef("_name", "_type", "_node_name");
|
||||
ThreadContext threadContext = new ThreadContext(Settings.EMPTY);
|
||||
threadContext.putTransient(AuthenticationField.AUTHENTICATION_KEY, new Authentication(user, realmRef, null));
|
||||
new Authentication(user, realmRef, null).writeToContext(threadContext);
|
||||
|
||||
IngestDocument ingestDocument = new IngestDocument(new HashMap<>(), new HashMap<>());
|
||||
SetSecurityUserProcessor processor = new SetSecurityUserProcessor("_tag", threadContext, "_field", EnumSet.allOf(Property.class));
|
||||
SetSecurityUserProcessor processor = new SetSecurityUserProcessor("_tag", securityContext, "_field", EnumSet.allOf(Property.class));
|
||||
processor.execute(ingestDocument);
|
||||
|
||||
Map<String, Object> result = ingestDocument.getFieldValue("_field", Map.class);
|
||||
@ -51,33 +62,32 @@ public class SetSecurityUserProcessorTests extends ESTestCase {
|
||||
User user = Mockito.mock(User.class);
|
||||
Authentication authentication = Mockito.mock(Authentication.class);
|
||||
Mockito.when(authentication.getUser()).thenReturn(user);
|
||||
|
||||
ThreadContext threadContext = new ThreadContext(Settings.EMPTY);
|
||||
threadContext.putTransient(AuthenticationField.AUTHENTICATION_KEY, authentication);
|
||||
Mockito.when(authentication.getAuthenticatedBy()).thenReturn(new Authentication.RealmRef("_name", "_type", "_node_name"));
|
||||
Mockito.when(authentication.getAuthenticationType()).thenReturn(AuthenticationType.REALM);
|
||||
Mockito.when(authentication.encode()).thenReturn(randomAlphaOfLength(24)); // don't care as long as it's not null
|
||||
new AuthenticationContextSerializer().writeToContext(authentication, threadContext);
|
||||
|
||||
IngestDocument ingestDocument = new IngestDocument(new HashMap<>(), new HashMap<>());
|
||||
SetSecurityUserProcessor processor = new SetSecurityUserProcessor("_tag", threadContext, "_field", EnumSet.allOf(Property.class));
|
||||
SetSecurityUserProcessor processor = new SetSecurityUserProcessor("_tag", securityContext, "_field", EnumSet.allOf(Property.class));
|
||||
processor.execute(ingestDocument);
|
||||
Map result = ingestDocument.getFieldValue("_field", Map.class);
|
||||
assertThat(result.size(), equalTo(0));
|
||||
}
|
||||
|
||||
public void testNoCurrentUser() throws Exception {
|
||||
ThreadContext threadContext = new ThreadContext(Settings.EMPTY);
|
||||
IngestDocument ingestDocument = new IngestDocument(new HashMap<>(), new HashMap<>());
|
||||
SetSecurityUserProcessor processor = new SetSecurityUserProcessor("_tag", threadContext, "_field", EnumSet.allOf(Property.class));
|
||||
SetSecurityUserProcessor processor = new SetSecurityUserProcessor("_tag", securityContext, "_field", EnumSet.allOf(Property.class));
|
||||
IllegalStateException e = expectThrows(IllegalStateException.class, () -> processor.execute(ingestDocument));
|
||||
assertThat(e.getMessage(), equalTo("No user authenticated, only use this processor via authenticated user"));
|
||||
}
|
||||
|
||||
public void testUsernameProperties() throws Exception {
|
||||
ThreadContext threadContext = new ThreadContext(Settings.EMPTY);
|
||||
User user = new User("_username", null, null);
|
||||
Authentication.RealmRef realmRef = new Authentication.RealmRef("_name", "_type", "_node_name");
|
||||
threadContext.putTransient(AuthenticationField.AUTHENTICATION_KEY, new Authentication(user, realmRef, null));
|
||||
new Authentication(user, realmRef, null).writeToContext(threadContext);
|
||||
|
||||
IngestDocument ingestDocument = new IngestDocument(new HashMap<>(), new HashMap<>());
|
||||
SetSecurityUserProcessor processor = new SetSecurityUserProcessor("_tag", threadContext, "_field", EnumSet.of(Property.USERNAME));
|
||||
SetSecurityUserProcessor processor = new SetSecurityUserProcessor("_tag", securityContext, "_field", EnumSet.of(Property.USERNAME));
|
||||
processor.execute(ingestDocument);
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
@ -87,13 +97,12 @@ public class SetSecurityUserProcessorTests extends ESTestCase {
|
||||
}
|
||||
|
||||
public void testRolesProperties() throws Exception {
|
||||
ThreadContext threadContext = new ThreadContext(Settings.EMPTY);
|
||||
User user = new User(randomAlphaOfLengthBetween(4, 12), "role1", "role2");
|
||||
Authentication.RealmRef realmRef = new Authentication.RealmRef("_name", "_type", "_node_name");
|
||||
threadContext.putTransient(AuthenticationField.AUTHENTICATION_KEY, new Authentication(user, realmRef, null));
|
||||
new Authentication(user, realmRef, null).writeToContext(threadContext);
|
||||
|
||||
IngestDocument ingestDocument = new IngestDocument(new HashMap<>(), new HashMap<>());
|
||||
SetSecurityUserProcessor processor = new SetSecurityUserProcessor("_tag", threadContext, "_field", EnumSet.of(Property.ROLES));
|
||||
SetSecurityUserProcessor processor = new SetSecurityUserProcessor("_tag", securityContext, "_field", EnumSet.of(Property.ROLES));
|
||||
processor.execute(ingestDocument);
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
@ -103,13 +112,13 @@ public class SetSecurityUserProcessorTests extends ESTestCase {
|
||||
}
|
||||
|
||||
public void testFullNameProperties() throws Exception {
|
||||
ThreadContext threadContext = new ThreadContext(Settings.EMPTY);
|
||||
User user = new User(randomAlphaOfLengthBetween(4, 12), null, "_full_name", null, null, true);
|
||||
Authentication.RealmRef realmRef = new Authentication.RealmRef("_name", "_type", "_node_name");
|
||||
threadContext.putTransient(AuthenticationField.AUTHENTICATION_KEY, new Authentication(user, realmRef, null));
|
||||
new Authentication(user, realmRef, null).writeToContext(threadContext);
|
||||
|
||||
IngestDocument ingestDocument = new IngestDocument(new HashMap<>(), new HashMap<>());
|
||||
SetSecurityUserProcessor processor = new SetSecurityUserProcessor("_tag", threadContext, "_field", EnumSet.of(Property.FULL_NAME));
|
||||
SetSecurityUserProcessor processor
|
||||
= new SetSecurityUserProcessor("_tag", securityContext, "_field", EnumSet.of(Property.FULL_NAME));
|
||||
processor.execute(ingestDocument);
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
@ -119,13 +128,12 @@ public class SetSecurityUserProcessorTests extends ESTestCase {
|
||||
}
|
||||
|
||||
public void testEmailProperties() throws Exception {
|
||||
ThreadContext threadContext = new ThreadContext(Settings.EMPTY);
|
||||
User user = new User(randomAlphaOfLengthBetween(4, 12), null, null, "_email", null, true);
|
||||
Authentication.RealmRef realmRef = new Authentication.RealmRef("_name", "_type", "_node_name");
|
||||
threadContext.putTransient(AuthenticationField.AUTHENTICATION_KEY, new Authentication(user, realmRef, null));
|
||||
new Authentication(user, realmRef, null).writeToContext(threadContext);
|
||||
|
||||
IngestDocument ingestDocument = new IngestDocument(new HashMap<>(), new HashMap<>());
|
||||
SetSecurityUserProcessor processor = new SetSecurityUserProcessor("_tag", threadContext, "_field", EnumSet.of(Property.EMAIL));
|
||||
SetSecurityUserProcessor processor = new SetSecurityUserProcessor("_tag", securityContext, "_field", EnumSet.of(Property.EMAIL));
|
||||
processor.execute(ingestDocument);
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
@ -135,13 +143,12 @@ public class SetSecurityUserProcessorTests extends ESTestCase {
|
||||
}
|
||||
|
||||
public void testMetadataProperties() throws Exception {
|
||||
ThreadContext threadContext = new ThreadContext(Settings.EMPTY);
|
||||
User user = new User(randomAlphaOfLengthBetween(4, 12), null, null, null, Collections.singletonMap("key", "value"), true);
|
||||
Authentication.RealmRef realmRef = new Authentication.RealmRef("_name", "_type", "_node_name");
|
||||
threadContext.putTransient(AuthenticationField.AUTHENTICATION_KEY, new Authentication(user, realmRef, null));
|
||||
new Authentication(user, realmRef, null).writeToContext(threadContext);
|
||||
|
||||
IngestDocument ingestDocument = new IngestDocument(new HashMap<>(), new HashMap<>());
|
||||
SetSecurityUserProcessor processor = new SetSecurityUserProcessor("_tag", threadContext, "_field", EnumSet.of(Property.METADATA));
|
||||
SetSecurityUserProcessor processor = new SetSecurityUserProcessor("_tag", securityContext, "_field", EnumSet.of(Property.METADATA));
|
||||
processor.execute(ingestDocument);
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
@ -152,12 +159,11 @@ public class SetSecurityUserProcessorTests extends ESTestCase {
|
||||
}
|
||||
|
||||
public void testOverwriteExistingField() throws Exception {
|
||||
ThreadContext threadContext = new ThreadContext(Settings.EMPTY);
|
||||
User user = new User("_username", null, null);
|
||||
Authentication.RealmRef realmRef = new Authentication.RealmRef("_name", "_type", "_node_name");
|
||||
threadContext.putTransient(AuthenticationField.AUTHENTICATION_KEY, new Authentication(user, realmRef, null));
|
||||
new Authentication(user, realmRef, null).writeToContext(threadContext);
|
||||
|
||||
SetSecurityUserProcessor processor = new SetSecurityUserProcessor("_tag", threadContext, "_field", EnumSet.of(Property.USERNAME));
|
||||
SetSecurityUserProcessor processor = new SetSecurityUserProcessor("_tag", securityContext, "_field", EnumSet.of(Property.USERNAME));
|
||||
|
||||
IngestDocument ingestDocument = new IngestDocument(new HashMap<>(), new HashMap<>());
|
||||
ingestDocument.setFieldValue("_field", "test");
|
||||
|
Loading…
x
Reference in New Issue
Block a user