Require elastic password be bootstrapped (elastic/x-pack-elasticsearch#1962)

This is related to elastic/x-pack-elasticsearch#1217. This commit requires that the elastic password
be bootstrapped for the user to be authenticated. As a result it removes
the special "setup" mode that allowed the user to be authenticated from
localhost.

Additionally, this commit updates the tests to work with this
functionality.

Original commit: elastic/x-pack-elasticsearch@d0d5d697a7
This commit is contained in:
Tim Brooks 2017-07-13 19:59:50 -05:00 committed by GitHub
parent 4de6d9ebe5
commit 6d04eacdec
38 changed files with 264 additions and 568 deletions

View File

@ -201,54 +201,21 @@ integTestCluster {
setting 'xpack.monitoring.exporters._local.type', 'local'
setting 'xpack.monitoring.exporters._local.enabled', 'false'
setting 'xpack.monitoring.collection.interval', '-1'
keystoreSetting 'es.bootstrap.passwd.elastic', 'x-pack-test-password'
distribution = 'zip' // this is important since we use the reindex module in ML
setupCommand 'setupTestUser', 'bin/x-pack/users', 'useradd', 'x_pack_rest_user', '-p', 'x-pack-test-password', '-r', 'superuser'
waitCondition = { NodeInfo node, AntBuilder ant ->
File tmpFile = new File(node.cwd, 'wait.success')
for (int i = 0; i < 10; i++) {
HttpURLConnection httpURLConnection = null;
try {
httpURLConnection = (HttpURLConnection) new URL("http://${node.httpUri()}/_xpack/security/user/elastic/_password")
.openConnection();
httpURLConnection.setRequestProperty("Authorization", "Basic " +
Base64.getEncoder().encodeToString("elastic:".getBytes(StandardCharsets.UTF_8)));
httpURLConnection.setRequestMethod("PUT");
httpURLConnection.setDoOutput(true);
httpURLConnection.setRequestProperty("Content-Type", "application/json; charset=UTF-8");
httpURLConnection.connect();
OutputStream out = httpURLConnection.getOutputStream();
out.write("{\"password\": \"x-pack-test-password\"}".getBytes(StandardCharsets.UTF_8));
out.close()
if (httpURLConnection.getResponseCode() == 200) {
break
}
} catch (Exception e) {
httpURLConnection.disconnect()
if (i == 9) {
logger.error("final attempt to set elastic password", e)
} else {
logger.debug("failed to set elastic password", e)
}
} finally {
if (httpURLConnection != null) {
httpURLConnection.disconnect();
}
}
// did not start, so wait a bit before trying again
Thread.sleep(500L);
}
for (int i = 0; i < 10; i++) {
// we use custom wait logic here as the elastic user is not available immediately and ant.get will fail when a 401 is returned
HttpURLConnection httpURLConnection = null;
try {
httpURLConnection = (HttpURLConnection) new URL("http://${node.httpUri()}/_cluster/health?wait_for_nodes=${numNodes}&wait_for_status=yellow").openConnection();
httpURLConnection.setRequestProperty("Authorization", "Basic " +
Base64.getEncoder().encodeToString("elastic:x-pack-test-password".getBytes(StandardCharsets.UTF_8)));
Base64.getEncoder().encodeToString("x_pack_rest_user:x-pack-test-password".getBytes(StandardCharsets.UTF_8)));
httpURLConnection.setRequestMethod("GET");
httpURLConnection.connect();
if (httpURLConnection.getResponseCode() == 200) {
@ -358,4 +325,5 @@ run {
setting 'xpack.security.enabled', 'true'
setting 'xpack.monitoring.enabled', 'true'
setting 'xpack.watcher.enabled', 'true'
keystoreSetting 'es.bootstrap.passwd.elastic', 'password'
}

View File

@ -294,7 +294,7 @@ public class AuthenticationService extends AbstractComponent {
"An error occurred while attempting to authenticate [{}] against realm [{}]",
authenticationToken.principal(), realm.name()), ex);
userListener.onFailure(ex);
}), request);
}));
} else {
userListener.onResponse(null);
}
@ -451,21 +451,16 @@ public class AuthenticationService extends AbstractComponent {
}
}
abstract static class AuditableRequest implements IncomingRequest {
abstract static class AuditableRequest {
final AuditTrail auditTrail;
final AuthenticationFailureHandler failureHandler;
final ThreadContext threadContext;
private final InetSocketAddress remoteAddress;
private final RequestType requestType;
AuditableRequest(AuditTrail auditTrail, AuthenticationFailureHandler failureHandler, ThreadContext threadContext,
RequestType requestType, InetSocketAddress remoteAddress) {
AuditableRequest(AuditTrail auditTrail, AuthenticationFailureHandler failureHandler, ThreadContext threadContext) {
this.auditTrail = auditTrail;
this.failureHandler = failureHandler;
this.threadContext = threadContext;
this.remoteAddress = remoteAddress;
this.requestType = requestType;
}
abstract void realmAuthenticationFailed(AuthenticationToken token, String realm);
@ -482,13 +477,6 @@ public class AuthenticationService extends AbstractComponent {
abstract void authenticationSuccess(String realm, User user);
public InetSocketAddress getRemoteAddress() {
return remoteAddress;
}
public RequestType getType() {
return requestType;
}
}
static class AuditableTransportRequest extends AuditableRequest {
@ -498,7 +486,7 @@ public class AuthenticationService extends AbstractComponent {
AuditableTransportRequest(AuditTrail auditTrail, AuthenticationFailureHandler failureHandler, ThreadContext threadContext,
String action, TransportMessage message) {
super(auditTrail, failureHandler, threadContext, getType(message), getRemoteAddress(message));
super(auditTrail, failureHandler, threadContext);
this.action = action;
this.message = message;
}
@ -552,14 +540,6 @@ public class AuthenticationService extends AbstractComponent {
return "transport request action [" + action + "]";
}
private static RequestType getType(TransportMessage message) {
return message.remoteAddress() == null ? RequestType.LOCAL_NODE : RequestType.REMOTE_NODE;
}
private static InetSocketAddress getRemoteAddress(TransportMessage message) {
TransportAddress transportAddress = message.remoteAddress();
return transportAddress == null ? null : transportAddress.address();
}
}
static class AuditableRestRequest extends AuditableRequest {
@ -569,7 +549,7 @@ public class AuthenticationService extends AbstractComponent {
@SuppressWarnings("unchecked")
AuditableRestRequest(AuditTrail auditTrail, AuthenticationFailureHandler failureHandler, ThreadContext threadContext,
RestRequest request) {
super(auditTrail, failureHandler, threadContext, RequestType.REST, (InetSocketAddress) request.getRemoteAddress());
super(auditTrail, failureHandler, threadContext);
this.request = request;
}

View File

@ -1,36 +0,0 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License;
* you may not use this file except in compliance with the Elastic License.
*/
package org.elasticsearch.xpack.security.authc;
import java.net.InetSocketAddress;
/**
* This represents an incoming request that needs to be authenticated
*/
public interface IncomingRequest {
/**
* This method returns the remote address for the request. It will be null if the request is a
* local transport request.
*
* @return the remote socket address
*/
InetSocketAddress getRemoteAddress();
/**
* This returns the type of request that is incoming. It can be a rest request, a remote
* transport request, or a local transport request.
*
* @return the request type
*/
RequestType getType();
enum RequestType {
REST,
REMOTE_NODE,
LOCAL_NODE
}
}

View File

@ -96,10 +96,8 @@ public abstract class Realm implements Comparable<Realm> {
*
* @param token The authentication token
* @param listener The listener to pass the authentication result to
* @param incomingRequest the request that is being authenticated
*/
public abstract void authenticate(AuthenticationToken token, ActionListener<AuthenticationResult> listener,
IncomingRequest incomingRequest);
public abstract void authenticate(AuthenticationToken token, ActionListener<AuthenticationResult> listener);
/**
* Looks up the user identified the String identifier. A successful lookup will call the {@link ActionListener#onResponse}

View File

@ -8,7 +8,6 @@ package org.elasticsearch.xpack.security.authc.esnative;
import org.elasticsearch.action.ActionListener;
import org.elasticsearch.common.settings.Setting;
import org.elasticsearch.xpack.security.authc.AuthenticationResult;
import org.elasticsearch.xpack.security.authc.IncomingRequest;
import org.elasticsearch.xpack.security.authc.RealmConfig;
import org.elasticsearch.xpack.security.authc.support.CachingUsernamePasswordRealm;
import org.elasticsearch.xpack.security.authc.support.UsernamePasswordToken;
@ -36,8 +35,7 @@ public class NativeRealm extends CachingUsernamePasswordRealm {
}
@Override
protected void doAuthenticate(UsernamePasswordToken token, ActionListener<AuthenticationResult> listener,
IncomingRequest incomingRequest) {
protected void doAuthenticate(UsernamePasswordToken token, ActionListener<AuthenticationResult> listener) {
userStore.verifyPassword(token.principal(), token.credentials(), listener);
}

View File

@ -9,25 +9,17 @@ import org.apache.logging.log4j.message.ParameterizedMessage;
import org.apache.logging.log4j.util.Supplier;
import org.elasticsearch.Version;
import org.elasticsearch.action.ActionListener;
import org.elasticsearch.cluster.ClusterChangedEvent;
import org.elasticsearch.cluster.ClusterStateListener;
import org.elasticsearch.common.settings.SecureSetting;
import org.elasticsearch.common.settings.SecureString;
import org.elasticsearch.common.settings.Setting;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.common.util.concurrent.ThreadContext;
import org.elasticsearch.env.Environment;
import org.elasticsearch.gateway.GatewayService;
import org.elasticsearch.threadpool.ThreadPool;
import org.elasticsearch.xpack.XPackSettings;
import org.elasticsearch.xpack.security.InternalClient;
import org.elasticsearch.xpack.security.Security;
import org.elasticsearch.xpack.security.SecurityLifecycleService;
import org.elasticsearch.xpack.security.authc.AuthenticationResult;
import org.elasticsearch.xpack.security.action.user.ChangePasswordAction;
import org.elasticsearch.xpack.security.action.user.ChangePasswordRequest;
import org.elasticsearch.xpack.security.action.user.ChangePasswordResponse;
import org.elasticsearch.xpack.security.authc.IncomingRequest;
import org.elasticsearch.xpack.security.authc.AuthenticationResult;
import org.elasticsearch.xpack.security.authc.RealmConfig;
import org.elasticsearch.xpack.security.authc.esnative.NativeUsersStore.ReservedUserInfo;
import org.elasticsearch.xpack.security.authc.support.CachingUsernamePasswordRealm;
@ -41,16 +33,11 @@ import org.elasticsearch.xpack.security.user.KibanaUser;
import org.elasticsearch.xpack.security.user.LogstashSystemUser;
import org.elasticsearch.xpack.security.user.User;
import java.net.InetAddress;
import java.net.NetworkInterface;
import java.net.SocketException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.locks.ReentrantLock;
/**
* A realm for predefined users. These users can only be modified in terms of changing their passwords; no other modifications are allowed.
@ -62,7 +49,6 @@ public class ReservedRealm extends CachingUsernamePasswordRealm {
public static final SecureString EMPTY_PASSWORD_TEXT = new SecureString("".toCharArray());
static final char[] EMPTY_PASSWORD_HASH = Hasher.BCRYPT.hash(EMPTY_PASSWORD_TEXT);
static final char[] OLD_DEFAULT_PASSWORD_HASH = Hasher.BCRYPT.hash(new SecureString("changeme".toCharArray()));
private static final ReservedUserInfo DEFAULT_USER_INFO = new ReservedUserInfo(EMPTY_PASSWORD_HASH, true, true);
private static final ReservedUserInfo DISABLED_USER_INFO = new ReservedUserInfo(EMPTY_PASSWORD_HASH, false, true);
@ -89,25 +75,7 @@ public class ReservedRealm extends CachingUsernamePasswordRealm {
}
@Override
protected void doAuthenticate(UsernamePasswordToken token, ActionListener<AuthenticationResult> listener,
IncomingRequest incomingRequest) {
if (incomingRequest.getType() != IncomingRequest.RequestType.REST) {
doAuthenticate(token, listener, false);
} else {
InetAddress address = incomingRequest.getRemoteAddress().getAddress();
try {
// This checks if the address is the loopback address or if it is bound to one of this machine's
// network interfaces. This is because we want to allow requests that originate from this machine.
final boolean isLocalMachine = address.isLoopbackAddress() || NetworkInterface.getByInetAddress(address) != null;
doAuthenticate(token, listener, isLocalMachine);
} catch (SocketException e) {
listener.onFailure(Exceptions.authenticationError("failed to authenticate user [{}]", e, token.principal()));
}
}
}
private void doAuthenticate(UsernamePasswordToken token, ActionListener<AuthenticationResult> listener, boolean acceptEmptyPassword) {
protected void doAuthenticate(UsernamePasswordToken token, ActionListener<AuthenticationResult> listener) {
if (realmEnabled == false) {
listener.onResponse(AuthenticationResult.notHandled());
} else if (isReserved(token.principal(), config.globalSettings()) == false) {
@ -118,17 +86,7 @@ public class ReservedRealm extends CachingUsernamePasswordRealm {
if (userInfo != null) {
try {
if (userInfo.hasEmptyPassword) {
// norelease
// Accepting the OLD_DEFAULT_PASSWORD_HASH is a transition step. We do not want to support
// this in a release.
if (isSetupMode(token.principal(), acceptEmptyPassword) == false) {
result = AuthenticationResult.terminate("failed to authenticate user [" + token.principal() + "]", null);
} else if (verifyPassword(userInfo, token)
|| Hasher.BCRYPT.verify(token.credentials(), OLD_DEFAULT_PASSWORD_HASH)) {
result = AuthenticationResult.success(getUser(token.principal(), userInfo));
} else {
result = AuthenticationResult.terminate("failed to authenticate user [" + token.principal() + "]", null);
}
result = AuthenticationResult.terminate("failed to authenticate user [" + token.principal() + "]", null);
} else if (verifyPassword(userInfo, token)) {
final User user = getUser(token.principal(), userInfo);
result = AuthenticationResult.success(user);
@ -136,7 +94,7 @@ public class ReservedRealm extends CachingUsernamePasswordRealm {
result = AuthenticationResult.terminate("failed to authenticate user [" + token.principal() + "]", null);
}
} finally {
if (userInfo.passwordHash != EMPTY_PASSWORD_HASH && userInfo.passwordHash != OLD_DEFAULT_PASSWORD_HASH) {
if (userInfo.passwordHash != EMPTY_PASSWORD_HASH) {
Arrays.fill(userInfo.passwordHash, (char) 0);
}
}
@ -149,10 +107,6 @@ public class ReservedRealm extends CachingUsernamePasswordRealm {
}
}
private boolean isSetupMode(String userName, boolean acceptEmptyPassword) {
return ElasticUser.NAME.equals(userName) && acceptEmptyPassword;
}
private boolean verifyPassword(ReservedUserInfo userInfo, UsernamePasswordToken token) {
if (Hasher.BCRYPT.verify(token.credentials(), userInfo.passwordHash)) {
return true;
@ -225,7 +179,7 @@ public class ReservedRealm extends CachingUsernamePasswordRealm {
assert username != null;
switch (username) {
case ElasticUser.NAME:
return new ElasticUser(userInfo.enabled, userInfo.hasEmptyPassword);
return new ElasticUser(userInfo.enabled);
case KibanaUser.NAME:
return new KibanaUser(userInfo.enabled);
case LogstashSystemUser.NAME:
@ -249,8 +203,7 @@ public class ReservedRealm extends CachingUsernamePasswordRealm {
List<User> users = new ArrayList<>(4);
ReservedUserInfo userInfo = reservedUserInfos.get(ElasticUser.NAME);
users.add(new ElasticUser(userInfo == null || userInfo.enabled,
userInfo == null || userInfo.hasEmptyPassword));
users.add(new ElasticUser(userInfo == null || userInfo.enabled));
userInfo = reservedUserInfos.get(KibanaUser.NAME);
users.add(new KibanaUser(userInfo == null || userInfo.enabled));

View File

@ -5,19 +5,18 @@
*/
package org.elasticsearch.xpack.security.authc.file;
import java.util.Map;
import java.util.Set;
import org.elasticsearch.action.ActionListener;
import org.elasticsearch.common.settings.Setting;
import org.elasticsearch.watcher.ResourceWatcherService;
import org.elasticsearch.xpack.security.authc.AuthenticationResult;
import org.elasticsearch.xpack.security.authc.IncomingRequest;
import org.elasticsearch.xpack.security.authc.RealmConfig;
import org.elasticsearch.xpack.security.authc.support.CachingUsernamePasswordRealm;
import org.elasticsearch.xpack.security.authc.support.UsernamePasswordToken;
import org.elasticsearch.xpack.security.user.User;
import java.util.Map;
import java.util.Set;
public class FileRealm extends CachingUsernamePasswordRealm {
public static final String TYPE = "file";
@ -39,8 +38,7 @@ public class FileRealm extends CachingUsernamePasswordRealm {
}
@Override
protected void doAuthenticate(UsernamePasswordToken token, ActionListener<AuthenticationResult> listener,
IncomingRequest incomingRequest) {
protected void doAuthenticate(UsernamePasswordToken token, ActionListener<AuthenticationResult> listener) {
final AuthenticationResult result = userPasswdStore.verifyPassword(token.principal(), token.credentials(), () -> {
String[] roles = userRolesStore.roles(token.principal());
return new User(token.principal(), roles);

View File

@ -5,13 +5,6 @@
*/
package org.elasticsearch.xpack.security.authc.ldap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.atomic.AtomicReference;
import java.util.function.Consumer;
import java.util.function.Supplier;
import com.unboundid.ldap.sdk.LDAPException;
import org.apache.logging.log4j.Logger;
import org.apache.logging.log4j.message.ParameterizedMessage;
@ -29,7 +22,6 @@ import org.elasticsearch.threadpool.ThreadPool;
import org.elasticsearch.threadpool.ThreadPool.Names;
import org.elasticsearch.watcher.ResourceWatcherService;
import org.elasticsearch.xpack.security.authc.AuthenticationResult;
import org.elasticsearch.xpack.security.authc.IncomingRequest;
import org.elasticsearch.xpack.security.authc.RealmConfig;
import org.elasticsearch.xpack.security.authc.RealmSettings;
import org.elasticsearch.xpack.security.authc.ldap.support.LdapLoadBalancing;
@ -45,6 +37,13 @@ import org.elasticsearch.xpack.security.authc.support.mapper.NativeRoleMappingSt
import org.elasticsearch.xpack.security.user.User;
import org.elasticsearch.xpack.ssl.SSLService;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.atomic.AtomicReference;
import java.util.function.Consumer;
import java.util.function.Supplier;
/**
* Authenticates username/password tokens against ldap, locates groups and maps them to roles.
@ -143,8 +142,7 @@ public final class LdapRealm extends CachingUsernamePasswordRealm {
* This user will then be passed to the listener
*/
@Override
protected void doAuthenticate(UsernamePasswordToken token, ActionListener<AuthenticationResult> listener,
IncomingRequest incomingRequest) {
protected void doAuthenticate(UsernamePasswordToken token, ActionListener<AuthenticationResult> listener) {
// we submit to the threadpool because authentication using LDAP will execute blocking I/O for a bind request and we don't want
// network threads stuck waiting for a socket to connect. After the bind, then all interaction with LDAP should be async
final CancellableLdapRunnable cancellableLdapRunnable = new CancellableLdapRunnable(listener,

View File

@ -5,18 +5,6 @@
*/
package org.elasticsearch.xpack.security.authc.pki;
import javax.net.ssl.X509TrustManager;
import java.security.cert.Certificate;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import org.apache.logging.log4j.Logger;
import org.apache.logging.log4j.message.ParameterizedMessage;
import org.apache.logging.log4j.util.Supplier;
@ -31,7 +19,6 @@ import org.elasticsearch.env.Environment;
import org.elasticsearch.watcher.ResourceWatcherService;
import org.elasticsearch.xpack.security.authc.AuthenticationResult;
import org.elasticsearch.xpack.security.authc.AuthenticationToken;
import org.elasticsearch.xpack.security.authc.IncomingRequest;
import org.elasticsearch.xpack.security.authc.Realm;
import org.elasticsearch.xpack.security.authc.RealmConfig;
import org.elasticsearch.xpack.security.authc.RealmSettings;
@ -42,6 +29,18 @@ import org.elasticsearch.xpack.security.user.User;
import org.elasticsearch.xpack.ssl.CertUtils;
import org.elasticsearch.xpack.ssl.SSLConfigurationSettings;
import javax.net.ssl.X509TrustManager;
import java.security.cert.Certificate;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class PkiRealm extends Realm {
public static final String PKI_CERT_HEADER_NAME = "__SECURITY_CLIENT_CERTIFICATE";
@ -83,8 +82,7 @@ public class PkiRealm extends Realm {
}
@Override
public void authenticate(AuthenticationToken authToken, ActionListener<AuthenticationResult> listener,
IncomingRequest incomingRequest) {
public void authenticate(AuthenticationToken authToken, ActionListener<AuthenticationResult> listener) {
X509AuthenticationToken token = (X509AuthenticationToken)authToken;
if (isCertificateChainTrusted(trustManager, token, logger) == false) {
listener.onResponse(AuthenticationResult.unsuccessful("Certificate for " + token.dn() + " is not trusted", null));

View File

@ -20,7 +20,6 @@ import org.elasticsearch.common.settings.Setting;
import org.elasticsearch.common.unit.TimeValue;
import org.elasticsearch.xpack.security.authc.AuthenticationResult;
import org.elasticsearch.xpack.security.authc.AuthenticationToken;
import org.elasticsearch.xpack.security.authc.IncomingRequest;
import org.elasticsearch.xpack.security.authc.RealmConfig;
import org.elasticsearch.xpack.security.user.User;
@ -72,17 +71,15 @@ public abstract class CachingUsernamePasswordRealm extends UsernamePasswordRealm
* doAuthenticate
* @param authToken The authentication token
* @param listener to be called at completion
* @param incomingRequest the request that is being authenticated
*/
@Override
public final void authenticate(AuthenticationToken authToken, ActionListener<AuthenticationResult> listener,
IncomingRequest incomingRequest) {
public final void authenticate(AuthenticationToken authToken, ActionListener<AuthenticationResult> listener) {
UsernamePasswordToken token = (UsernamePasswordToken) authToken;
try {
if (cache == null) {
doAuthenticate(token, listener, incomingRequest);
doAuthenticate(token, listener);
} else {
authenticateWithCache(token, listener, incomingRequest);
authenticateWithCache(token, listener);
}
} catch (Exception e) {
// each realm should handle exceptions, if we get one here it should be considered fatal
@ -90,8 +87,7 @@ public abstract class CachingUsernamePasswordRealm extends UsernamePasswordRealm
}
}
private void authenticateWithCache(UsernamePasswordToken token, ActionListener<AuthenticationResult> listener,
IncomingRequest incomingRequest) {
private void authenticateWithCache(UsernamePasswordToken token, ActionListener<AuthenticationResult> listener) {
UserWithHash userWithHash = cache.get(token.principal());
if (userWithHash == null) {
if (logger.isDebugEnabled()) {
@ -104,7 +100,7 @@ public abstract class CachingUsernamePasswordRealm extends UsernamePasswordRealm
logger.debug("realm [{}] authenticated user [{}], with roles [{}]", name(), token.principal(), user.roles());
}
listener.onResponse(result);
}, listener::onFailure), incomingRequest);
}, listener::onFailure));
} else if (userWithHash.hasHash()) {
if (userWithHash.verify(token.credentials())) {
if (userWithHash.user.enabled()) {
@ -122,7 +118,7 @@ public abstract class CachingUsernamePasswordRealm extends UsernamePasswordRealm
user.enabled(), user.roles());
}
listener.onResponse(result);
}, listener::onFailure), incomingRequest);
}, listener::onFailure));
}
} else {
cache.invalidate(token.principal());
@ -133,7 +129,7 @@ public abstract class CachingUsernamePasswordRealm extends UsernamePasswordRealm
name(), token.principal(), user.roles());
}
listener.onResponse(result);
}, listener::onFailure), incomingRequest);
}, listener::onFailure));
}
} else {
cache.invalidate(token.principal());
@ -144,12 +140,11 @@ public abstract class CachingUsernamePasswordRealm extends UsernamePasswordRealm
"realm [{}] authenticated user [{}] with roles [{}]", name(), token.principal(), user.roles());
}
listener.onResponse(result);
}, listener::onFailure), incomingRequest);
}, listener::onFailure));
}
}
private void doAuthenticateAndCache(UsernamePasswordToken token, ActionListener<AuthenticationResult> listener,
IncomingRequest incomingRequest) {
private void doAuthenticateAndCache(UsernamePasswordToken token, ActionListener<AuthenticationResult> listener) {
ActionListener<AuthenticationResult> wrapped = ActionListener.wrap((result) -> {
Objects.requireNonNull(result, "AuthenticationResult cannot be null");
if (result.getStatus() == AuthenticationResult.Status.SUCCESS) {
@ -160,7 +155,7 @@ public abstract class CachingUsernamePasswordRealm extends UsernamePasswordRealm
listener.onResponse(result);
}, listener::onFailure);
doAuthenticate(token, wrapped, incomingRequest);
doAuthenticate(token, wrapped);
}
@Override
@ -170,8 +165,7 @@ public abstract class CachingUsernamePasswordRealm extends UsernamePasswordRealm
return stats;
}
protected abstract void doAuthenticate(UsernamePasswordToken token, ActionListener<AuthenticationResult> listener,
IncomingRequest incomingRequest);
protected abstract void doAuthenticate(UsernamePasswordToken token, ActionListener<AuthenticationResult> listener);
@Override
public final void lookupUser(String username, ActionListener<User> listener) {

View File

@ -149,15 +149,6 @@ public class AuthorizationService extends AbstractComponent {
throw denial(authentication, action, request);
}
// norelease
// TODO: This functionality is disabled as it is not yet compatible with the upgrade process
// If the user is the elastic user in setup mode, then only change password requests can be authorized
// if (ElasticUser.isElasticUserInSetupMode(authentication.getUser())
// && ChangePasswordAction.NAME.equals(action) == false
// && ClusterHealthAction.NAME.equals(action) == false) {
// throw denial(authentication, action, request);
// }
// get the roles of the authenticated user, which may be different than the effective
Role permission = userRole;

View File

@ -18,27 +18,8 @@ public class ElasticUser extends User {
public static final String NAME = "elastic";
private static final String ROLE_NAME = "superuser";
private static final String SETUP_MODE = "_setup_mode";
public ElasticUser(boolean enabled) {
this(enabled, false);
}
public ElasticUser(boolean enabled, boolean setupMode) {
super(NAME, new String[] { ROLE_NAME }, null, null, metadata(setupMode), enabled);
}
public static boolean isElasticUserInSetupMode(User user) {
return NAME.equals(user.principal()) && Boolean.TRUE.equals(user.metadata().get(SETUP_MODE));
}
private static Map<String, Object> metadata(boolean setupMode) {
if (setupMode == false) {
return MetadataUtils.DEFAULT_RESERVED_METADATA;
} else {
HashMap<String, Object> metadata = new HashMap<>(MetadataUtils.DEFAULT_RESERVED_METADATA);
metadata.put(SETUP_MODE, true);
return metadata;
}
super(NAME, new String[] { ROLE_NAME }, null, null, MetadataUtils.DEFAULT_RESERVED_METADATA, enabled);
}
}

View File

@ -19,7 +19,6 @@ import org.elasticsearch.test.SecuritySettingsSource;
import org.elasticsearch.xpack.security.action.realm.ClearRealmCacheRequest;
import org.elasticsearch.xpack.security.action.realm.ClearRealmCacheResponse;
import org.elasticsearch.xpack.security.authc.AuthenticationResult;
import org.elasticsearch.xpack.security.authc.IncomingRequest;
import org.elasticsearch.xpack.security.authc.Realm;
import org.elasticsearch.xpack.security.authc.Realms;
import org.elasticsearch.xpack.security.authc.support.Hasher;
@ -42,7 +41,6 @@ import static org.hamcrest.Matchers.equalTo;
import static org.hamcrest.Matchers.not;
import static org.hamcrest.Matchers.notNullValue;
import static org.hamcrest.Matchers.sameInstance;
import static org.mockito.Mockito.mock;
public class ClearRealmsCacheTests extends SecurityIntegTestCase {
private static final String USERS_PASSWD_HASHED = new String(Hasher.BCRYPT.hash(new SecureString("passwd".toCharArray())));
@ -236,7 +234,7 @@ public class ClearRealmsCacheTests extends SecurityIntegTestCase {
for (Realm realm : realms) {
for (String username : usernames) {
PlainActionFuture<AuthenticationResult> future = new PlainActionFuture<>();
realm.authenticate(tokens.get(username), future, mock(IncomingRequest.class));
realm.authenticate(tokens.get(username), future);
User user = future.actionGet().getUser();
assertThat(user, notNullValue());
Map<Realm, User> realmToUser = users.get(username);
@ -253,7 +251,7 @@ public class ClearRealmsCacheTests extends SecurityIntegTestCase {
for (String username : usernames) {
for (Realm realm : realms) {
PlainActionFuture<AuthenticationResult> future = new PlainActionFuture<>();
realm.authenticate(tokens.get(username), future, mock(IncomingRequest.class));
realm.authenticate(tokens.get(username), future);
User user = future.actionGet().getUser();
assertThat(user, sameInstance(users.get(username).get(realm)));
}
@ -266,7 +264,7 @@ public class ClearRealmsCacheTests extends SecurityIntegTestCase {
for (String username : usernames) {
for (Realm realm : realms) {
PlainActionFuture<AuthenticationResult> future = new PlainActionFuture<>();
realm.authenticate(tokens.get(username), future, mock(IncomingRequest.class));
realm.authenticate(tokens.get(username), future);
User user = future.actionGet().getUser();
assertThat(user, notNullValue());
scenario.assertEviction(users.get(username).get(realm), user);

View File

@ -35,7 +35,10 @@ public abstract class NativeRealmIntegTestCase extends SecurityIntegTestCase {
@Before
public void ensureNativeStoresStarted() throws Exception {
assertSecurityIndexActive();
setupReservedPasswords();
if (shouldSetReservedUserPasswords()) {
ensureElasticPasswordBootstrapped();
setupReservedPasswords();
}
}
@After
@ -68,18 +71,14 @@ public abstract class NativeRealmIntegTestCase extends SecurityIntegTestCase {
}
public void setupReservedPasswords() throws IOException {
if (shouldSetReservedUserPasswords() == false) {
return;
}
logger.info("setting up reserved passwords for test");
SecureString defaultPassword = new SecureString("".toCharArray());
for (String username : Arrays.asList(ElasticUser.NAME, KibanaUser.NAME, BeatsSystemUser.NAME, LogstashSystemUser.NAME)) {
SecureString authPassword = username.equals(ElasticUser.NAME) ? defaultPassword : reservedPassword;
for (String username : Arrays.asList(KibanaUser.NAME, BeatsSystemUser.NAME, LogstashSystemUser.NAME)) {
String payload = "{\"password\": \"" + new String(reservedPassword.getChars()) + "\"}";
HttpEntity entity = new NStringEntity(payload, ContentType.APPLICATION_JSON);
BasicHeader authHeader = new BasicHeader(UsernamePasswordToken.BASIC_AUTH_HEADER,
UsernamePasswordToken.basicAuthHeaderValue(ElasticUser.NAME, authPassword));
UsernamePasswordToken.basicAuthHeaderValue(ElasticUser.NAME, SecuritySettingsSource.TEST_PASSWORD_SECURE_STRING));
String route = "/_xpack/security/user/" + username + "/_password";
Response response = getRestClient().performRequest("PUT", route, Collections.emptyMap(), entity, authHeader);
}

View File

@ -6,6 +6,7 @@
package org.elasticsearch.test;
import org.elasticsearch.AbstractOldXPackIndicesBackwardsCompatibilityTestCase;
import org.elasticsearch.action.ActionListener;
import org.elasticsearch.action.admin.cluster.health.ClusterHealthResponse;
import org.elasticsearch.action.admin.cluster.node.info.NodeInfo;
import org.elasticsearch.action.admin.cluster.node.info.NodesInfoResponse;
@ -35,6 +36,7 @@ import org.elasticsearch.xpack.XPackSettings;
import org.elasticsearch.xpack.ml.MachineLearning;
import org.elasticsearch.xpack.security.InternalClient;
import org.elasticsearch.xpack.security.Security;
import org.elasticsearch.xpack.security.authc.esnative.ReservedRealm;
import org.elasticsearch.xpack.security.client.SecurityClient;
import org.junit.AfterClass;
import org.junit.Before;
@ -48,6 +50,7 @@ import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.concurrent.CountDownLatch;
import java.util.function.Function;
import java.util.stream.Collectors;
@ -184,7 +187,7 @@ public abstract class SecurityIntegTestCase extends ESIntegTestCase {
Collection<String> pluginNames =
nodeInfo.getPlugins().getPluginInfos().stream().map(p -> p.getClassname()).collect(Collectors.toList());
assertThat("plugin [" + xpackPluginClass().getName() + "] not found in [" + pluginNames + "]", pluginNames,
hasItem(xpackPluginClass().getName()));
hasItem(xpackPluginClass().getName()));
}
}
@ -209,7 +212,7 @@ public abstract class SecurityIntegTestCase extends ESIntegTestCase {
Settings.Builder customBuilder = Settings.builder().put(customSettings);
if (customBuilder.getSecureSettings() != null) {
SecuritySettingsSource.addSecureSettings(builder, secureSettings ->
secureSettings.merge((MockSecureSettings) customBuilder.getSecureSettings()));
secureSettings.merge((MockSecureSettings) customBuilder.getSecureSettings()));
}
return builder.build();
}
@ -408,7 +411,7 @@ public abstract class SecurityIntegTestCase extends ESIntegTestCase {
}
@Override
protected Function<Client,Client> getClientWrapper() {
protected Function<Client, Client> getClientWrapper() {
Map<String, String> headers = Collections.singletonMap("Authorization",
basicAuthHeaderValue(nodeClientUsername(), nodeClientPassword()));
// we need to wrap node clients because we do not specify a user for nodes and all requests will use the system
@ -445,7 +448,11 @@ public abstract class SecurityIntegTestCase extends ESIntegTestCase {
}
public void assertSecurityIndexActive() throws Exception {
for (ClusterService clusterService : internalCluster().getInstances(ClusterService.class)) {
assertSecurityIndexActive(internalCluster());
}
public void assertSecurityIndexActive(InternalTestCluster internalTestCluster) throws Exception {
for (ClusterService clusterService : internalTestCluster.getInstances(ClusterService.class)) {
assertBusy(() -> {
ClusterState clusterState = clusterService.state();
assertFalse(clusterState.blocks().hasGlobalBlock(GatewayService.STATE_NOT_RECOVERED_BLOCK));
@ -461,6 +468,29 @@ public abstract class SecurityIntegTestCase extends ESIntegTestCase {
}
}
public void ensureElasticPasswordBootstrapped() throws Exception {
ensureElasticPasswordBootstrapped(internalCluster());
}
public void ensureElasticPasswordBootstrapped(InternalTestCluster internalTestCluster) throws Exception {
CountDownLatch latch = new CountDownLatch(1);
SecureString testPasswordHashed = new SecureString(SecuritySettingsSource.TEST_PASSWORD_HASHED.toCharArray());
ReservedRealm reservedRealm = internalTestCluster.getInstances(ReservedRealm.class).iterator().next();
reservedRealm.bootstrapElasticUserCredentials(testPasswordHashed, new ActionListener<Boolean>() {
@Override
public void onResponse(Boolean passwordSet) {
latch.countDown();
}
@Override
public void onFailure(Exception e) {
logger.error("Exception attempting to bootstrap password for test", e);
fail("Failed to bootstrap elastic password for test due to exception: " + e.getMessage());
}
});
latch.await();
}
public void assertSecurityIndexWriteable() throws Exception {
for (ClusterService clusterService : internalCluster().getInstances(ClusterService.class)) {
assertBusy(() -> {

View File

@ -32,15 +32,14 @@ import static org.hamcrest.Matchers.equalTo;
public class DatafeedJobsRestIT extends ESRestTestCase {
private static final String BASIC_AUTH_VALUE_ELASTIC =
basicAuthHeaderValue("elastic", SecuritySettingsSource.TEST_PASSWORD_SECURE_STRING);
private static final String BASIC_AUTH_VALUE_SUPER_USER =
basicAuthHeaderValue("x_pack_rest_user", SecuritySettingsSource.TEST_PASSWORD_SECURE_STRING);
private static final String BASIC_AUTH_VALUE_ML_ADMIN =
basicAuthHeaderValue("ml_admin", SecuritySettingsSource.TEST_PASSWORD_SECURE_STRING);
@Override
protected Settings restClientSettings() {
return Settings.builder().put(ThreadContext.PREFIX + ".Authorization",
BASIC_AUTH_VALUE_ELASTIC).build();
return Settings.builder().put(ThreadContext.PREFIX + ".Authorization", BASIC_AUTH_VALUE_SUPER_USER).build();
}
@Override
@ -51,10 +50,6 @@ public class DatafeedJobsRestIT extends ESRestTestCase {
@Before
public void setUpData() throws Exception {
String password = new String(SecuritySettingsSource.TEST_PASSWORD_SECURE_STRING.getChars());
String elasticUserPayload = "{\"password\" : \"" + password + "\"}";
client().performRequest("put", "_xpack/security/user/elastic/_password", Collections.emptyMap(),
new StringEntity(elasticUserPayload, ContentType.APPLICATION_JSON));
// This user has admin rights on machine learning, but (importantly for the tests) no
// rights on any of the data indexes
@ -310,7 +305,7 @@ public class DatafeedJobsRestIT extends ESRestTestCase {
new DatafeedBuilder(datafeedId, jobId, "airline-data-aggs", "response").build();
// This should be disallowed, because ml_admin is trying to preview a datafeed created by
// by another user (elastic in this case) that will reveal the content of an index they
// by another user (x_pack_rest_user in this case) that will reveal the content of an index they
// don't have permission to search directly
ResponseException e = expectThrows(ResponseException.class, () ->
client().performRequest("get",
@ -581,7 +576,7 @@ public class DatafeedJobsRestIT extends ESRestTestCase {
boolean source;
String scriptedFields;
String aggregations;
String authHeader = BASIC_AUTH_VALUE_ELASTIC;
String authHeader = BASIC_AUTH_VALUE_SUPER_USER;
DatafeedBuilder(String datafeedId, String jobId, String index, String type) {
this.datafeedId = datafeedId;

View File

@ -36,7 +36,8 @@ import static org.hamcrest.Matchers.not;
public class MlJobIT extends ESRestTestCase {
private static final String BASIC_AUTH_VALUE = basicAuthHeaderValue("elastic", SecuritySettingsSource.TEST_PASSWORD_SECURE_STRING);
private static final String BASIC_AUTH_VALUE = basicAuthHeaderValue("x_pack_rest_user",
SecuritySettingsSource.TEST_PASSWORD_SECURE_STRING);
@Override
protected Settings restClientSettings() {

View File

@ -81,7 +81,7 @@ abstract class MlNativeAutodetectIntegTestCase extends SecurityIntegTestCase {
protected Settings externalClusterClientSettings() {
Settings.Builder builder = Settings.builder();
builder.put(NetworkModule.TRANSPORT_TYPE_KEY, Security.NAME4);
builder.put(Security.USER_SETTING.getKey(), "elastic:" + SecuritySettingsSource.TEST_PASSWORD_SECURE_STRING);
builder.put(Security.USER_SETTING.getKey(), "x_pack_rest_user:" + SecuritySettingsSource.TEST_PASSWORD_SECURE_STRING);
builder.put(XPackSettings.MACHINE_LEARNING_ENABLED.getKey(), true);
return builder.build();
}

View File

@ -5,16 +5,9 @@
*/
package org.elasticsearch.xpack.security;
import org.apache.http.HttpEntity;
import org.apache.http.HttpHost;
import org.apache.http.entity.ContentType;
import org.apache.http.message.BasicHeader;
import org.apache.http.nio.entity.NStringEntity;
import org.elasticsearch.ElasticsearchSecurityException;
import org.elasticsearch.action.admin.cluster.health.ClusterHealthResponse;
import org.elasticsearch.client.Client;
import org.elasticsearch.client.RestClient;
import org.elasticsearch.client.RestClientBuilder;
import org.elasticsearch.cluster.ClusterState;
import org.elasticsearch.cluster.ClusterStateObserver;
import org.elasticsearch.cluster.service.ClusterService;
@ -29,7 +22,6 @@ import org.elasticsearch.env.NodeEnvironment;
import org.elasticsearch.index.IndexNotFoundException;
import org.elasticsearch.node.MockNode;
import org.elasticsearch.node.Node;
import org.elasticsearch.node.NodeValidationException;
import org.elasticsearch.plugins.Plugin;
import org.elasticsearch.test.ESIntegTestCase;
import org.elasticsearch.test.InternalTestCluster;
@ -40,14 +32,11 @@ import org.elasticsearch.xpack.security.action.role.PutRoleResponse;
import org.elasticsearch.xpack.security.action.user.PutUserResponse;
import org.elasticsearch.xpack.security.authc.support.UsernamePasswordToken;
import org.elasticsearch.xpack.security.client.SecurityClient;
import org.elasticsearch.xpack.security.user.ElasticUser;
import org.elasticsearch.xpack.security.support.IndexLifecycleManager;
import org.junit.After;
import org.junit.AfterClass;
import org.junit.BeforeClass;
import java.net.InetSocketAddress;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
@ -58,7 +47,6 @@ import java.util.Set;
import java.util.concurrent.CountDownLatch;
import java.util.function.Predicate;
import static org.elasticsearch.test.hamcrest.ElasticsearchAssertions.assertAcked;
import static org.elasticsearch.test.hamcrest.ElasticsearchAssertions.assertNoTimeout;
import static org.hamcrest.Matchers.arrayContaining;
import static org.hamcrest.Matchers.containsString;
@ -102,11 +90,7 @@ public class SecurityTribeIT extends NativeRealmIntegTestCase {
cluster2.beforeTest(random(), 0.1);
cluster2.ensureAtLeastNumDataNodes(2);
}
}
@Override
public boolean shouldSetReservedUserPasswords() {
return false;
assertSecurityIndexActive(cluster2);
}
@Override
@ -132,7 +116,7 @@ public class SecurityTribeIT extends NativeRealmIntegTestCase {
public void tearDownTribeNodeAndWipeCluster() throws Exception {
if (cluster2 != null) {
try {
cluster2.wipe(Collections.<String>emptySet());
cluster2.wipe(Collections.emptySet());
try {
// this is a hack to clean up the .security index since only the XPack user or superusers can delete it
cluster2.getInstance(InternalClient.class)
@ -160,7 +144,12 @@ public class SecurityTribeIT extends NativeRealmIntegTestCase {
return true;
}
private void setupTribeNode(Settings settings) throws NodeValidationException, InterruptedException {
@Override
protected boolean shouldSetReservedUserPasswords() {
return false;
}
private void setupTribeNode(Settings settings) throws Exception {
SecuritySettingsSource cluster2SettingsSource =
new SecuritySettingsSource(1, useGeneratedSSL, createTempDir(), Scope.TEST) {
@Override
@ -246,26 +235,14 @@ public class SecurityTribeIT extends NativeRealmIntegTestCase {
}, nodeCountPredicate);
latch.await();
}
assertTribeNodeHasAllIndices();
}
public void testThatTribeCanAuthenticateElasticUser() throws Exception {
InetSocketAddress[] inetSocketAddresses = cluster2.httpAddresses();
List<HttpHost> hosts = new ArrayList<>();
for (InetSocketAddress address : inetSocketAddresses) {
hosts.add(new HttpHost(address.getAddress(), address.getPort()));
}
RestClientBuilder builder = RestClient.builder(hosts.toArray(new HttpHost[hosts.size()]));
RestClient client = builder.build();
String payload = "{\"password\": \"" + SecuritySettingsSource.TEST_PASSWORD + "\"}";
HttpEntity entity = new NStringEntity(payload, ContentType.APPLICATION_JSON);
BasicHeader authHeader = new BasicHeader(UsernamePasswordToken.BASIC_AUTH_HEADER,
UsernamePasswordToken.basicAuthHeaderValue(ElasticUser.NAME, new SecureString("".toCharArray())));
String route = "/_xpack/security/user/" + ElasticUser.NAME + "/_password";
client.performRequest("PUT", route, Collections.emptyMap(), entity, authHeader);
client.close();
setupTribeNode(Settings.EMPTY);
ensureElasticPasswordBootstrapped(internalCluster());
assertTribeNodeHasAllIndices();
ClusterHealthResponse response = tribeClient.filterWithHeader(Collections.singletonMap("Authorization",
UsernamePasswordToken.basicAuthHeaderValue("elastic", SecuritySettingsSource.TEST_PASSWORD_SECURE_STRING)))
.admin().cluster().prepareHealth().get();
@ -274,8 +251,9 @@ public class SecurityTribeIT extends NativeRealmIntegTestCase {
public void testThatTribeCanAuthenticateElasticUserWithChangedPassword() throws Exception {
setupTribeNode(Settings.EMPTY);
Client clusterClient = randomBoolean() ? client() : cluster2.client();
securityClient(clusterClient).prepareChangePassword("elastic", "password".toCharArray()).get();
InternalTestCluster cluster = randomBoolean() ? internalCluster() : cluster2;
ensureElasticPasswordBootstrapped(cluster);
securityClient(cluster.client()).prepareChangePassword("elastic", "password".toCharArray()).get();
assertTribeNodeHasAllIndices();
ClusterHealthResponse response = tribeClient.filterWithHeader(Collections.singletonMap("Authorization",
@ -286,6 +264,8 @@ public class SecurityTribeIT extends NativeRealmIntegTestCase {
public void testThatTribeClustersHaveDifferentPasswords() throws Exception {
setupTribeNode(Settings.EMPTY);
ensureElasticPasswordBootstrapped(internalCluster());
ensureElasticPasswordBootstrapped(cluster2);
securityClient().prepareChangePassword("elastic", "password".toCharArray()).get();
securityClient(cluster2.client()).prepareChangePassword("elastic", "password2".toCharArray()).get();
@ -297,6 +277,9 @@ public class SecurityTribeIT extends NativeRealmIntegTestCase {
}
public void testUsersInBothTribes() throws Exception {
ensureElasticPasswordBootstrapped(internalCluster());
ensureElasticPasswordBootstrapped(cluster2);
final String preferredTribe = randomBoolean() ? "t1" : "t2";
setupTribeNode(Settings.builder().put("tribe.on_conflict", "prefer_" + preferredTribe).build());
final int randomUsers = scaledRandomIntBetween(3, 8);
@ -305,10 +288,7 @@ public class SecurityTribeIT extends NativeRealmIntegTestCase {
List<String> shouldBeSuccessfulUsers = new ArrayList<>();
List<String> shouldFailUsers = new ArrayList<>();
final Client preferredClient = "t1".equals(preferredTribe) ? cluster1Client : cluster2Client;
// always ensure the index exists on all of the clusters in this test
assertAcked(internalClient().admin().indices().prepareCreate(IndexLifecycleManager.INTERNAL_SECURITY_INDEX).get());
assertAcked(cluster2.getInstance(InternalClient.class).admin().indices()
.prepareCreate(IndexLifecycleManager.INTERNAL_SECURITY_INDEX).get());
for (int i = 0; i < randomUsers; i++) {
final String username = "user" + i;
Client clusterClient = randomBoolean() ? cluster1Client : cluster2Client;
@ -346,16 +326,16 @@ public class SecurityTribeIT extends NativeRealmIntegTestCase {
final String preferredTribe = randomBoolean() ? "t1" : "t2";
setupTribeNode(Settings.builder().put("tribe.on_conflict", "prefer_" + preferredTribe).build());
final int randomUsers = scaledRandomIntBetween(3, 8);
final Client cluster1Client = client();
final Client cluster2Client = cluster2.client();
List<String> shouldBeSuccessfulUsers = new ArrayList<>();
// only create users in the non preferred client
final Client nonPreferredClient = "t1".equals(preferredTribe) ? cluster2Client : cluster1Client;
final InternalTestCluster nonPreferredCluster = "t1".equals(preferredTribe) ? cluster2 : internalCluster();
ensureElasticPasswordBootstrapped(nonPreferredCluster);
for (int i = 0; i < randomUsers; i++) {
final String username = "user" + i;
PutUserResponse response =
securityClient(nonPreferredClient).preparePutUser(username, "password".toCharArray(), "superuser").get();
securityClient(nonPreferredCluster.client()).preparePutUser(username, "password".toCharArray(), "superuser").get();
assertTrue(response.created());
shouldBeSuccessfulUsers.add(username);
}
@ -370,6 +350,8 @@ public class SecurityTribeIT extends NativeRealmIntegTestCase {
}
public void testUserModificationUsingTribeNodeAreDisabled() throws Exception {
ensureElasticPasswordBootstrapped(internalCluster());
setupTribeNode(Settings.EMPTY);
SecurityClient securityClient = securityClient(tribeClient);
UnsupportedOperationException e = expectThrows(UnsupportedOperationException.class,
@ -385,6 +367,9 @@ public class SecurityTribeIT extends NativeRealmIntegTestCase {
}
public void testRetrieveRolesOnTribeNode() throws Exception {
ensureElasticPasswordBootstrapped(internalCluster());
ensureElasticPasswordBootstrapped(cluster2);
final String preferredTribe = randomBoolean() ? "t1" : "t2";
setupTribeNode(Settings.builder().put("tribe.on_conflict", "prefer_" + preferredTribe).build());
final int randomRoles = scaledRandomIntBetween(3, 8);
@ -393,10 +378,6 @@ public class SecurityTribeIT extends NativeRealmIntegTestCase {
List<String> shouldBeSuccessfulRoles = new ArrayList<>();
List<String> shouldFailRoles = new ArrayList<>();
final Client preferredClient = "t1".equals(preferredTribe) ? cluster1Client : cluster2Client;
// always ensure the index exists on all of the clusters in this test
assertAcked(internalClient().admin().indices().prepareCreate(IndexLifecycleManager.INTERNAL_SECURITY_INDEX).get());
assertAcked(cluster2.getInstance(InternalClient.class).admin().indices()
.prepareCreate(IndexLifecycleManager.INTERNAL_SECURITY_INDEX).get());
for (int i = 0; i < randomRoles; i++) {
final String rolename = "role" + i;
@ -432,10 +413,10 @@ public class SecurityTribeIT extends NativeRealmIntegTestCase {
final String preferredTribe = randomBoolean() ? "t1" : "t2";
setupTribeNode(Settings.builder().put("tribe.on_conflict", "prefer_" + preferredTribe).build());
final int randomRoles = scaledRandomIntBetween(3, 8);
final Client cluster1Client = client();
final Client cluster2Client = cluster2.client();
List<String> shouldBeSuccessfulRoles = new ArrayList<>();
final Client nonPreferredClient = "t1".equals(preferredTribe) ? cluster2Client : cluster1Client;
final InternalTestCluster nonPreferredCluster = "t1".equals(preferredTribe) ? cluster2 : internalCluster();
ensureElasticPasswordBootstrapped(nonPreferredCluster);
Client nonPreferredClient = nonPreferredCluster.client();
for (int i = 0; i < randomRoles; i++) {
final String rolename = "role" + i;

View File

@ -215,7 +215,7 @@ public class AuthenticationServiceTests extends ESTestCase {
}, this::logAndFail));
verify(auditTrail).authenticationSuccess(secondRealm.name(), user, "_action", message);
verifyNoMoreInteractions(auditTrail);
verify(firstRealm, never()).authenticate(eq(token), any(ActionListener.class), any(IncomingRequest.class));
verify(firstRealm, never()).authenticate(eq(token), any(ActionListener.class));
assertTrue(completed.get());
}
@ -571,7 +571,7 @@ public class AuthenticationServiceTests extends ESTestCase {
when(secondRealm.token(threadContext)).thenReturn(token);
when(secondRealm.supports(token)).thenReturn(true);
doThrow(authenticationError("realm doesn't like authenticate"))
.when(secondRealm).authenticate(eq(token), any(ActionListener.class), any(IncomingRequest.class));
.when(secondRealm).authenticate(eq(token), any(ActionListener.class));
try {
authenticateBlocking("_action", message, null);
fail("exception should bubble out");
@ -586,7 +586,7 @@ public class AuthenticationServiceTests extends ESTestCase {
when(secondRealm.token(threadContext)).thenReturn(token);
when(secondRealm.supports(token)).thenReturn(true);
doThrow(authenticationError("realm doesn't like authenticate"))
.when(secondRealm).authenticate(eq(token), any(ActionListener.class), any(IncomingRequest.class));
.when(secondRealm).authenticate(eq(token), any(ActionListener.class));
try {
authenticateBlocking(restRequest);
fail("exception should bubble out");
@ -882,7 +882,7 @@ public class AuthenticationServiceTests extends ESTestCase {
listener.onResponse(AuthenticationResult.success(user));
}
return null;
}).when(realm).authenticate(eq(token), any(ActionListener.class), any(IncomingRequest.class));
}).when(realm).authenticate(eq(token), any(ActionListener.class));
}
private Authentication authenticateBlocking(RestRequest restRequest) {

View File

@ -9,14 +9,14 @@ import org.elasticsearch.action.ActionListener;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.common.util.concurrent.ThreadContext;
import org.elasticsearch.env.Environment;
import org.elasticsearch.xpack.security.user.User;
import org.elasticsearch.xpack.security.authc.esnative.ReservedRealm;
import org.elasticsearch.xpack.security.authc.esnative.NativeRealm;
import org.elasticsearch.xpack.security.authc.file.FileRealm;
import org.elasticsearch.xpack.security.authc.ldap.LdapRealm;
import org.elasticsearch.license.XPackLicenseState;
import org.elasticsearch.license.XPackLicenseState.AllowedRealmType;
import org.elasticsearch.test.ESTestCase;
import org.elasticsearch.xpack.security.authc.esnative.NativeRealm;
import org.elasticsearch.xpack.security.authc.esnative.ReservedRealm;
import org.elasticsearch.xpack.security.authc.file.FileRealm;
import org.elasticsearch.xpack.security.authc.ldap.LdapRealm;
import org.elasticsearch.xpack.security.user.User;
import org.junit.Before;
import java.util.ArrayList;
@ -436,8 +436,7 @@ public class RealmsTests extends ESTestCase {
}
@Override
public void authenticate(AuthenticationToken token, ActionListener<AuthenticationResult> listener,
IncomingRequest incomingRequest) {
public void authenticate(AuthenticationToken token, ActionListener<AuthenticationResult> listener) {
listener.onResponse(AuthenticationResult.notHandled());
}

View File

@ -40,11 +40,6 @@ public class ESNativeMigrateToolTests extends NativeRealmIntegTestCase {
useSSL = randomBoolean();
}
@Override
public boolean shouldSetReservedUserPasswords() {
return false;
}
@Override
public Settings nodeSettings(int nodeOrdinal) {
logger.info("--> use SSL? {}", useSSL);
@ -62,6 +57,11 @@ public class ESNativeMigrateToolTests extends NativeRealmIntegTestCase {
return useSSL == false;
}
@Override
protected boolean shouldSetReservedUserPasswords() {
return false;
}
private Environment nodeEnvironment() throws Exception {
return internalCluster().getInstances(Environment.class).iterator().next();
}

View File

@ -5,16 +5,6 @@
*/
package org.elasticsearch.xpack.security.authc.esnative;
import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.net.UnknownHostException;
import java.util.Collection;
import java.util.Collections;
import java.util.Map;
import java.util.Map.Entry;
import java.util.concurrent.ExecutionException;
import java.util.function.Predicate;
import org.elasticsearch.ElasticsearchSecurityException;
import org.elasticsearch.Version;
import org.elasticsearch.action.ActionListener;
@ -27,9 +17,8 @@ import org.elasticsearch.env.Environment;
import org.elasticsearch.test.ESTestCase;
import org.elasticsearch.xpack.XPackSettings;
import org.elasticsearch.xpack.security.SecurityLifecycleService;
import org.elasticsearch.xpack.security.authc.AuthenticationResult;
import org.elasticsearch.xpack.security.action.user.ChangePasswordRequest;
import org.elasticsearch.xpack.security.authc.IncomingRequest;
import org.elasticsearch.xpack.security.authc.AuthenticationResult;
import org.elasticsearch.xpack.security.authc.esnative.NativeUsersStore.ReservedUserInfo;
import org.elasticsearch.xpack.security.authc.support.Hasher;
import org.elasticsearch.xpack.security.authc.support.UsernamePasswordToken;
@ -42,11 +31,18 @@ import org.elasticsearch.xpack.security.user.User;
import org.junit.Before;
import org.mockito.ArgumentCaptor;
import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.util.Collection;
import java.util.Collections;
import java.util.Map;
import java.util.Map.Entry;
import java.util.function.Predicate;
import static org.hamcrest.Matchers.contains;
import static org.hamcrest.Matchers.containsInAnyOrder;
import static org.hamcrest.Matchers.containsString;
import static org.hamcrest.Matchers.empty;
import static org.hamcrest.Matchers.equalTo;
import static org.hamcrest.Matchers.is;
import static org.hamcrest.Matchers.nullValue;
import static org.mockito.Matchers.any;
@ -68,34 +64,16 @@ public class ReservedRealmTests extends ESTestCase {
public static final String ACCEPT_DEFAULT_PASSWORDS = ReservedRealm.ACCEPT_DEFAULT_PASSWORD_SETTING.getKey();
private NativeUsersStore usersStore;
private SecurityLifecycleService securityLifecycleService;
private IncomingRequest incomingRequest;
@Before
public void setupMocks() throws Exception {
usersStore = mock(NativeUsersStore.class);
securityLifecycleService = mock(SecurityLifecycleService.class);
incomingRequest = mock(IncomingRequest.class);
when(securityLifecycleService.isSecurityIndexAvailable()).thenReturn(true);
when(securityLifecycleService.checkSecurityMappingVersion(any())).thenReturn(true);
mockGetAllReservedUserInfo(usersStore, Collections.emptyMap());
}
@SuppressForbidden(reason = "allow getting localhost")
public void testMappingVersionFromBeforeUserExisted() throws ExecutionException, InterruptedException, UnknownHostException {
when(securityLifecycleService.checkSecurityMappingVersion(any())).thenReturn(false);
final ReservedRealm reservedRealm =
new ReservedRealm(mock(Environment.class), Settings.EMPTY, usersStore,
new AnonymousUser(Settings.EMPTY), securityLifecycleService, new ThreadContext(Settings.EMPTY));
final String principal = ElasticUser.NAME;
PlainActionFuture<AuthenticationResult> future = new PlainActionFuture<>();
InetSocketAddress address = new InetSocketAddress(InetAddress.getLocalHost(), 100);
when(incomingRequest.getRemoteAddress()).thenReturn(address);
when(incomingRequest.getType()).thenReturn(IncomingRequest.RequestType.REST);
reservedRealm.authenticate(new UsernamePasswordToken(principal, EMPTY_PASSWORD), future, incomingRequest);
assertThat(future.get().getUser().enabled(), equalTo(false));
}
public void testDisableDefaultPasswordAuthentication() throws Throwable {
final User expected = randomFrom(new ElasticUser(true), new KibanaUser(true), new LogstashSystemUser(true));
@ -106,11 +84,11 @@ public class ReservedRealmTests extends ESTestCase {
securityLifecycleService, new ThreadContext(Settings.EMPTY));
PlainActionFuture<AuthenticationResult> listener = new PlainActionFuture<>();
reservedRealm.doAuthenticate(new UsernamePasswordToken(expected.principal(), EMPTY_PASSWORD), listener, incomingRequest);
reservedRealm.doAuthenticate(new UsernamePasswordToken(expected.principal(), EMPTY_PASSWORD), listener);
assertFailedAuthentication(listener, expected.principal());
}
public void testElasticEmptyPasswordAuthenticationFailsFromNonLocalhost() throws Throwable {
public void testElasticEmptyPasswordAuthenticationFails() throws Throwable {
final User expected = new ElasticUser(true);
final String principal = expected.principal();
@ -121,37 +99,10 @@ public class ReservedRealmTests extends ESTestCase {
PlainActionFuture<AuthenticationResult> listener = new PlainActionFuture<>();
InetSocketAddress address = new InetSocketAddress(InetAddress.getByName("128.9.8.1"), 100);
when(incomingRequest.getRemoteAddress()).thenReturn(address);
reservedRealm.doAuthenticate(new UsernamePasswordToken(principal, EMPTY_PASSWORD), listener, incomingRequest);
reservedRealm.doAuthenticate(new UsernamePasswordToken(principal, EMPTY_PASSWORD), listener);
assertFailedAuthentication(listener, expected.principal());
}
@SuppressForbidden(reason = "allow getting localhost")
public void testElasticEmptyPasswordAuthenticationSucceedsInSetupModeIfRestRequestComesFromLocalhost() throws Throwable {
final User expected = new ElasticUser(true, true);
final String principal = expected.principal();
Settings settings = Settings.builder().put(ACCEPT_DEFAULT_PASSWORDS, true).build();
final ReservedRealm reservedRealm =
new ReservedRealm(mock(Environment.class), settings, usersStore,
new AnonymousUser(Settings.EMPTY), securityLifecycleService, new ThreadContext(Settings.EMPTY));
PlainActionFuture<AuthenticationResult> listener = new PlainActionFuture<>();
InetSocketAddress address = new InetSocketAddress(InetAddress.getLocalHost(), 100);
when(incomingRequest.getRemoteAddress()).thenReturn(address);
when(incomingRequest.getType()).thenReturn(IncomingRequest.RequestType.REST);
reservedRealm.doAuthenticate(new UsernamePasswordToken(principal, EMPTY_PASSWORD), listener, incomingRequest);
User user = listener.actionGet().getUser();
assertEquals(expected, user);
assertNotEquals(new ElasticUser(true, false), user);
}
public void testAuthenticationDisabled() throws Throwable {
Settings settings = Settings.builder().put(XPackSettings.RESERVED_REALM_ENABLED_SETTING.getKey(), false).build();
final boolean securityIndexExists = randomBoolean();
@ -165,7 +116,7 @@ public class ReservedRealmTests extends ESTestCase {
final String principal = expected.principal();
PlainActionFuture<AuthenticationResult> listener = new PlainActionFuture<>();
reservedRealm.doAuthenticate(new UsernamePasswordToken(principal, EMPTY_PASSWORD), listener, mock(IncomingRequest.class));
reservedRealm.doAuthenticate(new UsernamePasswordToken(principal, EMPTY_PASSWORD), listener);
final AuthenticationResult result = listener.actionGet();
assertThat(result.getStatus(), is(AuthenticationResult.Status.CONTINUE));
assertNull(result.getUser());
@ -196,7 +147,7 @@ public class ReservedRealmTests extends ESTestCase {
// test empty password
final PlainActionFuture<AuthenticationResult> listener = new PlainActionFuture<>();
reservedRealm.doAuthenticate(new UsernamePasswordToken(principal, EMPTY_PASSWORD), listener, incomingRequest);
reservedRealm.doAuthenticate(new UsernamePasswordToken(principal, EMPTY_PASSWORD), listener);
assertFailedAuthentication(listener, expectedUser.principal());
// the realm assumes it owns the hashed password so it fills it with 0's
@ -208,7 +159,7 @@ public class ReservedRealmTests extends ESTestCase {
// test new password
final PlainActionFuture<AuthenticationResult> authListener = new PlainActionFuture<>();
reservedRealm.doAuthenticate(new UsernamePasswordToken(principal, newPassword), authListener, incomingRequest);
reservedRealm.doAuthenticate(new UsernamePasswordToken(principal, newPassword), authListener);
final User authenticated = authListener.actionGet().getUser();
assertEquals(expectedUser, authenticated);
assertThat(expectedUser.enabled(), is(enabled));
@ -225,7 +176,7 @@ public class ReservedRealmTests extends ESTestCase {
final ReservedRealm reservedRealm =
new ReservedRealm(mock(Environment.class), Settings.EMPTY, usersStore,
new AnonymousUser(Settings.EMPTY), securityLifecycleService, new ThreadContext(Settings.EMPTY));
final User expectedUser = randomFrom(new ElasticUser(true, true), new KibanaUser(true), new LogstashSystemUser(true));
final User expectedUser = randomFrom(new ElasticUser(true), new KibanaUser(true), new LogstashSystemUser(true));
final String principal = expectedUser.principal();
PlainActionFuture<User> listener = new PlainActionFuture<>();
@ -313,7 +264,7 @@ public class ReservedRealmTests extends ESTestCase {
new AnonymousUser(Settings.EMPTY), securityLifecycleService, new ThreadContext(Settings.EMPTY));
PlainActionFuture<Collection<User>> userFuture = new PlainActionFuture<>();
reservedRealm.users(userFuture);
assertThat(userFuture.actionGet(), containsInAnyOrder(new ElasticUser(true, true), new KibanaUser(true),
assertThat(userFuture.actionGet(), containsInAnyOrder(new ElasticUser(true), new KibanaUser(true),
new LogstashSystemUser(true), new BeatsSystemUser(true)));
}
@ -335,29 +286,21 @@ public class ReservedRealmTests extends ESTestCase {
}
}
@SuppressForbidden(reason = "allow getting localhost")
public void testFailedAuthentication() throws Exception {
final ReservedRealm reservedRealm = new ReservedRealm(mock(Environment.class), Settings.EMPTY, usersStore,
new AnonymousUser(Settings.EMPTY), securityLifecycleService, new ThreadContext(Settings.EMPTY));
InetSocketAddress address = new InetSocketAddress(InetAddress.getLocalHost(), 100);
// maybe cache a successful auth
if (randomBoolean()) {
PlainActionFuture<AuthenticationResult> future = new PlainActionFuture<>();
IncomingRequest r = mock(IncomingRequest.class);
when(r.getRemoteAddress()).thenReturn(address);
when(r.getType()).thenReturn(IncomingRequest.RequestType.REST);
reservedRealm.authenticate(new UsernamePasswordToken(ElasticUser.NAME, EMPTY_PASSWORD), future, r);
reservedRealm.authenticate(new UsernamePasswordToken(ElasticUser.NAME, EMPTY_PASSWORD), future);
User user = future.actionGet().getUser();
assertEquals(new ElasticUser(true, true), user);
assertEquals(new ElasticUser(true), user);
}
PlainActionFuture<AuthenticationResult> future = new PlainActionFuture<>();
IncomingRequest r = mock(IncomingRequest.class);
when(r.getRemoteAddress()).thenReturn(address);
when(r.getType()).thenReturn(IncomingRequest.RequestType.REST);
reservedRealm.authenticate(new UsernamePasswordToken(ElasticUser.NAME, new SecureString("foobar".toCharArray())), future, r);
reservedRealm.authenticate(new UsernamePasswordToken(ElasticUser.NAME, new SecureString("foobar".toCharArray())), future);
assertFailedAuthentication(future, ElasticUser.NAME);
}

View File

@ -17,7 +17,6 @@ import org.elasticsearch.env.Environment;
import org.elasticsearch.test.ESTestCase;
import org.elasticsearch.watcher.ResourceWatcherService;
import org.elasticsearch.xpack.security.authc.AuthenticationResult;
import org.elasticsearch.xpack.security.authc.IncomingRequest;
import org.elasticsearch.xpack.security.authc.RealmConfig;
import org.elasticsearch.xpack.security.authc.support.Hasher;
import org.elasticsearch.xpack.security.authc.support.UsernamePasswordToken;
@ -66,7 +65,7 @@ public class FileRealmTests extends ESTestCase {
RealmConfig config = new RealmConfig("file-test", Settings.EMPTY, globalSettings, new Environment(globalSettings), new ThreadContext(globalSettings));
FileRealm realm = new FileRealm(config, userPasswdStore, userRolesStore);
PlainActionFuture<AuthenticationResult> future = new PlainActionFuture<>();
realm.authenticate(new UsernamePasswordToken("user1", new SecureString("test123")), future, mock(IncomingRequest.class));
realm.authenticate(new UsernamePasswordToken("user1", new SecureString("test123")), future);
final AuthenticationResult result = future.actionGet();
assertThat(result.getStatus(), is(AuthenticationResult.Status.SUCCESS));
User user = result.getUser();
@ -87,10 +86,10 @@ public class FileRealmTests extends ESTestCase {
when(userRolesStore.roles("user1")).thenReturn(new String[]{"role1", "role2"});
FileRealm realm = new FileRealm(config, userPasswdStore, userRolesStore);
PlainActionFuture<AuthenticationResult> future = new PlainActionFuture<>();
realm.authenticate(new UsernamePasswordToken("user1", new SecureString("test123")), future, mock(IncomingRequest.class));
realm.authenticate(new UsernamePasswordToken("user1", new SecureString("test123")), future);
User user1 = future.actionGet().getUser();
future = new PlainActionFuture<>();
realm.authenticate(new UsernamePasswordToken("user1", new SecureString("test123")), future, mock(IncomingRequest.class));
realm.authenticate(new UsernamePasswordToken("user1", new SecureString("test123")), future);
User user2 = future.actionGet().getUser();
assertThat(user1, sameInstance(user2));
}
@ -104,32 +103,32 @@ public class FileRealmTests extends ESTestCase {
doReturn(new String[] { "role1", "role2" }).when(userRolesStore).roles("user1");
FileRealm realm = new FileRealm(config, userPasswdStore, userRolesStore);
PlainActionFuture<AuthenticationResult> future = new PlainActionFuture<>();
realm.authenticate(new UsernamePasswordToken("user1", new SecureString("test123")), future, mock(IncomingRequest.class));
realm.authenticate(new UsernamePasswordToken("user1", new SecureString("test123")), future);
User user1 = future.actionGet().getUser();
future = new PlainActionFuture<>();
realm.authenticate(new UsernamePasswordToken("user1", new SecureString("test123")), future, mock(IncomingRequest.class));
realm.authenticate(new UsernamePasswordToken("user1", new SecureString("test123")), future);
User user2 = future.actionGet().getUser();
assertThat(user1, sameInstance(user2));
userPasswdStore.notifyRefresh();
future = new PlainActionFuture<>();
realm.authenticate(new UsernamePasswordToken("user1", new SecureString("test123")), future, mock(IncomingRequest.class));
realm.authenticate(new UsernamePasswordToken("user1", new SecureString("test123")), future);
User user3 = future.actionGet().getUser();
assertThat(user2, not(sameInstance(user3)));
future = new PlainActionFuture<>();
realm.authenticate(new UsernamePasswordToken("user1", new SecureString("test123")), future, mock(IncomingRequest.class));
realm.authenticate(new UsernamePasswordToken("user1", new SecureString("test123")), future);
User user4 = future.actionGet().getUser();
assertThat(user3, sameInstance(user4));
userRolesStore.notifyRefresh();
future = new PlainActionFuture<>();
realm.authenticate(new UsernamePasswordToken("user1", new SecureString("test123")), future, mock(IncomingRequest.class));
realm.authenticate(new UsernamePasswordToken("user1", new SecureString("test123")), future);
User user5 = future.actionGet().getUser();
assertThat(user4, not(sameInstance(user5)));
future = new PlainActionFuture<>();
realm.authenticate(new UsernamePasswordToken("user1", new SecureString("test123")), future, mock(IncomingRequest.class));
realm.authenticate(new UsernamePasswordToken("user1", new SecureString("test123")), future);
User user6 = future.actionGet().getUser();
assertThat(user5, sameInstance(user6));
}

View File

@ -20,7 +20,6 @@ import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.common.util.concurrent.ThreadContext;
import org.elasticsearch.env.Environment;
import org.elasticsearch.xpack.security.authc.AuthenticationResult;
import org.elasticsearch.xpack.security.authc.IncomingRequest;
import org.elasticsearch.xpack.security.authc.ldap.ActiveDirectorySessionFactory.DownLevelADAuthenticator;
import org.elasticsearch.xpack.security.authc.ldap.ActiveDirectorySessionFactory.UpnADAuthenticator;
import org.elasticsearch.xpack.security.user.User;
@ -141,7 +140,7 @@ public class ActiveDirectoryRealmTests extends ESTestCase {
LdapRealm realm = new LdapRealm(LdapRealm.AD_TYPE, config, sessionFactory, roleMapper, threadPool);
PlainActionFuture<AuthenticationResult> future = new PlainActionFuture<>();
realm.authenticate(new UsernamePasswordToken("CN=ironman", new SecureString(PASSWORD)), future, mock(IncomingRequest.class));
realm.authenticate(new UsernamePasswordToken("CN=ironman", new SecureString(PASSWORD)), future);
final AuthenticationResult result = future.actionGet();
assertThat(result.getStatus(), is(AuthenticationResult.Status.SUCCESS));
final User user = result.getUser();
@ -158,7 +157,7 @@ public class ActiveDirectoryRealmTests extends ESTestCase {
// Thor does not have a UPN of form CN=Thor@ad.test.elasticsearch.com
PlainActionFuture<AuthenticationResult> future = new PlainActionFuture<>();
realm.authenticate(new UsernamePasswordToken("CN=Thor", new SecureString(PASSWORD)), future, mock(IncomingRequest.class));
realm.authenticate(new UsernamePasswordToken("CN=Thor", new SecureString(PASSWORD)), future);
User user = future.actionGet().getUser();
assertThat(user, is(notNullValue()));
assertThat(user.roles(), arrayContaining(containsString("Avengers")));
@ -183,7 +182,7 @@ public class ActiveDirectoryRealmTests extends ESTestCase {
int count = randomIntBetween(2, 10);
for (int i = 0; i < count; i++) {
PlainActionFuture<AuthenticationResult> future = new PlainActionFuture<>();
realm.authenticate(new UsernamePasswordToken("CN=ironman", new SecureString(PASSWORD)), future, mock(IncomingRequest.class));
realm.authenticate(new UsernamePasswordToken("CN=ironman", new SecureString(PASSWORD)), future);
future.actionGet();
}
@ -201,7 +200,7 @@ public class ActiveDirectoryRealmTests extends ESTestCase {
int count = randomIntBetween(2, 10);
for (int i = 0; i < count; i++) {
PlainActionFuture<AuthenticationResult> future = new PlainActionFuture<>();
realm.authenticate(new UsernamePasswordToken("CN=ironman", new SecureString(PASSWORD)), future, mock(IncomingRequest.class));
realm.authenticate(new UsernamePasswordToken("CN=ironman", new SecureString(PASSWORD)), future);
future.actionGet();
}
@ -219,7 +218,7 @@ public class ActiveDirectoryRealmTests extends ESTestCase {
int count = randomIntBetween(2, 10);
for (int i = 0; i < count; i++) {
PlainActionFuture<AuthenticationResult> future = new PlainActionFuture<>();
realm.authenticate(new UsernamePasswordToken("CN=ironman", new SecureString(PASSWORD)), future, mock(IncomingRequest.class));
realm.authenticate(new UsernamePasswordToken("CN=ironman", new SecureString(PASSWORD)), future);
future.actionGet();
}
@ -231,7 +230,7 @@ public class ActiveDirectoryRealmTests extends ESTestCase {
for (int i = 0; i < count; i++) {
PlainActionFuture<AuthenticationResult> future = new PlainActionFuture<>();
realm.authenticate(new UsernamePasswordToken("CN=ironman", new SecureString(PASSWORD)), future, mock(IncomingRequest.class));
realm.authenticate(new UsernamePasswordToken("CN=ironman", new SecureString(PASSWORD)), future);
future.actionGet();
}
@ -248,7 +247,7 @@ public class ActiveDirectoryRealmTests extends ESTestCase {
LdapRealm realm = new LdapRealm(LdapRealm.AD_TYPE, config, sessionFactory, roleMapper, threadPool);
PlainActionFuture<AuthenticationResult> future = new PlainActionFuture<>();
realm.authenticate(new UsernamePasswordToken("CN=ironman", new SecureString(PASSWORD)), future, mock(IncomingRequest.class));
realm.authenticate(new UsernamePasswordToken("CN=ironman", new SecureString(PASSWORD)), future);
User user = future.actionGet().getUser();
assertThat(user, is(notNullValue()));
assertThat(user.roles(), arrayContaining(equalTo("group_role")));
@ -264,7 +263,7 @@ public class ActiveDirectoryRealmTests extends ESTestCase {
LdapRealm realm = new LdapRealm(LdapRealm.AD_TYPE, config, sessionFactory, roleMapper, threadPool);
PlainActionFuture<AuthenticationResult> future = new PlainActionFuture<>();
realm.authenticate(new UsernamePasswordToken("CN=Thor", new SecureString(PASSWORD)), future, mock(IncomingRequest.class));
realm.authenticate(new UsernamePasswordToken("CN=Thor", new SecureString(PASSWORD)), future);
User user = future.actionGet().getUser();
assertThat(user, is(notNullValue()));
assertThat(user.roles(), arrayContainingInAnyOrder(equalTo("group_role"), equalTo("user_role")));

View File

@ -5,10 +5,6 @@
*/
package org.elasticsearch.xpack.security.authc.ldap;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import com.unboundid.ldap.sdk.LDAPURL;
import org.elasticsearch.action.ActionListener;
import org.elasticsearch.action.support.PlainActionFuture;
@ -20,7 +16,6 @@ import org.elasticsearch.threadpool.TestThreadPool;
import org.elasticsearch.threadpool.ThreadPool;
import org.elasticsearch.watcher.ResourceWatcherService;
import org.elasticsearch.xpack.security.authc.AuthenticationResult;
import org.elasticsearch.xpack.security.authc.IncomingRequest;
import org.elasticsearch.xpack.security.authc.RealmConfig;
import org.elasticsearch.xpack.security.authc.ldap.support.LdapSearchScope;
import org.elasticsearch.xpack.security.authc.ldap.support.LdapTestCase;
@ -34,6 +29,10 @@ import org.elasticsearch.xpack.ssl.VerificationMode;
import org.junit.After;
import org.junit.Before;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import static org.elasticsearch.xpack.security.authc.ldap.support.SessionFactory.URLS_SETTING;
import static org.hamcrest.Matchers.arrayContaining;
import static org.hamcrest.Matchers.contains;
@ -46,7 +45,6 @@ import static org.hamcrest.Matchers.notNullValue;
import static org.hamcrest.Matchers.nullValue;
import static org.mockito.Matchers.any;
import static org.mockito.Matchers.anyString;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
@ -88,7 +86,7 @@ public class LdapRealmTests extends LdapTestCase {
threadPool);
PlainActionFuture<AuthenticationResult> future = new PlainActionFuture<>();
ldap.authenticate(new UsernamePasswordToken(VALID_USERNAME, new SecureString(PASSWORD)), future, mock(IncomingRequest.class));
ldap.authenticate(new UsernamePasswordToken(VALID_USERNAME, new SecureString(PASSWORD)), future);
final AuthenticationResult result = future.actionGet();
assertThat(result.getStatus(), is(AuthenticationResult.Status.SUCCESS));
User user = result.getUser();
@ -113,7 +111,7 @@ public class LdapRealmTests extends LdapTestCase {
new LdapRealm(LdapRealm.LDAP_TYPE, config, ldapFactory, buildGroupAsRoleMapper(resourceWatcherService), threadPool);
PlainActionFuture<AuthenticationResult> future = new PlainActionFuture<>();
ldap.authenticate(new UsernamePasswordToken(VALID_USERNAME, new SecureString(PASSWORD)), future, mock(IncomingRequest.class));
ldap.authenticate(new UsernamePasswordToken(VALID_USERNAME, new SecureString(PASSWORD)), future);
final AuthenticationResult result = future.actionGet();
assertThat(result.getStatus(), is(AuthenticationResult.Status.SUCCESS));
User user = result.getUser();
@ -139,11 +137,11 @@ public class LdapRealmTests extends LdapTestCase {
new LdapRealm(LdapRealm.LDAP_TYPE, config, ldapFactory, buildGroupAsRoleMapper(resourceWatcherService), threadPool);
PlainActionFuture<AuthenticationResult> future = new PlainActionFuture<>();
ldap.authenticate(new UsernamePasswordToken(VALID_USERNAME, new SecureString(PASSWORD)), future, mock(IncomingRequest.class));
ldap.authenticate(new UsernamePasswordToken(VALID_USERNAME, new SecureString(PASSWORD)), future);
assertThat(future.actionGet().getStatus(), is(AuthenticationResult.Status.SUCCESS));
future = new PlainActionFuture<>();
ldap.authenticate(new UsernamePasswordToken(VALID_USERNAME, new SecureString(PASSWORD)), future, mock(IncomingRequest.class));
ldap.authenticate(new UsernamePasswordToken(VALID_USERNAME, new SecureString(PASSWORD)), future);
assertThat(future.actionGet().getStatus(), is(AuthenticationResult.Status.SUCCESS));
//verify one and only one session -> caching is working
@ -163,10 +161,10 @@ public class LdapRealmTests extends LdapTestCase {
ldapFactory = spy(ldapFactory);
LdapRealm ldap = new LdapRealm(LdapRealm.LDAP_TYPE, config, ldapFactory, roleMapper, threadPool);
PlainActionFuture<AuthenticationResult> future = new PlainActionFuture<>();
ldap.authenticate(new UsernamePasswordToken(VALID_USERNAME, new SecureString(PASSWORD)), future, mock(IncomingRequest.class));
ldap.authenticate(new UsernamePasswordToken(VALID_USERNAME, new SecureString(PASSWORD)), future);
future.actionGet();
future = new PlainActionFuture<>();
ldap.authenticate(new UsernamePasswordToken(VALID_USERNAME, new SecureString(PASSWORD)), future, mock(IncomingRequest.class));
ldap.authenticate(new UsernamePasswordToken(VALID_USERNAME, new SecureString(PASSWORD)), future);
future.actionGet();
//verify one and only one session -> caching is working
@ -175,7 +173,7 @@ public class LdapRealmTests extends LdapTestCase {
roleMapper.notifyRefresh();
future = new PlainActionFuture<>();
ldap.authenticate(new UsernamePasswordToken(VALID_USERNAME, new SecureString(PASSWORD)), future, mock(IncomingRequest.class));
ldap.authenticate(new UsernamePasswordToken(VALID_USERNAME, new SecureString(PASSWORD)), future);
future.actionGet();
//we need to session again
@ -196,10 +194,10 @@ public class LdapRealmTests extends LdapTestCase {
LdapRealm ldap =
new LdapRealm(LdapRealm.LDAP_TYPE, config, ldapFactory, buildGroupAsRoleMapper(resourceWatcherService), threadPool);
PlainActionFuture<AuthenticationResult> future = new PlainActionFuture<>();
ldap.authenticate(new UsernamePasswordToken(VALID_USERNAME, new SecureString(PASSWORD)), future, mock(IncomingRequest.class));
ldap.authenticate(new UsernamePasswordToken(VALID_USERNAME, new SecureString(PASSWORD)), future);
future.actionGet();
future = new PlainActionFuture<>();
ldap.authenticate(new UsernamePasswordToken(VALID_USERNAME, new SecureString(PASSWORD)), future, mock(IncomingRequest.class));
ldap.authenticate(new UsernamePasswordToken(VALID_USERNAME, new SecureString(PASSWORD)), future);
future.actionGet();
//verify two and only two binds -> caching is disabled
@ -290,7 +288,7 @@ public class LdapRealmTests extends LdapTestCase {
new DnRoleMapper(LdapRealm.LDAP_TYPE, config, resourceWatcherService), threadPool);
PlainActionFuture<AuthenticationResult> future = new PlainActionFuture<>();
ldap.authenticate(new UsernamePasswordToken("Horatio Hornblower", new SecureString(PASSWORD)), future, mock(IncomingRequest.class));
ldap.authenticate(new UsernamePasswordToken("Horatio Hornblower", new SecureString(PASSWORD)), future);
final AuthenticationResult result = future.actionGet();
assertThat(result.getStatus(), is(AuthenticationResult.Status.SUCCESS));
User user = result.getUser();
@ -316,7 +314,7 @@ public class LdapRealmTests extends LdapTestCase {
threadPool);
PlainActionFuture<AuthenticationResult> future = new PlainActionFuture<>();
ldap.authenticate(new UsernamePasswordToken(VALID_USERNAME, new SecureString(PASSWORD)), future, mock(IncomingRequest.class));
ldap.authenticate(new UsernamePasswordToken(VALID_USERNAME, new SecureString(PASSWORD)), future);
final AuthenticationResult result = future.actionGet();
assertThat(result.getStatus(), is(AuthenticationResult.Status.CONTINUE));
assertThat(result.getUser(), nullValue());

View File

@ -25,7 +25,6 @@ import org.elasticsearch.common.util.concurrent.ThreadContext;
import org.elasticsearch.env.Environment;
import org.elasticsearch.test.ESTestCase;
import org.elasticsearch.xpack.security.authc.AuthenticationResult;
import org.elasticsearch.xpack.security.authc.IncomingRequest;
import org.elasticsearch.xpack.security.authc.RealmConfig;
import org.elasticsearch.xpack.security.authc.support.UserRoleMapper;
import org.elasticsearch.xpack.security.authc.support.UsernamePasswordToken;
@ -106,7 +105,7 @@ public class PkiRealmTests extends ESTestCase {
}).when(roleMapper).resolveRoles(any(UserRoleMapper.UserData.class), any(ActionListener.class));
PlainActionFuture<AuthenticationResult> future = new PlainActionFuture<>();
realm.authenticate(token, future, mock(IncomingRequest.class));
realm.authenticate(token, future);
final AuthenticationResult result = future.actionGet();
assertThat(result.getStatus(), is(AuthenticationResult.Status.SUCCESS));
User user = result.getUser();
@ -132,7 +131,7 @@ public class PkiRealmTests extends ESTestCase {
X509AuthenticationToken token = realm.token(threadContext);
PlainActionFuture<AuthenticationResult> future = new PlainActionFuture<>();
realm.authenticate(token, future, mock(IncomingRequest.class));
realm.authenticate(token, future);
User user = future.actionGet().getUser();
assertThat(user, is(notNullValue()));
assertThat(user.principal(), is("elasticsearch"));
@ -163,7 +162,7 @@ public class PkiRealmTests extends ESTestCase {
X509AuthenticationToken token = realm.token(threadContext);
PlainActionFuture<AuthenticationResult> future = new PlainActionFuture<>();
realm.authenticate(token, future, mock(IncomingRequest.class));
realm.authenticate(token, future);
User user = future.actionGet().getUser();
assertThat(user, is(notNullValue()));
assertThat(user.principal(), is("Elasticsearch Test Node"));
@ -194,7 +193,7 @@ public class PkiRealmTests extends ESTestCase {
X509AuthenticationToken token = realm.token(threadContext);
PlainActionFuture<AuthenticationResult> future = new PlainActionFuture<>();
realm.authenticate(token, future, mock(IncomingRequest.class));
realm.authenticate(token, future);
User user = future.actionGet().getUser();
assertThat(user, is(nullValue()));
}

View File

@ -14,7 +14,6 @@ import org.elasticsearch.common.util.concurrent.ThreadContext;
import org.elasticsearch.test.ESTestCase;
import org.elasticsearch.test.SecuritySettingsSource;
import org.elasticsearch.xpack.security.authc.AuthenticationResult;
import org.elasticsearch.xpack.security.authc.IncomingRequest;
import org.elasticsearch.xpack.security.authc.Realm;
import org.elasticsearch.xpack.security.authc.RealmConfig;
import org.elasticsearch.xpack.security.user.User;
@ -59,8 +58,7 @@ public class CachingUsernamePasswordRealmTests extends ESTestCase {
RealmConfig config = new RealmConfig("test_realm", settings, globalSettings, new ThreadContext(Settings.EMPTY));
CachingUsernamePasswordRealm realm = new CachingUsernamePasswordRealm("test", config) {
@Override
protected void doAuthenticate(UsernamePasswordToken token, ActionListener<AuthenticationResult> listener,
IncomingRequest incomingRequest) {
protected void doAuthenticate(UsernamePasswordToken token, ActionListener<AuthenticationResult> listener) {
listener.onResponse(AuthenticationResult.success(new User("username", new String[]{"r1", "r2", "r3"})));
}
@ -77,25 +75,25 @@ public class CachingUsernamePasswordRealmTests extends ESTestCase {
AlwaysAuthenticateCachingRealm realm = new AlwaysAuthenticateCachingRealm(globalSettings);
SecureString pass = new SecureString("pass");
PlainActionFuture<AuthenticationResult> future = new PlainActionFuture<>();
realm.authenticate(new UsernamePasswordToken("a", pass), future, mock(IncomingRequest.class));
realm.authenticate(new UsernamePasswordToken("a", pass), future);
future.actionGet();
future = new PlainActionFuture<>();
realm.authenticate(new UsernamePasswordToken("b", pass), future, mock(IncomingRequest.class));
realm.authenticate(new UsernamePasswordToken("b", pass), future);
future.actionGet();
future = new PlainActionFuture<>();
realm.authenticate(new UsernamePasswordToken("c", pass), future, mock(IncomingRequest.class));
realm.authenticate(new UsernamePasswordToken("c", pass), future);
future.actionGet();
assertThat(realm.authInvocationCounter.intValue(), is(3));
future = new PlainActionFuture<>();
realm.authenticate(new UsernamePasswordToken("a", pass), future, mock(IncomingRequest.class));
realm.authenticate(new UsernamePasswordToken("a", pass), future);
future.actionGet();
future = new PlainActionFuture<>();
realm.authenticate(new UsernamePasswordToken("b", pass), future, mock(IncomingRequest.class));
realm.authenticate(new UsernamePasswordToken("b", pass), future);
future.actionGet();
future = new PlainActionFuture<>();
realm.authenticate(new UsernamePasswordToken("c", pass), future, mock(IncomingRequest.class));
realm.authenticate(new UsernamePasswordToken("c", pass), future);
future.actionGet();
assertThat(realm.authInvocationCounter.intValue(), is(3));
@ -141,7 +139,7 @@ public class CachingUsernamePasswordRealmTests extends ESTestCase {
// now authenticate
PlainActionFuture<AuthenticationResult> authFuture = new PlainActionFuture<>();
realm.authenticate(new UsernamePasswordToken("a", new SecureString("pass")), authFuture, mock(IncomingRequest.class));
realm.authenticate(new UsernamePasswordToken("a", new SecureString("pass")), authFuture);
AuthenticationResult authResult = authFuture.actionGet();
assertThat(authResult.getStatus(), is(AuthenticationResult.Status.SUCCESS));
User user = authResult.getUser();
@ -152,7 +150,7 @@ public class CachingUsernamePasswordRealmTests extends ESTestCase {
// authenticate a different user first
authFuture = new PlainActionFuture<>();
realm.authenticate(new UsernamePasswordToken("b", new SecureString("pass")), authFuture, mock(IncomingRequest.class));
realm.authenticate(new UsernamePasswordToken("b", new SecureString("pass")), authFuture);
authResult = authFuture.actionGet();
assertThat(authResult.getStatus(), is(AuthenticationResult.Status.SUCCESS));
user = authResult.getUser();
@ -176,19 +174,19 @@ public class CachingUsernamePasswordRealmTests extends ESTestCase {
SecureString pass2 = new SecureString("password");
PlainActionFuture<AuthenticationResult> future = new PlainActionFuture<>();
realm.authenticate(new UsernamePasswordToken(user, pass1), future, mock(IncomingRequest.class));
realm.authenticate(new UsernamePasswordToken(user, pass1), future);
future.actionGet();
future = new PlainActionFuture<>();
realm.authenticate(new UsernamePasswordToken(user, pass1), future, mock(IncomingRequest.class));
realm.authenticate(new UsernamePasswordToken(user, pass1), future);
future.actionGet();
assertThat(realm.authInvocationCounter.intValue(), is(1));
future = new PlainActionFuture<>();
realm.authenticate(new UsernamePasswordToken(user, pass2), future, mock(IncomingRequest.class));
realm.authenticate(new UsernamePasswordToken(user, pass2), future);
future.actionGet();
future = new PlainActionFuture<>();
realm.authenticate(new UsernamePasswordToken(user, pass2), future, mock(IncomingRequest.class));
realm.authenticate(new UsernamePasswordToken(user, pass2), future);
future.actionGet();
assertThat(realm.authInvocationCounter.intValue(), is(2));
@ -202,21 +200,21 @@ public class CachingUsernamePasswordRealmTests extends ESTestCase {
SecureString password = new SecureString("password");
PlainActionFuture<AuthenticationResult> future = new PlainActionFuture<>();
realm.authenticate(new UsernamePasswordToken(user, password), future, mock(IncomingRequest.class));
realm.authenticate(new UsernamePasswordToken(user, password), future);
assertThat(future.actionGet().getUser().enabled(), equalTo(false));
assertThat(realm.authInvocationCounter.intValue(), is(1));
realm.setUsersEnabled(true);
future = new PlainActionFuture<>();
realm.authenticate(new UsernamePasswordToken(user, password), future, mock(IncomingRequest.class));
realm.authenticate(new UsernamePasswordToken(user, password), future);
future.actionGet();
assertThat(future.actionGet().getUser().enabled(), equalTo(true));
assertThat(realm.authInvocationCounter.intValue(), is(2));
future = new PlainActionFuture<>();
realm.authenticate(new UsernamePasswordToken(user, password), future, mock(IncomingRequest.class));
realm.authenticate(new UsernamePasswordToken(user, password), future);
future.actionGet();
assertThat(future.actionGet().getUser().enabled(), equalTo(true));
@ -235,7 +233,7 @@ public class CachingUsernamePasswordRealmTests extends ESTestCase {
// authenticate
PlainActionFuture<AuthenticationResult> future = new PlainActionFuture<>();
realm.authenticate(authToken, future, mock(IncomingRequest.class));
realm.authenticate(authToken, future);
final User user1 = future.actionGet().getUser();
assertThat(user1.roles(), arrayContaining("testRole1", "testRole2"));
assertThat(realm.authInvocationCounter.intValue(), is(1));
@ -244,7 +242,7 @@ public class CachingUsernamePasswordRealmTests extends ESTestCase {
// authenticate
future = new PlainActionFuture<>();
realm.authenticate(authToken, future, mock(IncomingRequest.class));
realm.authenticate(authToken, future);
final User user2 = future.actionGet().getUser();
assertThat(user2.roles(), arrayContaining("testRole1", "testRole2"));
assertThat(user2, not(sameInstance(user1)));
@ -263,7 +261,7 @@ public class CachingUsernamePasswordRealmTests extends ESTestCase {
PlainActionFuture<AuthenticationResult> future = new PlainActionFuture<>();
// authenticate
realm.authenticate(authToken, future, mock(IncomingRequest.class));
realm.authenticate(authToken, future);
final long start = System.currentTimeMillis();
final User user1 = future.actionGet().getUser();
assertThat(realm.authInvocationCounter.intValue(), is(1));
@ -271,19 +269,19 @@ public class CachingUsernamePasswordRealmTests extends ESTestCase {
// After 100 ms (from the original start time), authenticate (read from cache). We don't care about the result
sleepUntil(start + 100);
future = new PlainActionFuture<>();
realm.authenticate(authToken, future, mock(IncomingRequest.class));
realm.authenticate(authToken, future);
future.actionGet();
// After 200 ms (from the original start time), authenticate (read from cache). We don't care about the result
sleepUntil(start + 200);
future = new PlainActionFuture<>();
realm.authenticate(authToken, future, mock(IncomingRequest.class));
realm.authenticate(authToken, future);
future.actionGet();
// After 300 ms (from the original start time), authenticate again. The cache entry should have expired (despite the previous reads)
sleepUntil(start + 300);
future = new PlainActionFuture<>();
realm.authenticate(authToken, future, mock(IncomingRequest.class));
realm.authenticate(authToken, future);
final User user2 = future.actionGet().getUser();
assertThat(user2, not(sameInstance(user1)));
// Due to slow VMs etc, the cache might have expired more than once during the test, but we can accept that.
@ -301,13 +299,13 @@ public class CachingUsernamePasswordRealmTests extends ESTestCase {
public void testAuthenticateContract() throws Exception {
Realm realm = new FailingAuthenticationRealm(Settings.EMPTY, globalSettings);
PlainActionFuture<AuthenticationResult> future = new PlainActionFuture<>();
realm.authenticate(new UsernamePasswordToken("user", new SecureString("pass")), future, mock(IncomingRequest.class));
realm.authenticate(new UsernamePasswordToken("user", new SecureString("pass")), future);
User user = future.actionGet().getUser();
assertThat(user, nullValue());
realm = new ThrowingAuthenticationRealm(Settings.EMPTY, globalSettings);
future = new PlainActionFuture<>();
realm.authenticate(new UsernamePasswordToken("user", new SecureString("pass")), future, mock(IncomingRequest.class));
realm.authenticate(new UsernamePasswordToken("user", new SecureString("pass")), future);
RuntimeException e = expectThrows(RuntimeException.class, future::actionGet);
assertThat(e.getMessage(), containsString("whatever exception"));
}
@ -335,8 +333,7 @@ public class CachingUsernamePasswordRealmTests extends ESTestCase {
RealmConfig config = new RealmConfig("test_realm", Settings.EMPTY, globalSettings, new ThreadContext(Settings.EMPTY));
final CachingUsernamePasswordRealm realm = new CachingUsernamePasswordRealm("test", config) {
@Override
protected void doAuthenticate(UsernamePasswordToken token, ActionListener<AuthenticationResult> listener,
IncomingRequest incomingRequest) {
protected void doAuthenticate(UsernamePasswordToken token, ActionListener<AuthenticationResult> listener) {
// do something slow
if (BCrypt.checkpw(token.credentials(), passwordHash)) {
listener.onResponse(AuthenticationResult.success(new User(username, new String[]{"r1", "r2", "r3"})));
@ -375,7 +372,7 @@ public class CachingUsernamePasswordRealmTests extends ESTestCase {
}, (e) -> {
logger.error("caught exception", e);
fail("unexpected exception - " + e);
}), mock(IncomingRequest.class));
}));
}
} catch (InterruptedException e) {
@ -399,8 +396,7 @@ public class CachingUsernamePasswordRealmTests extends ESTestCase {
RealmConfig config = new RealmConfig("test_realm", Settings.EMPTY, globalSettings, new ThreadContext(Settings.EMPTY));
final CachingUsernamePasswordRealm realm = new CachingUsernamePasswordRealm("test", config) {
@Override
protected void doAuthenticate(UsernamePasswordToken token, ActionListener<AuthenticationResult> listener,
IncomingRequest incomingRequest) {
protected void doAuthenticate(UsernamePasswordToken token, ActionListener<AuthenticationResult> listener) {
listener.onFailure(new UnsupportedOperationException("authenticate should not be called!"));
}
@ -454,8 +450,7 @@ public class CachingUsernamePasswordRealmTests extends ESTestCase {
}
@Override
protected void doAuthenticate(UsernamePasswordToken token, ActionListener<AuthenticationResult> listener,
IncomingRequest incomingRequest) {
protected void doAuthenticate(UsernamePasswordToken token, ActionListener<AuthenticationResult> listener) {
listener.onResponse(AuthenticationResult.notHandled());
}
@ -472,8 +467,7 @@ public class CachingUsernamePasswordRealmTests extends ESTestCase {
}
@Override
protected void doAuthenticate(UsernamePasswordToken token, ActionListener<AuthenticationResult> listener,
IncomingRequest incomingRequest) {
protected void doAuthenticate(UsernamePasswordToken token, ActionListener<AuthenticationResult> listener) {
listener.onFailure(new RuntimeException("whatever exception"));
}
@ -503,8 +497,7 @@ public class CachingUsernamePasswordRealmTests extends ESTestCase {
}
@Override
protected void doAuthenticate(UsernamePasswordToken token, ActionListener<AuthenticationResult> listener,
IncomingRequest incomingRequest) {
protected void doAuthenticate(UsernamePasswordToken token, ActionListener<AuthenticationResult> listener) {
authInvocationCounter.incrementAndGet();
final User user = new User(token.principal(), new String[]{"testRole1", "testRole2"}, null, null, emptyMap(), usersEnabled);
listener.onResponse(AuthenticationResult.success(user));
@ -527,8 +520,7 @@ public class CachingUsernamePasswordRealmTests extends ESTestCase {
}
@Override
protected void doAuthenticate(UsernamePasswordToken token, ActionListener<AuthenticationResult> listener,
IncomingRequest incomingRequest) {
protected void doAuthenticate(UsernamePasswordToken token, ActionListener<AuthenticationResult> listener) {
authInvocationCounter.incrementAndGet();
listener.onResponse(AuthenticationResult.success(new User(token.principal(), new String[]{"testRole1", "testRole2"})));
}

View File

@ -349,25 +349,8 @@ public class AuthorizationServiceTests extends ESTestCase {
verifyNoMoreInteractions(auditTrail);
}
@AwaitsFix(bugUrl = "https://github.com/elastic/x-pack-elasticsearch/issues/1217")
public void testElasticUserOnlyAuthorizedForChangePasswordRequestsInSetupMode() {
final User user = new ElasticUser(true, true);
final ChangePasswordRequest changePasswordrequest = new ChangePasswordRequestBuilder(mock(Client.class))
.username(user.principal()).request();
authorize(createAuthentication(user), ChangePasswordAction.NAME, changePasswordrequest);
verify(auditTrail).accessGranted(user, ChangePasswordAction.NAME, changePasswordrequest);
Tuple<String, TransportRequest> request = randomCompositeRequest();
assertThrowsAuthorizationException(() -> authorize(createAuthentication(user), request.v1(), request.v2()),
request.v1(), "elastic");
verify(auditTrail).accessDenied(user, request.v1(), request.v2());
}
public void testElasticUserAuthorizedForNonChangePasswordRequestsWhenNotInSetupMode() {
final User user = new ElasticUser(true, false);
final User user = new ElasticUser(true);
Tuple<String, TransportRequest> request = randomCompositeRequest();
authorize(createAuthentication(user), request.v1(), request.v2());

View File

@ -38,9 +38,7 @@ import static org.elasticsearch.xpack.security.authc.support.UsernamePasswordTok
public abstract class XPackRestTestCase extends ESClientYamlSuiteTestCase {
private static final String BASIC_AUTH_VALUE =
basicAuthHeaderValue("elastic", SecuritySettingsSource.TEST_PASSWORD_SECURE_STRING);
private final SetOnce<Integer> oneAllowed401 = new SetOnce<>();
basicAuthHeaderValue("x_pack_rest_user", SecuritySettingsSource.TEST_PASSWORD_SECURE_STRING);
public XPackRestTestCase(@Name("yaml") ClientYamlTestCandidate testCandidate) {
super(testCandidate);
@ -58,26 +56,6 @@ public abstract class XPackRestTestCase extends ESClientYamlSuiteTestCase {
.build();
}
@Before
public void setPasswords() throws IOException {
BasicHeader authHeader = new BasicHeader("Authorization",
basicAuthHeaderValue("elastic", new SecureString("".toCharArray())));
String elasticUserPayload = "{\"password\" : \"" + SecuritySettingsSource.TEST_PASSWORD + "\"}";
try {
client().performRequest("put", "_xpack/security/user/elastic/_password", Collections.emptyMap(),
new StringEntity(elasticUserPayload, ContentType.APPLICATION_JSON), authHeader);
} catch (ResponseException e) {
// The password might have already been set by the build.gradle file. So we ignore unsuccessful attempts
// due to failed authentication
if (e.getResponse().getStatusLine().getStatusCode() != 401) {
throw e;
} else {
oneAllowed401.set(e.getResponse().getStatusLine().getStatusCode());
}
}
}
/**
* Waits for the Machine Learning templates to be created by {@link MachineLearningTemplateRegistry}.
*/

View File

@ -28,7 +28,7 @@ Closure waitWithAuth = { NodeInfo node, AntBuilder ant ->
try {
httpURLConnection = (HttpURLConnection) new URL("http://${node.httpUri()}/_cluster/health?wait_for_nodes=${node.config.numNodes}&wait_for_status=yellow").openConnection();
httpURLConnection.setRequestProperty("Authorization", "Basic " +
Base64.getEncoder().encodeToString("elastic:changeme".getBytes(StandardCharsets.UTF_8)));
Base64.getEncoder().encodeToString("test_user:x-pack-test-password".getBytes(StandardCharsets.UTF_8)));
httpURLConnection.setRequestMethod("GET");
httpURLConnection.setConnectTimeout(1000);
httpURLConnection.setReadTimeout(30000); // read needs to wait for nodes!
@ -116,12 +116,11 @@ subprojects {
numBwcNodes = 2
numNodes = 2
clusterName = 'full-cluster-restart'
setupCommand 'setupTestUser', 'bin/x-pack/users', 'useradd', 'test_user', '-p', 'x-pack-test-password', '-r', 'superuser'
waitCondition = waitWithAuth
setting 'xpack.security.transport.ssl.enabled', 'true'
setting 'xpack.ssl.keystore.path', 'testnode.jks'
setting 'xpack.ssl.keystore.password', 'testnode'
setting 'xpack.security.authc.realms.native.type', 'native'
setting 'xpack.security.authc.realms.native.order', '0'
dependsOn copyTestNodeKeystore
extraConfigFile 'testnode.jks', new File(outputDir + '/testnode.jks')
if (withSystemKey) {
@ -152,11 +151,10 @@ subprojects {
numNodes = 2
clusterName = 'full-cluster-restart'
dataDir = { nodeNum -> oldClusterTest.nodes[nodeNum].dataDir }
setupCommand 'setupTestUser', 'bin/x-pack/users', 'useradd', 'test_user', '-p', 'x-pack-test-password', '-r', 'superuser'
waitCondition = waitWithAuth
setting 'xpack.ssl.keystore.path', 'testnode.jks'
keystoreSetting 'xpack.ssl.keystore.secure_password', 'testnode'
setting 'xpack.security.authc.realms.native.type', 'native'
setting 'xpack.security.authc.realms.native.order', '0'
dependsOn copyTestNodeKeystore
extraConfigFile 'testnode.jks', new File(outputDir + '/testnode.jks')
if (withSystemKey) {

View File

@ -84,7 +84,7 @@ public class FullClusterRestartIT extends ESRestTestCase {
@Override
protected Settings restClientSettings() {
String token = "Basic " + Base64.getEncoder().encodeToString("elastic:changeme".getBytes(StandardCharsets.UTF_8));
String token = "Basic " + Base64.getEncoder().encodeToString("test_user:x-pack-test-password".getBytes(StandardCharsets.UTF_8));
return Settings.builder()
.put(ThreadContext.PREFIX + ".Authorization", token)
// we increase the timeout here to 90 seconds to handle long waits for a green

View File

@ -31,7 +31,7 @@ Closure waitWithAuth = { NodeInfo node, AntBuilder ant ->
// TODO this sucks having to hardcode number of nodes, but node.config.numNodes isn't necessarily accurate for rolling
httpURLConnection = (HttpURLConnection) new URL("http://${node.httpUri()}/_cluster/health?wait_for_nodes=2&wait_for_status=yellow").openConnection();
httpURLConnection.setRequestProperty("Authorization", "Basic " +
Base64.getEncoder().encodeToString("elastic:changeme".getBytes(StandardCharsets.UTF_8)));
Base64.getEncoder().encodeToString("test_user:x-pack-test-password".getBytes(StandardCharsets.UTF_8)));
httpURLConnection.setRequestMethod("GET");
httpURLConnection.setConnectTimeout(1000);
httpURLConnection.setReadTimeout(30000); // read needs to wait for nodes!
@ -114,6 +114,7 @@ subprojects {
configure(extensions.findByName("${baseName}#oldClusterTestCluster")) {
dependsOn copyTestNodeKeystore
plugin ':x-pack-elasticsearch:plugin'
setupCommand 'setupTestUser', 'bin/x-pack/users', 'useradd', 'test_user', '-p', 'x-pack-test-password', '-r', 'superuser'
distribution = 'zip'
bwcVersion = version
numBwcNodes = 2
@ -146,6 +147,7 @@ subprojects {
configure(extensions.findByName("${baseName}#mixedClusterTestCluster")) {
dependsOn oldClusterTestRunner, "${baseName}#oldClusterTestCluster#node1.stop"
plugin ':x-pack-elasticsearch:plugin'
setupCommand 'setupTestUser', 'bin/x-pack/users', 'useradd', 'test_user', '-p', 'x-pack-test-password', '-r', 'superuser'
distribution = 'zip'
clusterName = 'rolling-upgrade'
unicastTransportUri = { seedNode, node, ant -> oldClusterTest.nodes.get(0).transportUri() }
@ -175,6 +177,7 @@ subprojects {
configure(extensions.findByName("${baseName}#upgradedClusterTestCluster")) {
dependsOn(mixedClusterTestRunner, "${baseName}#oldClusterTestCluster#node0.stop")
plugin ':x-pack-elasticsearch:plugin'
setupCommand 'setupTestUser', 'bin/x-pack/users', 'useradd', 'test_user', '-p', 'x-pack-test-password', '-r', 'superuser'
distribution = 'zip'
clusterName = 'rolling-upgrade'
unicastTransportUri = { seedNode, node, ant -> mixedClusterTest.nodes.get(0).transportUri() }
@ -228,7 +231,6 @@ subprojects {
dependsOn = ["v${wireCompatVersions[-1]}#bwcTest"]
}
}
check.dependsOn(integTest)
dependencies {

View File

@ -56,7 +56,7 @@ public class UpgradeClusterClientYamlTestSuiteIT extends SecurityClusterClientYa
@Override
protected Settings restClientSettings() {
String token = "Basic " + Base64.getEncoder().encodeToString(("elastic:changeme").getBytes(StandardCharsets.UTF_8));
String token = "Basic " + Base64.getEncoder().encodeToString(("test_user:x-pack-test-password").getBytes(StandardCharsets.UTF_8));
return Settings.builder()
.put(ThreadContext.PREFIX + ".Authorization", token)
// we increase the timeout here to 90 seconds to handle long waits for a green

View File

@ -112,7 +112,7 @@ public class WatchBackwardsCompatibilityIT extends ESRestTestCase {
@Override
protected Settings restClientSettings() {
String token = "Basic " + Base64.getEncoder()
.encodeToString(("elastic:changeme").getBytes(StandardCharsets.UTF_8));
.encodeToString(("test_user:x-pack-test-password").getBytes(StandardCharsets.UTF_8));
return Settings.builder()
.put(ThreadContext.PREFIX + ".Authorization", token)
.build();

View File

@ -9,13 +9,12 @@ import org.elasticsearch.action.ActionListener;
import org.elasticsearch.common.settings.SecureString;
import org.elasticsearch.common.util.concurrent.ThreadContext;
import org.elasticsearch.xpack.security.authc.AuthenticationResult;
import org.elasticsearch.xpack.security.authc.IncomingRequest;
import org.elasticsearch.xpack.security.authc.support.CharArrays;
import org.elasticsearch.xpack.security.user.User;
import org.elasticsearch.xpack.security.authc.AuthenticationToken;
import org.elasticsearch.xpack.security.authc.Realm;
import org.elasticsearch.xpack.security.authc.RealmConfig;
import org.elasticsearch.xpack.security.authc.support.CharArrays;
import org.elasticsearch.xpack.security.authc.support.UsernamePasswordToken;
import org.elasticsearch.xpack.security.user.User;
public class CustomRealm extends Realm {
@ -50,8 +49,7 @@ public class CustomRealm extends Realm {
}
@Override
public void authenticate(AuthenticationToken authToken, ActionListener<AuthenticationResult> listener,
IncomingRequest incomingRequest) {
public void authenticate(AuthenticationToken authToken, ActionListener<AuthenticationResult> listener) {
UsernamePasswordToken token = (UsernamePasswordToken)authToken;
final String actualUser = token.principal();
if (KNOWN_USER.equals(actualUser)) {

View File

@ -10,17 +10,14 @@ import org.elasticsearch.common.settings.SecureString;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.common.util.concurrent.ThreadContext;
import org.elasticsearch.env.Environment;
import org.elasticsearch.test.ESTestCase;
import org.elasticsearch.xpack.security.authc.AuthenticationResult;
import org.elasticsearch.xpack.security.authc.IncomingRequest;
import org.elasticsearch.xpack.security.user.User;
import org.elasticsearch.xpack.security.authc.RealmConfig;
import org.elasticsearch.xpack.security.authc.support.UsernamePasswordToken;
import org.elasticsearch.test.ESTestCase;
import org.elasticsearch.xpack.security.user.User;
import static org.hamcrest.Matchers.equalTo;
import static org.hamcrest.Matchers.notNullValue;
import static org.hamcrest.Matchers.nullValue;
import static org.mockito.Mockito.mock;
public class CustomRealmTests extends ESTestCase {
public void testAuthenticate() {
@ -29,7 +26,7 @@ public class CustomRealmTests extends ESTestCase {
SecureString password = CustomRealm.KNOWN_PW.clone();
UsernamePasswordToken token = new UsernamePasswordToken(CustomRealm.KNOWN_USER, password);
PlainActionFuture<AuthenticationResult> plainActionFuture = new PlainActionFuture<>();
realm.authenticate(token, plainActionFuture, mock(IncomingRequest.class));
realm.authenticate(token, plainActionFuture);
User user = plainActionFuture.actionGet().getUser();
assertThat(user, notNullValue());
assertThat(user.roles(), equalTo(CustomRealm.ROLES));
@ -42,7 +39,7 @@ public class CustomRealmTests extends ESTestCase {
SecureString password = CustomRealm.KNOWN_PW.clone();
UsernamePasswordToken token = new UsernamePasswordToken(CustomRealm.KNOWN_USER + "1", password);
PlainActionFuture<AuthenticationResult> plainActionFuture = new PlainActionFuture<>();
realm.authenticate(token, plainActionFuture, mock(IncomingRequest.class));
realm.authenticate(token, plainActionFuture);
final AuthenticationResult result = plainActionFuture.actionGet();
assertThat(result.getStatus(), equalTo(AuthenticationResult.Status.CONTINUE));
}

View File

@ -12,6 +12,7 @@ import org.apache.http.HttpHost;
import org.apache.http.entity.ContentType;
import org.apache.http.message.BasicHeader;
import org.apache.http.nio.entity.NStringEntity;
import org.apache.lucene.util.LuceneTestCase;
import org.elasticsearch.action.admin.cluster.health.ClusterHealthResponse;
import org.elasticsearch.client.Response;
import org.elasticsearch.client.RestClient;
@ -96,24 +97,6 @@ public class TribeWithSecurityIT extends SecurityIntegTestCase {
public void addSecurityIndex() throws IOException {
client().admin().indices().prepareCreate(INTERNAL_SECURITY_INDEX).get();
cluster2.client().admin().indices().prepareCreate(INTERNAL_SECURITY_INDEX).get();
InetSocketAddress[] inetSocketAddresses = cluster2.httpAddresses();
List<HttpHost> hosts = new ArrayList<>();
for (InetSocketAddress socketAddress : inetSocketAddresses) {
hosts.add(new HttpHost(socketAddress.getAddress(), socketAddress.getPort()));
}
RestClientBuilder builder = RestClient.builder(hosts.toArray(new HttpHost[hosts.size()]));
RestClient client = builder.build();
SecureString defaultPassword = new SecureString("".toCharArray());
String payload = "{\"password\": \"" + SecuritySettingsSource.TEST_PASSWORD + "\"}";
HttpEntity entity = new NStringEntity(payload, ContentType.APPLICATION_JSON);
BasicHeader authHeader = new BasicHeader(UsernamePasswordToken.BASIC_AUTH_HEADER,
UsernamePasswordToken.basicAuthHeaderValue(ElasticUser.NAME, defaultPassword));
String route = "/_xpack/security/user/elastic/_password";
Response response = getRestClient().performRequest("PUT", route, Collections.emptyMap(), entity, authHeader);
client.close();
}
@Override
@ -135,6 +118,7 @@ public class TribeWithSecurityIT extends SecurityIntegTestCase {
return new ExternalTestCluster(createTempDir(), externalClusterClientSettings(), transportClientPlugins(), transportAddresses);
}
@LuceneTestCase.AwaitsFix(bugUrl = "https://github.com/elastic/x-pack-elasticsearch/issues/1996")
public void testThatTribeCanAuthenticateElasticUser() throws Exception {
ClusterHealthResponse response = tribeNode.client().filterWithHeader(Collections.singletonMap("Authorization",
UsernamePasswordToken.basicAuthHeaderValue("elastic", SecuritySettingsSource.TEST_PASSWORD_SECURE_STRING)))
@ -142,6 +126,7 @@ public class TribeWithSecurityIT extends SecurityIntegTestCase {
assertNoTimeout(response);
}
@LuceneTestCase.AwaitsFix(bugUrl = "https://github.com/elastic/x-pack-elasticsearch/issues/1996")
public void testThatTribeCanAuthenticateElasticUserWithChangedPassword() throws Exception {
securityClient(client()).prepareChangePassword("elastic", "password".toCharArray()).get();
@ -152,6 +137,7 @@ public class TribeWithSecurityIT extends SecurityIntegTestCase {
assertNoTimeout(response);
}
@LuceneTestCase.AwaitsFix(bugUrl = "https://github.com/elastic/x-pack-elasticsearch/issues/1996")
public void testThatTribeClustersHaveDifferentPasswords() throws Exception {
securityClient().prepareChangePassword("elastic", "password".toCharArray()).get();
securityClient(cluster2.client()).prepareChangePassword("elastic", "password2".toCharArray()).get();