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:
parent
4de6d9ebe5
commit
6d04eacdec
|
@ -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'
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
||||
}
|
||||
}
|
|
@ -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}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
@ -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));
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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));
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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(() -> {
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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() {
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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());
|
||||
}
|
||||
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
@ -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));
|
||||
}
|
||||
|
|
|
@ -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")));
|
||||
|
|
|
@ -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());
|
||||
|
|
|
@ -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()));
|
||||
}
|
||||
|
|
|
@ -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"})));
|
||||
}
|
||||
|
|
|
@ -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());
|
||||
|
||||
|
|
|
@ -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}.
|
||||
*/
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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)) {
|
||||
|
|
|
@ -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));
|
||||
}
|
||||
|
|
|
@ -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();
|
||||
|
|
Loading…
Reference in New Issue