Merge branch 'master' into feature/sql

Original commit: elastic/x-pack-elasticsearch@51fc29da6a
This commit is contained in:
Nik Everett 2017-07-03 18:04:09 -04:00
commit 50a46d0ed2
194 changed files with 1608 additions and 1070 deletions

View File

@ -113,7 +113,7 @@ Closure waitWithAuth = { NodeInfo node, AntBuilder ant ->
try {
httpURLConnection = (HttpURLConnection) new URL("http://${node.httpUri()}/_cluster/health").openConnection();
httpURLConnection.setRequestProperty("Authorization", "Basic " +
Base64.getEncoder().encodeToString("test_admin:changeme".getBytes(StandardCharsets.UTF_8)));
Base64.getEncoder().encodeToString("test_admin:x-pack-test-password".getBytes(StandardCharsets.UTF_8)));
httpURLConnection.setRequestMethod("GET");
httpURLConnection.setConnectTimeout(1000);
httpURLConnection.setReadTimeout(30000);
@ -145,7 +145,7 @@ Closure waitWithAuth = { NodeInfo node, AntBuilder ant ->
integTestCluster {
plugin ':x-pack-elasticsearch:plugin'
setupCommand 'setupTestAdmin',
'bin/x-pack/users', 'useradd', 'test_admin', '-p', 'changeme', '-r', 'superuser'
'bin/x-pack/users', 'useradd', 'test_admin', '-p', 'x-pack-test-password', '-r', 'superuser'
waitCondition = waitWithAuth
}

View File

@ -6,7 +6,6 @@
:es-repo-dir: {docdir}/../../../../elasticsearch/docs
:es-test-dir: {docdir}/../../../../elasticsearch/docs/src/test
:plugins-examples-dir: {docdir}/../../../../elasticsearch/plugins/examples
:docs-dir: {docdir}/../../../../docs
include::{es-repo-dir}/Versions.asciidoc[]

View File

@ -72,8 +72,8 @@ make it easier to control which users have authority to view and manage the jobs
{dfeeds}, and results.
By default, you can perform all of the steps in this tutorial by using the
built-in `elastic` super user. The default password for the `elastic` user is
`changeme`. For information about how to change that password, see
built-in `elastic` super user. However, the password must be set before the user
can do anything. For information about how to set that password, see
<<security-getting-started>>.
If you are performing these steps in a production environment, take extra care
@ -191,7 +191,7 @@ mapping for the data set:
[source,shell]
----------------------------------
curl -u elastic:changeme -X PUT -H 'Content-Type: application/json'
curl -u elastic:x-pack-test-password -X PUT -H 'Content-Type: application/json'
http://localhost:9200/server-metrics -d '{
"settings":{
"number_of_shards":1,
@ -227,7 +227,7 @@ http://localhost:9200/server-metrics -d '{
}'
----------------------------------
NOTE: If you run this command, you must replace `changeme` with your
NOTE: If you run this command, you must replace `x-pack-test-password` with your
actual password.
////
@ -247,16 +247,16 @@ example, which loads the four JSON files:
[source,shell]
----------------------------------
curl -u elastic:changeme -X POST -H "Content-Type: application/json"
curl -u elastic:x-pack-test-password -X POST -H "Content-Type: application/json"
http://localhost:9200/server-metrics/_bulk --data-binary "@server-metrics_1.json"
curl -u elastic:changeme -X POST -H "Content-Type: application/json"
curl -u elastic:x-pack-test-password -X POST -H "Content-Type: application/json"
http://localhost:9200/server-metrics/_bulk --data-binary "@server-metrics_2.json"
curl -u elastic:changeme -X POST -H "Content-Type: application/json"
curl -u elastic:x-pack-test-password -X POST -H "Content-Type: application/json"
http://localhost:9200/server-metrics/_bulk --data-binary "@server-metrics_3.json"
curl -u elastic:changeme -X POST -H "Content-Type: application/json"
curl -u elastic:x-pack-test-password -X POST -H "Content-Type: application/json"
http://localhost:9200/server-metrics/_bulk --data-binary "@server-metrics_4.json"
----------------------------------
@ -271,7 +271,7 @@ You can verify that the data was loaded successfully with the following command:
[source,shell]
----------------------------------
curl 'http://localhost:9200/_cat/indices?v' -u elastic:changeme
curl 'http://localhost:9200/_cat/indices?v' -u elastic:x-pack-test-password
----------------------------------
You should see output similar to the following:

View File

@ -13,7 +13,7 @@ To change the password of the logged in user, submit a POST request to the
--------------------------------------------------
POST _xpack/security/user/elastic/_password
{
"password": "changeme"
"password": "x-pack-test-password"
}
--------------------------------------------------
// CONSOLE

View File

@ -16,8 +16,8 @@ endpoint.
POST /_xpack/security/oauth2/token
{
"grant_type" : "password",
"username" : "elastic",
"password" : "changeme"
"username" : "test_admin",
"password" : "x-pack-test-password"
}
--------------------------------------------------
// CONSOLE

View File

@ -15,9 +15,11 @@ see <<managing-native-users, Managing Native Users>>.
=== Built-in Users
{security} provides built-in user credentials to help you get up and running.
These users have a fixed set of privileges and the default password `changeme`.
Please read <<reset-built-in-user-passwords,Reset Built-in User Passwords>> and
<<disabling-default-password, Disable Default Password Functionality>> below.
These users have a fixed set of privileges and cannot be authenticated until their
passwords have been set. The exception is the `elastic` user which can be authenticated
from a localhost rest request with an empty password. Until a password is set, the elastic
user is only authorized to perform change password requests.
Please read <<reset-built-in-user-passwords,Reset Built-in User Passwords>> below.
.{security} Built-in Users
|========
@ -48,8 +50,7 @@ be disabled individually, using the
==== Reset Built-in User Passwords
[IMPORTANT]
=============================================================================
You must reset the default passwords for all built-in users, and then
<<disabling-default-password, disable default password support>>.
You must set the passwords for all built-in users.
You can update passwords from the *Management > Users* UI in Kibana or with the
{ref}/security-api-users.html#security-api-reset-user-password[Reset Password API]:
@ -117,14 +118,8 @@ PUT _xpack/security/user/logstash_system/_enable
==== Disable Default Password Functionality
[IMPORTANT]
=============================================================================
The default password of `changeme` is provided as a convenience that allows you to quickly
setup your Elasticsearch stack. It should not be used when running in production.
Once you have changed the password for the built-in users, you must disable default password support
by setting `xpack.security.authc.accept_default_password` to `false`.
A {ref}/bootstrap-checks.html[bootstrap check] will prevent your cluster from operating in production
mode until you make this configuration change.
This setting is deprecated. The elastic user no longer has a default password. The password must
be set before the user can be used.
=============================================================================

View File

@ -61,7 +61,7 @@ xpack:
order: 0
url: "ldaps://ldap.example.com:636"
bind_dn: "cn=ldapuser, ou=users, o=services, dc=example, dc=com"
bind_password: changeme
bind_password: x-pack-test-password
user_search:
base_dn: "dc=example,dc=com"
attribute: cn

View File

@ -21,7 +21,7 @@ Run the migrate tool after you install the X-Pack plugin. For example:
[source, sh]
----------------------------------------------------------------------
$ bin/x-pack/migrate native -U http://localhost:9200 -u elastic -p changeme
$ bin/x-pack/migrate native -U http://localhost:9200 -u elastic -p x-pack-test-password
-n lee,foo -r role1,role2,role3,role4,foo
starting migration of users and roles...
importing users from [/home/es/config/shield/users]...
@ -69,5 +69,5 @@ to specify a different configuration directory, the command would look like:
[source, sh]
----------------------------------------------------------------------
$ bin/x-pack/migrate native -U http://localhost:9200 -u elastic -p changeme --path.conf /etc/elasticsearch
$ bin/x-pack/migrate native -U http://localhost:9200 -u elastic -p x-pack-test-password --path.conf /etc/elasticsearch
----------------------------------------------------------------------

View File

@ -80,7 +80,7 @@ xpack:
type: pki
truststore:
path: "/path/to/pki_truststore.jks"
password: "changeme"
password: "x-pack-test-password"
------------------------------------------------------------
. Restart Elasticsearch.

View File

@ -36,7 +36,8 @@ curl -XPUT -u elastic 'localhost:9200/_xpack/security/user/logstash_system/_pass
----------------------------------------------------------
// NOTCONSOLE
NOTE: The default password for the `elastic` user is `changeme`.
NOTE: By default, the `elastic` user does not have a password set. Until its password is set, the `elastic` user will only be
allowed to submit change password rest requests from localhost.
--
@ -72,23 +73,6 @@ curl -XPOST -u elastic 'localhost:9200/_xpack/security/user/johndoe' -H "Content
// NOTCONSOLE
--
[[enable-message-authentication]]
. Enable message authentication to verify that messages are not tampered with or corrupted in transit:
.. Run the `syskeygen` tool from `ES_HOME` without any options:
+
[source, shell]
----------------
bin/x-pack/syskeygen
----------------
+
This creates a system key file in `CONFIG_DIR/x-pack/system_key`.
.. Copy the generated system key to the rest of the nodes in the cluster.
+
IMPORTANT: The system key is a symmetric key, so the same key must be on every
node in the cluster.
[[enable-auditing]]
. Enable Auditing to keep track of attempted and successful interactions with
your Elasticsearch cluster:

View File

@ -52,11 +52,8 @@ A critical part of security is keeping confidential data confidential.
Elasticsearch has built-in protections against accidental data loss and
corruption. However, there's nothing to stop deliberate tampering or data
interception. {security} preserves the integrity of your data by
<<ssl-tls, encrypting communications>> to and from nodes and
<<enable-message-authentication, authenticating messages>> to verify that they
have not been tampered with or corrupted in transit during node-to-node
communication. For even greater protection, you can increase the
<<ciphers, encryption strength>> and
<<ssl-tls, encrypting communications>> to and from nodes.
For even greater protection, you can increase the <<ciphers, encryption strength>> and
<<separating-node-client-traffic, separate client traffic from node-to-node communications>>.

View File

@ -20,10 +20,6 @@ The {security} uses the following files:
* `CONFIG_DIR/x-pack/log4j2.properties` contains audit information (read more
<<logging-file, here>>).
* `CONFIG_DIR/x-pack/system_key` holds a cluster secret key that's used to
authenticate messages during node to node communication. For more information,
see <<enable-message-authentication, Enabling Message Authentication>>.
[[security-files-location]]
IMPORTANT: Any files that {security} uses must be stored in the Elasticsearch

View File

@ -102,7 +102,7 @@ March 15, 2016
.Bug Fixes
* Enable <<field-and-document-access-control,document and field level security>> by default.
* Fix issues with <<enable-message-authentication,message authentication>> on certain JDKs that do not support cloning message
* Fix issues with message authentication on certain JDKs that do not support cloning message
authentication codes.
* Built in <<setting-up-authentication, realms>> no longer throw an exception if the `Authorization` header does not contain a basic
authentication token.
@ -209,7 +209,7 @@ the correct user to index the audit events.
July 21, 2015
.Bug Fixes
* Fixes <<enable-message-authentication,message authentication>> serialization to work with Shield 1.2.1 and earlier.
* Fixes message authentication serialization to work with Shield 1.2.1 and earlier.
** NOTE: if you are upgrading from Shield 1.3.0 or Shield 1.2.2 a {ref-17}/setup-upgrade.html#restart-upgrade[cluster restart upgrade]
will be necessary. When upgrading from other versions of Shield, follow the normal upgrade procedure.
@ -245,7 +245,7 @@ June 24, 2015
July 21, 2015
.Bug Fixes
* Fixes <<enable-message-authentication,message authentication>> serialization to work with Shield 1.2.1 and earlier.
* Fixes message authentication serialization to work with Shield 1.2.1 and earlier.
** NOTE: if you are upgrading from Shield 1.2.2 a {ref-17}/setup-upgrade.html#restart-upgrade[cluster restart upgrade]
will be necessary. When upgrading from other versions of Shield, follow the normal upgrade procedure.

View File

@ -58,11 +58,11 @@ for the client traffic by adding the following to `elasticsearch.yml`:
--------------------------------------------------
transport.profiles.client.xpack.security.ssl.truststore:
path: /path/to/another/truststore
password: changeme
password: x-pack-test-password
transport.profiles.client.xpack.security.ssl.keystore:
path: /path/to/another/keystore
password: changeme
password: x-pack-test-password
--------------------------------------------------
To change the default behavior that requires certificates for transport clients,

View File

@ -57,7 +57,7 @@ users from the **Management / Users** UI in Kibana or through the
---------------------------------------------------------------
POST /_xpack/security/user/packetbeat_internal
{
"password" : "changeme",
"password" : "x-pack-test-password",
"roles" : [ "packetbeat_writer"],
"full_name" : "Internal Packetbeat User"
}
@ -87,7 +87,7 @@ output.elasticsearch:
hosts: ["localhost:9200"]
index: "packetbeat"
username: "packetbeat_internal"
password: "changeme"
password: "x-pack-test-password"
--------------------------------------------------
.. To use PKI authentication, configure the `certificate` and
@ -144,7 +144,7 @@ the `packetbeat_reader` role:
---------------------------------------------------------------
POST /_xpack/security/user/packetbeat_user
{
"password" : "changeme",
"password" : "x-pack-test-password",
"roles" : [ "packetbeat_reader"],
"full_name" : "Packetbeat User"
}

View File

@ -137,7 +137,7 @@ import org.elasticsearch.xpack.client.PreBuiltXPackTransportClient;
TransportClient client = new PreBuiltXPackTransportClient(Settings.builder()
.put("cluster.name", "myClusterName")
.put("xpack.security.user", "transport_client_user:changeme")
.put("xpack.security.user", "transport_client_user:x-pack-test-password")
...
.build())
.addTransportAddress(new InetSocketTransportAddress("localhost", 9300))
@ -169,14 +169,14 @@ import static org.elasticsearch.xpack.security.authc.support.UsernamePasswordTok
TransportClient client = new PreBuiltXPackTransportClient(Settings.builder()
.put("cluster.name", "myClusterName")
.put("xpack.security.user", "transport_client_user:changeme")
.put("xpack.security.user", "transport_client_user:x-pack-test-password")
...
.build())
.build()
.addTransportAddress(new InetSocketTransportAddress(InetAddress.getByName("localhost"), 9300))
.addTransportAddress(new InetSocketTransportAddress(InetAddress.getByName("localhost"), 9301))
String token = basicAuthHeaderValue("test_user", new SecureString("changeme".toCharArray()));
String token = basicAuthHeaderValue("test_user", new SecureString("x-pack-test-password".toCharArray()));
client.filterWithHeader(Collections.singletonMap("Authorization", token))
.prepareSearch().get();
@ -198,7 +198,7 @@ import org.elasticsearch.xpack.client.PreBuiltXPackTransportClient;
TransportClient client = new PreBuiltXPackTransportClient(Settings.builder()
.put("cluster.name", "myClusterName")
.put("xpack.security.user", "transport_client_user:changeme")
.put("xpack.security.user", "transport_client_user:x-pack-test-password")
.put("xpack.ssl.key", "/path/to/client.key")
.put("xpack.ssl.certificate", "/path/to/client.crt")
.put("xpack.ssl.certificate_authorities", "/path/to/ca.crt")
@ -217,7 +217,7 @@ import org.elasticsearch.xpack.client.PreBuiltXPackTransportClient;
TransportClient client = new PreBuiltXPackTransportClient(Settings.builder()
.put("cluster.name", "myClusterName")
.put("xpack.security.user", "transport_client_user:changeme")
.put("xpack.security.user", "transport_client_user:x-pack-test-password")
.put("xpack.ssl.key", "/path/to/client.key")
.put("xpack.ssl.certificate", "/path/to/client.crt")
.put("xpack.ssl.certificate_authorities", "/path/to/ca.crt")
@ -246,7 +246,7 @@ import org.elasticsearch.xpack.client.PreBuiltXPackTransportClient;
TransportClient client = new PreBuiltXPackTransportClient(Settings.builder()
.put("cluster.name", "myClusterName")
.put("xpack.security.user", "test_user:changeme")
.put("xpack.security.user", "test_user:x-pack-test-password")
.put("xpack.ssl.certificate_authorities", "/path/to/ca.crt")
.put("xpack.security.transport.ssl.enabled", "true")
...

View File

@ -27,8 +27,8 @@ To use Kibana with {security}:
requests as this user to access the cluster monitoring APIs and the `.kibana` index.
The server does _not_ need access to user indices.
+
By default, the `kibana` user password is set to `changeme`. Change this password
through the reset password API:
By default, the `kibana` does not have a password. The user will not be enabled until
a password is set. Set the password through the reset password API:
+
[source,shell]
--------------------------------------------------------------------------------

View File

@ -61,7 +61,7 @@ the `user` API:
---------------------------------------------------------------
POST _xpack/security/user/logstash_internal
{
"password" : "changeme",
"password" : "x-pack-test-password",
"roles" : [ "logstash_writer"],
"full_name" : "Internal Logstash User"
}
@ -76,18 +76,18 @@ plugins in your Logstash `.conf` file. For example:
input {
...
user => logstash_internal
password => changeme
password => x-pack-test-password
}
filter {
...
user => logstash_internal
password => changeme
password => x-pack-test-password
}
output {
elasticsearch {
...
user => logstash_internal
password => changeme
password => x-pack-test-password
}
--------------------------------------------------
@ -126,7 +126,7 @@ the `user` API:
---------------------------------------------------------------
POST _xpack/security/user/logstash_user
{
"password" : "changeme",
"password" : "x-pack-test-password",
"roles" : [ "logstash_reader"],
"full_name" : "Kibana User"
}
@ -187,8 +187,8 @@ This user has the minimum permissions necessary for the monitoring function, and
_should not_ be used for any other purpose - it is specifically _not intended_ for
use within a Logstash pipeline.
By default, the `logstash_system` user password is set to `changeme`.
Change this password through the reset password API:
By default, the `logstash_system` does not have a password. The user will not be enabled until
a password is set. Set the password through the reset password API:
[source,js]
---------------------------------------------------------------------

View File

@ -152,7 +152,7 @@ for the agent user:
--------------------------------------------------
xpack.monitoring.elasticsearch.url: ["http://es-mon-1:9200", "http://es-mon2:9200"]
xpack.monitoring.elasticsearch.username: "remote_monitor"
xpack.monitoring.elasticsearch.password: "changeme"
xpack.monitoring.elasticsearch.password: "x-pack-test-password"
--------------------------------------------------
.. If SSL/TLS is enabled on the monitoring cluster:
@ -176,6 +176,6 @@ Alternatively, you can configure trusted certificates using a truststore
[source,yaml]
--------------------------------------------------
xpack.monitoring.elasticsearch.ssl.truststore.path: /path/to/file
xpack.monitoring.elasticsearch.ssl.truststore.password: changeme
xpack.monitoring.elasticsearch.ssl.truststore.password: x-pack-test-password
--------------------------------------------------
--

View File

@ -24,7 +24,7 @@ the following request creates a `reporter` user that has the
---------------------------------------------------------------
POST /_xpack/security/user/reporter
{
"password" : "changeme",
"password" : "x-pack-test-password",
"roles" : ["kibana_user", "reporting_user"],
"full_name" : "Reporting User"
}

View File

@ -15,14 +15,6 @@ To use a tribe node with secured clusters:
. Install {xpack} on the tribe node and every node in each connected cluster.
. Enable <<enable-message-authentication, message authentication>> globally.
Generate a system key on one node and copy it to the tribe node and every other
node in each of the connected clusters.
+
IMPORTANT: For message authentication to work properly across multiple clusters,
the tribe node and all of the connected clusters must share the same
system key. {security} reads the system key from `CONFIG_DIR/x-pack/system_key`.
. Enable encryption globally. To encrypt communications, you must enable
<<ssl-tls,enable SSL/TLS>> on every node.
+

View File

@ -21,8 +21,6 @@ Configure in both `elasticsearch.yml` and `kibana.yml`.
==== Default Password Security Settings
`xpack.security.authc.accept_default_password`::
In `elasticsearch.yml`, set this to `false` to disable support for the default "changeme" password.
For more information, see {xpack-ref}/setting-up-authentication.html#disabling-default-password[
Disable Default Password Functionality].
[float]
[[anonymous-access-settings]]

View File

@ -88,7 +88,7 @@ PUT _xpack/watcher/watch/cluster_health_watch
"auth": {
"basic": {
"username": "elastic",
"password": "changeme"
"password": "x-pack-test-password"
}
}
}

View File

@ -33,7 +33,7 @@ output { <2>
elasticsearch {
hosts => "http://localhost:9200"
user => "elastic"
password => "changeme"
password => "x-pack-test-password"
}
}

View File

@ -26,7 +26,7 @@ import static java.util.Collections.singletonMap;
import static org.elasticsearch.xpack.security.authc.support.UsernamePasswordToken.basicAuthHeaderValue;
public class XDocsClientYamlTestSuiteIT extends ESClientYamlSuiteTestCase {
private static final String USER_TOKEN = basicAuthHeaderValue("test_admin", new SecureString("changeme".toCharArray()));
private static final String USER_TOKEN = basicAuthHeaderValue("test_admin", new SecureString("x-pack-test-password".toCharArray()));
public XDocsClientYamlTestSuiteIT(@Name("yaml") ClientYamlTestCandidate testCandidate) {
super(testCandidate);

1
plugin/.gitignore vendored Normal file
View File

@ -0,0 +1 @@
/bin/

View File

@ -98,7 +98,7 @@ if [ -e "$CONF_DIR" ]; then
fi
cd "$ES_HOME" > /dev/null
"$JAVA" $ES_JAVA_OPTS -Des.path.home="$ES_HOME" -cp "$ES_CLASSPATH" org.elasticsearch.xpack.security.crypto.tool.SystemKeyTool $properties "${args[@]}"
"$JAVA" $ES_JAVA_OPTS -Des.path.home="$ES_HOME" -cp "$ES_CLASSPATH" org.elasticsearch.common.settings.EncKeyTool $properties "${args[@]}"
status=$?
cd - > /dev/null
exit $status

View File

@ -5,5 +5,5 @@ rem or more contributor license agreements. Licensed under the Elastic License;
rem you may not use this file except in compliance with the Elastic License.
PUSHD "%~dp0"
CALL "%~dp0.in.bat" org.elasticsearch.xpack.security.crypto.tool.SystemKeyTool %*
CALL "%~dp0.in.bat" org.elasticsearch.common.settings.EncKeyTool %*
POPD

View File

@ -210,13 +210,50 @@ integTestCluster {
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:changeme".getBytes(StandardCharsets.UTF_8)));
Base64.getEncoder().encodeToString("elastic:x-pack-test-password".getBytes(StandardCharsets.UTF_8)));
httpURLConnection.setRequestMethod("GET");
httpURLConnection.connect();
if (httpURLConnection.getResponseCode() == 200) {

View File

@ -97,6 +97,7 @@ import org.elasticsearch.xpack.security.Security;
import org.elasticsearch.xpack.security.SecurityFeatureSet;
import org.elasticsearch.xpack.security.authc.AuthenticationService;
import org.elasticsearch.xpack.security.authc.support.UsernamePasswordToken;
import org.elasticsearch.xpack.security.crypto.CryptoService;
import org.elasticsearch.xpack.sql.plugin.SqlPlugin;
import org.elasticsearch.xpack.ssl.SSLConfigurationReloader;
import org.elasticsearch.xpack.ssl.SSLService;
@ -122,9 +123,12 @@ import java.util.Set;
import java.util.function.Supplier;
import java.util.function.UnaryOperator;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import javax.security.auth.DestroyFailedException;
import static org.elasticsearch.xpack.watcher.Watcher.ENCRYPT_SENSITIVE_DATA_SETTING;
public class XPackPlugin extends Plugin implements ScriptPlugin, ActionPlugin, IngestPlugin, NetworkPlugin {
public static final String NAME = "x-pack";
@ -203,6 +207,7 @@ public class XPackPlugin extends Plugin implements ScriptPlugin, ActionPlugin, I
protected Graph graph;
protected MachineLearning machineLearning;
protected Logstash logstash;
protected CryptoService cryptoService;
protected Deprecation deprecation;
protected Upgrade upgrade;
protected SqlPlugin sql;
@ -232,6 +237,7 @@ public class XPackPlugin extends Plugin implements ScriptPlugin, ActionPlugin, I
} else {
this.extensionsService = null;
}
cryptoService = ENCRYPT_SENSITIVE_DATA_SETTING.get(settings) ? new CryptoService(settings) : null;
}
// For tests only
@ -286,7 +292,7 @@ public class XPackPlugin extends Plugin implements ScriptPlugin, ActionPlugin, I
// watcher http stuff
Map<String, HttpAuthFactory> httpAuthFactories = new HashMap<>();
httpAuthFactories.put(BasicAuth.TYPE, new BasicAuthFactory(security.getCryptoService()));
httpAuthFactories.put(BasicAuth.TYPE, new BasicAuthFactory(cryptoService));
// TODO: add more auth types, or remove this indirection
HttpAuthRegistry httpAuthRegistry = new HttpAuthRegistry(httpAuthFactories);
HttpRequestTemplate.Parser httpTemplateParser = new HttpRequestTemplate.Parser(httpAuthRegistry);
@ -299,7 +305,7 @@ public class XPackPlugin extends Plugin implements ScriptPlugin, ActionPlugin, I
components.addAll(notificationComponents);
components.addAll(watcher.createComponents(getClock(), scriptService, internalClient, licenseState,
httpClient, httpTemplateParser, threadPool, clusterService, security.getCryptoService(), xContentRegistry, components));
httpClient, httpTemplateParser, threadPool, clusterService, cryptoService, xContentRegistry, components));
components.addAll(machineLearning.createComponents(internalClient, clusterService, threadPool, xContentRegistry));
@ -321,7 +327,7 @@ public class XPackPlugin extends Plugin implements ScriptPlugin, ActionPlugin, I
HttpRequestTemplate.Parser httpTemplateParser, ScriptService scriptService,
HttpAuthRegistry httpAuthRegistry) {
List<Object> components = new ArrayList<>();
components.add(new EmailService(settings, security.getCryptoService(), clusterSettings));
components.add(new EmailService(settings, cryptoService, clusterSettings));
components.add(new HipChatService(settings, httpClient, clusterSettings));
components.add(new JiraService(settings, httpClient, clusterSettings));
components.add(new SlackService(settings, httpClient, clusterSettings));
@ -582,7 +588,10 @@ public class XPackPlugin extends Plugin implements ScriptPlugin, ActionPlugin, I
@Override
public List<BootstrapCheck> getBootstrapChecks() {
return security.getBootstrapChecks();
return Collections.unmodifiableList(
Stream.of(security.getBootstrapChecks(), watcher.getBootstrapChecks())
.flatMap(Collection::stream)
.collect(Collectors.toList()));
}
}

View File

@ -12,7 +12,6 @@ import org.elasticsearch.common.Strings;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.common.unit.TimeValue;
import org.elasticsearch.common.xcontent.XContentParser;
import org.elasticsearch.index.query.QueryParseContext;
import org.elasticsearch.rest.RestController;
import org.elasticsearch.rest.RestRequest;
import org.elasticsearch.rest.action.RestToXContentListener;
@ -28,10 +27,10 @@ import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import static org.elasticsearch.index.query.AbstractQueryBuilder.parseInnerQueryBuilder;
import static org.elasticsearch.rest.RestRequest.Method.GET;
import static org.elasticsearch.rest.RestRequest.Method.POST;
import static org.elasticsearch.xpack.graph.action.GraphExploreAction.INSTANCE;
/**
* @see GraphExploreRequest
*/
@ -89,7 +88,6 @@ public class RestGraphAction extends XPackRestHandler {
Hop currentHop = graphRequest.createNextHop(null);
try (XContentParser parser = request.contentOrSourceParamParser()) {
QueryParseContext context = new QueryParseContext(parser);
XContentParser.Token token = parser.nextToken();
@ -97,15 +95,14 @@ public class RestGraphAction extends XPackRestHandler {
throw new ElasticsearchParseException("failed to parse search source. source must be an object, but found [{}] instead",
token.name());
}
parseHop(parser, context, currentHop, graphRequest);
parseHop(parser, currentHop, graphRequest);
}
graphRequest.types(Strings.splitStringByCommaToArray(request.param("type")));
return channel -> client.es().execute(INSTANCE, graphRequest, new RestToXContentListener<>(channel));
}
private void parseHop(XContentParser parser, QueryParseContext context, Hop currentHop,
GraphExploreRequest graphRequest) throws IOException {
private void parseHop(XContentParser parser, Hop currentHop, GraphExploreRequest graphRequest) throws IOException {
String fieldName = null;
XContentParser.Token token;
@ -121,15 +118,15 @@ public class RestGraphAction extends XPackRestHandler {
}
} else if (token == XContentParser.Token.START_OBJECT) {
if (QUERY_FIELD.match(fieldName)) {
currentHop.guidingQuery(context.parseInnerQueryBuilder());
currentHop.guidingQuery(parseInnerQueryBuilder(parser));
} else if (CONNECTIONS_FIELD.match(fieldName)) {
parseHop(parser, context, graphRequest.createNextHop(null), graphRequest);
parseHop(parser, graphRequest.createNextHop(null), graphRequest);
} else if (CONTROLS_FIELD.match(fieldName)) {
if (currentHop.getParentHop() != null) {
throw new ElasticsearchParseException(
"Controls are a global setting that can only be set in the root " + fieldName, token.name());
}
parseControls(parser, context, graphRequest);
parseControls(parser, graphRequest);
} else {
throw new ElasticsearchParseException("Illegal object property in graph definition " + fieldName, token.name());
@ -221,7 +218,7 @@ public class RestGraphAction extends XPackRestHandler {
"Graph vertices definition cannot contain both "+ INCLUDE_FIELD.getPreferredName()+
" and "+EXCLUDE_FIELD.getPreferredName()+" clauses", token.name());
}
excludes = new HashSet<String>();
excludes = new HashSet<>();
while ((token = parser.nextToken()) != XContentParser.Token.END_ARRAY) {
excludes.add(parser.text());
}
@ -274,7 +271,7 @@ public class RestGraphAction extends XPackRestHandler {
}
private void parseControls(XContentParser parser, QueryParseContext context, GraphExploreRequest graphRequest) throws IOException {
private void parseControls(XContentParser parser, GraphExploreRequest graphRequest) throws IOException {
XContentParser.Token token;
String fieldName = null;

View File

@ -18,9 +18,9 @@ import org.elasticsearch.common.xcontent.ObjectParser;
import org.elasticsearch.common.xcontent.ToXContentObject;
import org.elasticsearch.common.xcontent.XContentBuilder;
import org.elasticsearch.common.xcontent.XContentParser;
import org.elasticsearch.index.query.AbstractQueryBuilder;
import org.elasticsearch.index.query.QueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.index.query.QueryParseContext;
import org.elasticsearch.search.aggregations.AggregationBuilder;
import org.elasticsearch.search.aggregations.AggregatorFactories;
import org.elasticsearch.search.aggregations.bucket.histogram.DateHistogramAggregationBuilder;
@ -87,14 +87,14 @@ public class DatafeedConfig extends AbstractDiffable<DatafeedConfig> implements
PARSER.declareString((builder, val) ->
builder.setFrequency(TimeValue.parseTimeValue(val, FREQUENCY.getPreferredName())), FREQUENCY);
PARSER.declareObject(Builder::setQuery,
(p, c) -> new QueryParseContext(p).parseInnerQueryBuilder(), QUERY);
PARSER.declareObject(Builder::setAggregations, (p, c) -> AggregatorFactories.parseAggregators(new QueryParseContext(p)),
(p, c) -> AbstractQueryBuilder.parseInnerQueryBuilder(p), QUERY);
PARSER.declareObject(Builder::setAggregations, (p, c) -> AggregatorFactories.parseAggregators(p),
AGGREGATIONS);
PARSER.declareObject(Builder::setAggregations,(p, c) -> AggregatorFactories.parseAggregators(new QueryParseContext(p)), AGGS);
PARSER.declareObject(Builder::setAggregations,(p, c) -> AggregatorFactories.parseAggregators(p), AGGS);
PARSER.declareObject(Builder::setScriptFields, (p, c) -> {
List<SearchSourceBuilder.ScriptField> parsedScriptFields = new ArrayList<>();
while (p.nextToken() != XContentParser.Token.END_OBJECT) {
parsedScriptFields.add(new SearchSourceBuilder.ScriptField(new QueryParseContext(p)));
parsedScriptFields.add(new SearchSourceBuilder.ScriptField(p));
}
parsedScriptFields.sort(Comparator.comparing(SearchSourceBuilder.ScriptField::fieldName));
return parsedScriptFields;

View File

@ -16,8 +16,8 @@ import org.elasticsearch.common.xcontent.ObjectParser;
import org.elasticsearch.common.xcontent.ToXContentObject;
import org.elasticsearch.common.xcontent.XContentBuilder;
import org.elasticsearch.common.xcontent.XContentParser;
import org.elasticsearch.index.query.AbstractQueryBuilder;
import org.elasticsearch.index.query.QueryBuilder;
import org.elasticsearch.index.query.QueryParseContext;
import org.elasticsearch.search.aggregations.AggregatorFactories;
import org.elasticsearch.search.builder.SearchSourceBuilder;
import org.elasticsearch.xpack.ml.job.config.Job;
@ -49,15 +49,15 @@ public class DatafeedUpdate implements Writeable, ToXContentObject {
PARSER.declareString((builder, val) -> builder.setFrequency(
TimeValue.parseTimeValue(val, DatafeedConfig.FREQUENCY.getPreferredName())), DatafeedConfig.FREQUENCY);
PARSER.declareObject(Builder::setQuery,
(p, c) -> new QueryParseContext(p).parseInnerQueryBuilder(), DatafeedConfig.QUERY);
PARSER.declareObject(Builder::setAggregations, (p, c) -> AggregatorFactories.parseAggregators(new QueryParseContext(p)),
(p, c) -> AbstractQueryBuilder.parseInnerQueryBuilder(p), DatafeedConfig.QUERY);
PARSER.declareObject(Builder::setAggregations, (p, c) -> AggregatorFactories.parseAggregators(p),
DatafeedConfig.AGGREGATIONS);
PARSER.declareObject(Builder::setAggregations,(p, c) -> AggregatorFactories.parseAggregators(new QueryParseContext(p)),
PARSER.declareObject(Builder::setAggregations,(p, c) -> AggregatorFactories.parseAggregators(p),
DatafeedConfig.AGGS);
PARSER.declareObject(Builder::setScriptFields, (p, c) -> {
List<SearchSourceBuilder.ScriptField> parsedScriptFields = new ArrayList<>();
while (p.nextToken() != XContentParser.Token.END_OBJECT) {
parsedScriptFields.add(new SearchSourceBuilder.ScriptField(new QueryParseContext(p)));
parsedScriptFields.add(new SearchSourceBuilder.ScriptField(p));
}
parsedScriptFields.sort(Comparator.comparing(SearchSourceBuilder.ScriptField::fieldName));
return parsedScriptFields;

View File

@ -31,6 +31,16 @@ import java.util.Collections;
*/
public class NodeStatsCollector extends Collector {
private static final CommonStatsFlags FLAGS =
new CommonStatsFlags(CommonStatsFlags.Flag.Docs,
CommonStatsFlags.Flag.FieldData,
CommonStatsFlags.Flag.Store,
CommonStatsFlags.Flag.Indexing,
CommonStatsFlags.Flag.QueryCache,
CommonStatsFlags.Flag.RequestCache,
CommonStatsFlags.Flag.Search,
CommonStatsFlags.Flag.Segments);
private final Client client;
public NodeStatsCollector(Settings settings, ClusterService clusterService,
@ -43,7 +53,7 @@ public class NodeStatsCollector extends Collector {
@Override
protected Collection<MonitoringDoc> doCollect() throws Exception {
NodesStatsRequest request = new NodesStatsRequest("_local");
request.indices(CommonStatsFlags.ALL);
request.indices(FLAGS);
request.os(true);
request.jvm(true);
request.process(true);
@ -67,4 +77,5 @@ public class NodeStatsCollector extends Collector {
return Collections.singletonList(nodeStatsDoc);
}
}

View File

@ -200,7 +200,6 @@ public class Security implements ActionPlugin, IngestPlugin, NetworkPlugin {
private final boolean enabled;
private final boolean transportClientMode;
private final XPackLicenseState licenseState;
private final CryptoService cryptoService;
private final SSLService sslService;
/* what a PITA that we need an extra indirection to initialize this. Yet, once we got rid of guice we can thing about how
* to fix this or make it simpler. Today we need several service that are created in createComponents but we need to register
@ -220,18 +219,11 @@ public class Security implements ActionPlugin, IngestPlugin, NetworkPlugin {
this.enabled = XPackSettings.SECURITY_ENABLED.get(settings);
if (enabled && transportClientMode == false) {
validateAutoCreateIndex(settings);
cryptoService = new CryptoService(settings, env);
} else {
cryptoService = null;
}
this.licenseState = licenseState;
this.sslService = sslService;
}
public CryptoService getCryptoService() {
return cryptoService;
}
public Collection<Module> nodeModules() {
List<Module> modules = new ArrayList<>();
if (enabled == false || transportClientMode) {
@ -254,7 +246,6 @@ public class Security implements ActionPlugin, IngestPlugin, NetworkPlugin {
if (enabled == false) {
modules.add(b -> {
b.bind(CryptoService.class).toProvider(Providers.of(null));
b.bind(Realms.class).toProvider(Providers.of(null)); // for SecurityFeatureSet
b.bind(CompositeRolesStore.class).toProvider(Providers.of(null)); // for SecurityFeatureSet
b.bind(NativeRoleMappingStore.class).toProvider(Providers.of(null)); // for SecurityFeatureSet
@ -268,7 +259,6 @@ public class Security implements ActionPlugin, IngestPlugin, NetworkPlugin {
// which might not be the case during Plugin class instantiation. Once nodeModules are pulled
// everything should have been loaded
modules.add(b -> {
b.bind(CryptoService.class).toInstance(cryptoService);
if (XPackSettings.AUDIT_ENABLED.get(settings)) {
b.bind(AuditTrail.class).to(AuditTrailService.class); // interface used by some actions...
}
@ -474,9 +464,6 @@ public class Security implements ActionPlugin, IngestPlugin, NetworkPlugin {
settingsList.add(TokenService.DELETE_INTERVAL);
settingsList.add(TokenService.DELETE_TIMEOUT);
// encryption settings
CryptoService.addSettings(settingsList);
// hide settings
settingsList.add(Setting.listSetting(setting("hide_settings"), Collections.emptyList(), Function.identity(),
Property.NodeScope, Property.Filtered));

View File

@ -16,6 +16,7 @@ import org.elasticsearch.common.settings.SecureString;
import org.elasticsearch.common.settings.Setting;
import org.elasticsearch.common.settings.Setting.Property;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.common.transport.TransportAddress;
import org.elasticsearch.common.util.concurrent.ThreadContext;
import org.elasticsearch.node.Node;
import org.elasticsearch.rest.RestRequest;
@ -29,6 +30,7 @@ import org.elasticsearch.xpack.security.authc.support.UsernamePasswordToken;
import org.elasticsearch.xpack.security.user.AnonymousUser;
import org.elasticsearch.xpack.security.user.User;
import java.net.InetSocketAddress;
import java.util.List;
import java.util.Map;
import java.util.function.BiConsumer;
@ -132,8 +134,8 @@ public class AuthenticationService extends AbstractComponent {
private final AuditableRequest request;
private final User fallbackUser;
private final ActionListener<Authentication> listener;
private final ActionListener<Authentication> listener;
private RealmRef authenticatedBy = null;
private RealmRef lookedupBy = null;
private AuthenticationToken authenticationToken = null;
@ -279,7 +281,7 @@ public class AuthenticationService extends AbstractComponent {
authenticationToken.principal(), realm.name(), ex);
logger.debug("Authentication failed due to exception", ex);
userListener.onFailure(ex);
}));
}), request);
} else {
userListener.onResponse(null);
}
@ -436,16 +438,21 @@ public class AuthenticationService extends AbstractComponent {
}
}
abstract static class AuditableRequest {
abstract static class AuditableRequest implements IncomingRequest {
final AuditTrail auditTrail;
final AuthenticationFailureHandler failureHandler;
final ThreadContext threadContext;
private final InetSocketAddress remoteAddress;
private final RequestType requestType;
AuditableRequest(AuditTrail auditTrail, AuthenticationFailureHandler failureHandler, ThreadContext threadContext) {
AuditableRequest(AuditTrail auditTrail, AuthenticationFailureHandler failureHandler, ThreadContext threadContext,
RequestType requestType, InetSocketAddress remoteAddress) {
this.auditTrail = auditTrail;
this.failureHandler = failureHandler;
this.threadContext = threadContext;
this.remoteAddress = remoteAddress;
this.requestType = requestType;
}
abstract void realmAuthenticationFailed(AuthenticationToken token, String realm);
@ -461,6 +468,14 @@ public class AuthenticationService extends AbstractComponent {
abstract ElasticsearchSecurityException runAsDenied(User user, AuthenticationToken token);
abstract void authenticationSuccess(String realm, User user);
public InetSocketAddress getRemoteAddress() {
return remoteAddress;
}
public RequestType getType() {
return requestType;
}
}
static class AuditableTransportRequest extends AuditableRequest {
@ -470,7 +485,7 @@ public class AuthenticationService extends AbstractComponent {
AuditableTransportRequest(AuditTrail auditTrail, AuthenticationFailureHandler failureHandler, ThreadContext threadContext,
String action, TransportMessage message) {
super(auditTrail, failureHandler, threadContext);
super(auditTrail, failureHandler, threadContext, getType(message), getRemoteAddress(message));
this.action = action;
this.message = message;
}
@ -523,15 +538,25 @@ public class AuthenticationService extends AbstractComponent {
public String toString() {
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 {
private final RestRequest request;
@SuppressWarnings("unchecked")
AuditableRestRequest(AuditTrail auditTrail, AuthenticationFailureHandler failureHandler, ThreadContext threadContext,
RestRequest request) {
super(auditTrail, failureHandler, threadContext);
super(auditTrail, failureHandler, threadContext, RequestType.REST, (InetSocketAddress) request.getRemoteAddress());
this.request = request;
}

View File

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

View File

@ -81,10 +81,12 @@ public abstract class Realm implements Comparable<Realm> {
* {@link ActionListener#onResponse} with the User associated with the given token. An unsuccessful authentication calls
* with {@code null} on the argument.
*
* The remote address should be null if the request initiated from the local node.
* @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<User> listener);
public abstract void authenticate(AuthenticationToken token, ActionListener<User> listener, IncomingRequest incomingRequest);
/**
* Looks up the user identified the String identifier. A successful lookup will call the {@link ActionListener#onResponse}

View File

@ -7,12 +7,12 @@ package org.elasticsearch.xpack.security.authc.esnative;
import org.elasticsearch.action.ActionListener;
import org.elasticsearch.common.settings.Setting;
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.HashSet;
import java.util.Set;
/**
@ -35,7 +35,7 @@ public class NativeRealm extends CachingUsernamePasswordRealm {
}
@Override
protected void doAuthenticate(UsernamePasswordToken token, ActionListener<User> listener) {
protected void doAuthenticate(UsernamePasswordToken token, ActionListener<User> listener, IncomingRequest incomingRequest) {
userStore.verifyPassword(token.principal(), token.credentials(), listener);
}

View File

@ -210,7 +210,7 @@ public class NativeRealmMigrator implements IndexLifecycleManager.IndexDataMigra
}
try (SecureString secureString = new SecureString(passwordHash.toCharArray())) {
return Hasher.BCRYPT.verify(ReservedRealm.DEFAULT_PASSWORD_TEXT, secureString.getChars());
return Hasher.BCRYPT.verify(ReservedRealm.EMPTY_PASSWORD_TEXT, secureString.getChars());
}
}

View File

@ -548,7 +548,7 @@ public class NativeUsersStore extends AbstractComponent {
} else if (password.isEmpty() && containerSettings.inContainer() && username.equals(ElasticUser.NAME)) {
listener.onResponse(new ReservedUserInfo(containerSettings.getPasswordHash(), enabled, false));
} else if (password.isEmpty()) {
listener.onResponse(new ReservedUserInfo(ReservedRealm.DEFAULT_PASSWORD_HASH, enabled, true));
listener.onResponse(new ReservedUserInfo(ReservedRealm.EMPTY_PASSWORD_HASH, enabled, true));
} else {
listener.onResponse(new ReservedUserInfo(password.toCharArray(), enabled, false));
}
@ -607,7 +607,7 @@ public class NativeUsersStore extends AbstractComponent {
char[] passwordHash = containerSettings.getPasswordHash();
userInfos.put(searchHit.getId(), new ReservedUserInfo(passwordHash, enabled, false));
} else if (password.isEmpty()) {
userInfos.put(username, new ReservedUserInfo(ReservedRealm.DEFAULT_PASSWORD_HASH, enabled, true));
userInfos.put(username, new ReservedUserInfo(ReservedRealm.EMPTY_PASSWORD_HASH, enabled, true));
} else {
userInfos.put(username, new ReservedUserInfo(password.toCharArray(), enabled, false));
}
@ -694,12 +694,12 @@ public class NativeUsersStore extends AbstractComponent {
public final char[] passwordHash;
public final boolean enabled;
public final boolean hasDefaultPassword;
public final boolean hasEmptyPassword;
ReservedUserInfo(char[] passwordHash, boolean enabled, boolean hasDefaultPassword) {
ReservedUserInfo(char[] passwordHash, boolean enabled, boolean hasEmptyPassword) {
this.passwordHash = passwordHash;
this.enabled = enabled;
this.hasDefaultPassword = hasDefaultPassword;
this.hasEmptyPassword = hasEmptyPassword;
}
}
}

View File

@ -17,6 +17,7 @@ import org.elasticsearch.env.Environment;
import org.elasticsearch.xpack.XPackSettings;
import org.elasticsearch.xpack.security.Security;
import org.elasticsearch.xpack.security.SecurityLifecycleService;
import org.elasticsearch.xpack.security.authc.IncomingRequest;
import org.elasticsearch.xpack.security.authc.RealmConfig;
import org.elasticsearch.xpack.security.authc.esnative.NativeUsersStore.ReservedUserInfo;
import org.elasticsearch.xpack.security.authc.support.CachingUsernamePasswordRealm;
@ -30,6 +31,9 @@ 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;
@ -44,20 +48,20 @@ public class ReservedRealm extends CachingUsernamePasswordRealm {
public static final String TYPE = "reserved";
public static final SecureString DEFAULT_PASSWORD_TEXT = new SecureString("changeme".toCharArray());
static final char[] DEFAULT_PASSWORD_HASH = Hasher.BCRYPT.hash(DEFAULT_PASSWORD_TEXT);
public static final SecureString EMPTY_PASSWORD_TEXT = new SecureString("".toCharArray());
static final char[] EMPTY_PASSWORD_HASH = Hasher.BCRYPT.hash(EMPTY_PASSWORD_TEXT);
private static final ReservedUserInfo DEFAULT_USER_INFO = new ReservedUserInfo(DEFAULT_PASSWORD_HASH, true, true);
private static final ReservedUserInfo DISABLED_USER_INFO = new ReservedUserInfo(DEFAULT_PASSWORD_HASH, false, true);
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);
public static final Setting<Boolean> ACCEPT_DEFAULT_PASSWORD_SETTING = Setting.boolSetting(
Security.setting("authc.accept_default_password"), true, Setting.Property.NodeScope, Setting.Property.Filtered);
Security.setting("authc.accept_default_password"), true, Setting.Property.NodeScope, Setting.Property.Filtered,
Setting.Property.Deprecated);
private final NativeUsersStore nativeUsersStore;
private final AnonymousUser anonymousUser;
private final boolean realmEnabled;
private final boolean anonymousEnabled;
private final boolean defaultPasswordEnabled;
private final SecurityLifecycleService securityLifecycleService;
public ReservedRealm(Environment env, Settings settings, NativeUsersStore nativeUsersStore, AnonymousUser anonymousUser,
@ -67,12 +71,28 @@ public class ReservedRealm extends CachingUsernamePasswordRealm {
this.realmEnabled = XPackSettings.RESERVED_REALM_ENABLED_SETTING.get(settings);
this.anonymousUser = anonymousUser;
this.anonymousEnabled = AnonymousUser.isAnonymousEnabled(settings);
this.defaultPasswordEnabled = ACCEPT_DEFAULT_PASSWORD_SETTING.get(settings);
this.securityLifecycleService = securityLifecycleService;
}
@Override
protected void doAuthenticate(UsernamePasswordToken token, ActionListener<User> listener) {
protected void doAuthenticate(UsernamePasswordToken token, ActionListener<User> 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<User> listener, boolean acceptEmptyPassword) {
if (realmEnabled == false) {
listener.onResponse(null);
} else if (isReserved(token.principal(), config.globalSettings()) == false) {
@ -82,7 +102,10 @@ public class ReservedRealm extends CachingUsernamePasswordRealm {
Runnable action;
if (userInfo != null) {
try {
if (verifyPassword(userInfo, token)) {
if (userInfo.hasEmptyPassword && isSetupMode(token.principal(), acceptEmptyPassword) == false) {
action = () -> listener.onFailure(Exceptions.authenticationError("failed to authenticate user [{}]",
token.principal()));
} else if (verifyPassword(userInfo, token)) {
final User user = getUser(token.principal(), userInfo);
action = () -> listener.onResponse(user);
} else {
@ -90,7 +113,7 @@ public class ReservedRealm extends CachingUsernamePasswordRealm {
token.principal()));
}
} finally {
if (userInfo.passwordHash != DEFAULT_PASSWORD_HASH) {
if (userInfo.passwordHash != EMPTY_PASSWORD_HASH) {
Arrays.fill(userInfo.passwordHash, (char) 0);
}
}
@ -104,11 +127,12 @@ 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)) {
if (userInfo.hasDefaultPassword && this.defaultPasswordEnabled == false) {
return false;
}
return true;
}
return false;
@ -154,7 +178,7 @@ public class ReservedRealm extends CachingUsernamePasswordRealm {
assert username != null;
switch (username) {
case ElasticUser.NAME:
return new ElasticUser(userInfo.enabled);
return new ElasticUser(userInfo.enabled, userInfo.hasEmptyPassword);
case KibanaUser.NAME:
return new KibanaUser(userInfo.enabled);
case LogstashSystemUser.NAME:
@ -178,7 +202,8 @@ 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));
users.add(new ElasticUser(userInfo == null || userInfo.enabled,
userInfo == null || userInfo.hasEmptyPassword));
userInfo = reservedUserInfos.get(KibanaUser.NAME);
users.add(new KibanaUser(userInfo == null || userInfo.enabled));

View File

@ -157,7 +157,7 @@ public class SetupPasswordTool extends MultiCommand {
private OptionSpec<String> noPromptOption;
private String elasticUser = ElasticUser.NAME;
private SecureString elasticUserPassword = ReservedRealm.DEFAULT_PASSWORD_TEXT;
private SecureString elasticUserPassword = ReservedRealm.EMPTY_PASSWORD_TEXT;
private String url;
SetupCommand(String description) {

View File

@ -11,6 +11,7 @@ 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.IncomingRequest;
import org.elasticsearch.xpack.security.authc.RealmConfig;
import org.elasticsearch.xpack.security.authc.support.CachingUsernamePasswordRealm;
import org.elasticsearch.xpack.security.authc.support.UsernamePasswordToken;
@ -37,7 +38,7 @@ public class FileRealm extends CachingUsernamePasswordRealm {
}
@Override
protected void doAuthenticate(UsernamePasswordToken token, ActionListener<User> listener) {
protected void doAuthenticate(UsernamePasswordToken token, ActionListener<User> listener, IncomingRequest incomingRequest) {
if (userPasswdStore.verifyPassword(token.principal(), token.credentials())) {
String[] roles = userRolesStore.roles(token.principal());
listener.onResponse(new User(token.principal(), roles));

View File

@ -19,7 +19,6 @@ import org.apache.lucene.util.IOUtils;
import org.elasticsearch.ElasticsearchTimeoutException;
import org.elasticsearch.action.ActionListener;
import org.elasticsearch.action.support.ContextPreservingActionListener;
import org.elasticsearch.common.Strings;
import org.elasticsearch.common.collect.MapBuilder;
import org.elasticsearch.common.settings.Setting;
import org.elasticsearch.common.settings.Setting.Property;
@ -29,6 +28,7 @@ import org.elasticsearch.common.util.concurrent.ThreadContext;
import org.elasticsearch.threadpool.ThreadPool;
import org.elasticsearch.threadpool.ThreadPool.Names;
import org.elasticsearch.watcher.ResourceWatcherService;
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;
@ -142,7 +142,7 @@ public final class LdapRealm extends CachingUsernamePasswordRealm {
* This user will then be passed to the listener
*/
@Override
protected void doAuthenticate(UsernamePasswordToken token, ActionListener<User> listener) {
protected void doAuthenticate(UsernamePasswordToken token, ActionListener<User> listener, IncomingRequest incomingRequest) {
// we submit to the threadpool because authentication using LDAP will execute blocking I/O for a bind request and we don't want
// network threads stuck waiting for a socket to connect. After the bind, then all interaction with LDAP should be async
final CancellableLdapRunnable cancellableLdapRunnable = new CancellableLdapRunnable(listener,

View File

@ -17,6 +17,7 @@ import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.common.util.concurrent.ThreadContext;
import org.elasticsearch.env.Environment;
import org.elasticsearch.watcher.ResourceWatcherService;
import org.elasticsearch.xpack.security.authc.IncomingRequest;
import org.elasticsearch.xpack.security.authc.support.UserRoleMapper;
import org.elasticsearch.xpack.security.authc.support.mapper.CompositeRoleMapper;
import org.elasticsearch.xpack.security.authc.support.mapper.NativeRoleMappingStore;
@ -40,9 +41,6 @@ import java.util.Set;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import static org.elasticsearch.xpack.XPackSettings.HTTP_SSL_ENABLED;
import static org.elasticsearch.xpack.security.Security.setting;
public class PkiRealm extends Realm {
public static final String PKI_CERT_HEADER_NAME = "__SECURITY_CLIENT_CERTIFICATE";
@ -84,7 +82,7 @@ public class PkiRealm extends Realm {
}
@Override
public void authenticate(AuthenticationToken authToken, ActionListener<User> listener) {
public void authenticate(AuthenticationToken authToken, ActionListener<User> listener, IncomingRequest incomingRequest) {
X509AuthenticationToken token = (X509AuthenticationToken)authToken;
if (isCertificateChainTrusted(trustManager, token, logger) == false) {
listener.onResponse(null);

View File

@ -12,6 +12,7 @@ import org.elasticsearch.common.settings.SecureString;
import org.elasticsearch.common.settings.Setting;
import org.elasticsearch.common.unit.TimeValue;
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;
@ -67,17 +68,18 @@ public abstract class CachingUsernamePasswordRealm extends UsernamePasswordRealm
* If the user exists in the cache (keyed by the principle name), then the password is validated
* against a hash also stored in the cache. Otherwise the subclass authenticates the user via
* 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<User> listener) {
UsernamePasswordToken token = (UsernamePasswordToken)authToken;
public final void authenticate(AuthenticationToken authToken, ActionListener<User> listener, IncomingRequest incomingRequest) {
UsernamePasswordToken token = (UsernamePasswordToken) authToken;
try {
if (cache == null) {
doAuthenticate(token, listener);
doAuthenticate(token, listener, incomingRequest);
} else {
authenticateWithCache(token, listener);
authenticateWithCache(token, listener, incomingRequest);
}
} catch (Exception e) {
// each realm should handle exceptions, if we get one here it should be considered fatal
@ -85,7 +87,7 @@ public abstract class CachingUsernamePasswordRealm extends UsernamePasswordRealm
}
}
private void authenticateWithCache(UsernamePasswordToken token, ActionListener<User> listener) {
private void authenticateWithCache(UsernamePasswordToken token, ActionListener<User> listener, IncomingRequest incomingRequest) {
UserWithHash userWithHash = cache.get(token.principal());
if (userWithHash == null) {
if (logger.isDebugEnabled()) {
@ -97,7 +99,7 @@ public abstract class CachingUsernamePasswordRealm extends UsernamePasswordRealm
logger.debug("realm [{}] authenticated user [{}], with roles [{}]", name(), token.principal(), user.roles());
}
listener.onResponse(user);
}, listener::onFailure));
}, listener::onFailure), incomingRequest);
} else if (userWithHash.hasHash()) {
if (userWithHash.verify(token.credentials())) {
if (userWithHash.user.enabled()) {
@ -114,7 +116,7 @@ public abstract class CachingUsernamePasswordRealm extends UsernamePasswordRealm
user.enabled(), user.roles());
}
listener.onResponse(user);
}, listener::onFailure));
}, listener::onFailure), incomingRequest);
}
} else {
cache.invalidate(token.principal());
@ -124,7 +126,7 @@ public abstract class CachingUsernamePasswordRealm extends UsernamePasswordRealm
name(), token.principal(), user.roles());
}
listener.onResponse(user);
}, listener::onFailure));
}, listener::onFailure), incomingRequest);
}
} else {
cache.invalidate(token.principal());
@ -134,12 +136,12 @@ public abstract class CachingUsernamePasswordRealm extends UsernamePasswordRealm
"realm [{}] authenticated user [{}] with roles [{}]", name(), token.principal(), user.roles());
}
listener.onResponse(user);
}, listener::onFailure));
}, listener::onFailure), incomingRequest);
}
}
private void doAuthenticateAndCache(UsernamePasswordToken token, ActionListener<User> listener) {
doAuthenticate(token, ActionListener.wrap((user) -> {
private void doAuthenticateAndCache(UsernamePasswordToken token, ActionListener<User> listener, IncomingRequest incomingRequest) {
ActionListener<User> wrapped = ActionListener.wrap((user) -> {
if (user == null) {
listener.onResponse(null);
} else {
@ -148,7 +150,9 @@ public abstract class CachingUsernamePasswordRealm extends UsernamePasswordRealm
cache.put(token.principal(), userWithHash);
listener.onResponse(user);
}
}, listener::onFailure));
}, listener::onFailure);
doAuthenticate(token, wrapped, incomingRequest);
}
@Override
@ -158,7 +162,7 @@ public abstract class CachingUsernamePasswordRealm extends UsernamePasswordRealm
return stats;
}
protected abstract void doAuthenticate(UsernamePasswordToken token, ActionListener<User> listener);
protected abstract void doAuthenticate(UsernamePasswordToken token, ActionListener<User> listener, IncomingRequest incomingRequest);
@Override
public final void lookupUser(String username, ActionListener<User> listener) {

View File

@ -9,6 +9,7 @@ import org.elasticsearch.ElasticsearchSecurityException;
import org.elasticsearch.action.ActionListener;
import org.elasticsearch.action.CompositeIndicesRequest;
import org.elasticsearch.action.IndicesRequest;
import org.elasticsearch.action.admin.cluster.health.ClusterHealthAction;
import org.elasticsearch.action.admin.indices.alias.Alias;
import org.elasticsearch.action.admin.indices.alias.IndicesAliasesRequest;
import org.elasticsearch.action.admin.indices.create.CreateIndexRequest;
@ -54,6 +55,7 @@ import org.elasticsearch.xpack.security.authz.store.CompositeRolesStore;
import org.elasticsearch.xpack.security.authz.store.ReservedRolesStore;
import org.elasticsearch.xpack.security.support.Automatons;
import org.elasticsearch.xpack.security.user.AnonymousUser;
import org.elasticsearch.xpack.security.user.ElasticUser;
import org.elasticsearch.xpack.security.user.SystemUser;
import org.elasticsearch.xpack.security.user.User;
import org.elasticsearch.xpack.security.user.XPackUser;
@ -150,6 +152,12 @@ public class AuthorizationService extends AbstractComponent {
throw denial(authentication, action, request);
}
// 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) {
throw denial(authentication, action, request);
}
// get the roles of the authenticated user, which may be different than the effective
Role permission = userRole;

View File

@ -134,7 +134,7 @@ public class SecurityIndexSearcherWrapper extends IndexSearcherWrapper {
String templateResult = evaluateTemplate(bytesReference.utf8ToString());
try (XContentParser parser = XContentFactory.xContent(templateResult)
.createParser(queryShardContext.getXContentRegistry(), templateResult)) {
QueryBuilder queryBuilder = queryShardContext.newParseContext(parser).parseInnerQueryBuilder();
QueryBuilder queryBuilder = queryShardContext.parseInnerQueryBuilder(parser);
verifyRoleQuery(queryBuilder);
failIfQueryUsesClient(scriptService, queryBuilder, queryShardContext);
ParsedQuery parsedQuery = queryShardContext.toFilter(queryBuilder);

View File

@ -12,10 +12,8 @@ import javax.crypto.KeyGenerator;
import javax.crypto.SecretKey;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.io.InputStream;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
@ -25,12 +23,12 @@ import java.util.List;
import org.elasticsearch.ElasticsearchException;
import org.elasticsearch.common.component.AbstractComponent;
import org.elasticsearch.common.io.Streams;
import org.elasticsearch.common.settings.Setting;
import org.elasticsearch.common.settings.Setting.Property;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.env.Environment;
import org.elasticsearch.xpack.XPackPlugin;
import org.elasticsearch.xpack.security.authc.support.CharArrays;
import org.elasticsearch.xpack.watcher.Watcher;
import static org.elasticsearch.xpack.security.Security.setting;
@ -42,14 +40,19 @@ public class CryptoService extends AbstractComponent {
public static final String KEY_ALGO = "HmacSHA512";
public static final int KEY_SIZE = 1024;
static final String FILE_NAME = "system_key";
static final String DEFAULT_ENCRYPTION_ALGORITHM = "AES/CTR/NoPadding";
static final String DEFAULT_KEY_ALGORITH = "AES";
static final String ENCRYPTED_TEXT_PREFIX = "::es_encrypted::";
static final int DEFAULT_KEY_LENGTH = 128;
private static final Setting<Boolean> SYSTEM_KEY_REQUIRED_SETTING =
Setting.boolSetting(setting("system_key.required"), false, Property.NodeScope);
// the encryption used in this class was picked when Java 7 was still the min. supported
// version. The use of counter mode was chosen to simplify the need to deal with padding
// and for its speed. 128 bit key length is chosen due to the JCE policy that ships by
// default with the Oracle JDK.
// TODO: with better support in Java 8, we should consider moving to use AES GCM as it
// also provides authentication of the encrypted data, which is something that we are
// missing here.
private static final String DEFAULT_ENCRYPTION_ALGORITHM = "AES/CTR/NoPadding";
private static final String DEFAULT_KEY_ALGORITH = "AES";
private static final int DEFAULT_KEY_LENGTH = 128;
private static final Setting<String> ENCRYPTION_ALGO_SETTING =
new Setting<>(setting("encryption.algorithm"), s -> DEFAULT_ENCRYPTION_ALGORITHM, s -> s, Property.NodeScope);
private static final Setting<Integer> ENCRYPTION_KEY_LENGTH_SETTING =
@ -65,7 +68,7 @@ public class CryptoService extends AbstractComponent {
*/
private final SecretKey encryptionKey;
public CryptoService(Settings settings, Environment env) throws IOException {
public CryptoService(Settings settings) throws IOException {
super(settings);
this.encryptionAlgorithm = ENCRYPTION_ALGO_SETTING.get(settings);
final int keyLength = ENCRYPTION_KEY_LENGTH_SETTING.get(settings);
@ -76,17 +79,13 @@ public class CryptoService extends AbstractComponent {
throw new IllegalArgumentException("invalid key length [" + keyLength + "]. value must be a multiple of 8");
}
Path keyFile = resolveSystemKey(env);
SecretKey systemKey = readSystemKey(keyFile, SYSTEM_KEY_REQUIRED_SETTING.get(settings));
SecretKey systemKey = readSystemKey(Watcher.ENCRYPTION_KEY_SETTING.get(settings));
try {
encryptionKey = encryptionKey(systemKey, keyLength, keyAlgorithm);
} catch (NoSuchAlgorithmException nsae) {
throw new ElasticsearchException("failed to start crypto service. could not load encryption key", nsae);
}
if (systemKey != null) {
logger.info("system key [{}] has been loaded", keyFile.toAbsolutePath());
}
assert encryptionKey != null : "the encryption key should never be null";
}
public static byte[] generateKey() {
@ -103,21 +102,14 @@ public class CryptoService extends AbstractComponent {
}
}
public static Path resolveSystemKey(Environment env) {
return XPackPlugin.resolveConfigFile(env, FILE_NAME);
}
private static SecretKey readSystemKey(Path file, boolean required) throws IOException {
if (Files.exists(file)) {
byte[] bytes = Files.readAllBytes(file);
return new SecretKeySpec(bytes, KEY_ALGO);
private static SecretKey readSystemKey(InputStream in) throws IOException {
final int keySizeBytes = KEY_SIZE / 8;
final byte[] keyBytes = new byte[keySizeBytes];
final int read = Streams.readFully(in, keyBytes);
if (read != keySizeBytes) {
throw new IllegalArgumentException("key size did not match expected value; was the key generated with syskeygen?");
}
if (required) {
throw new FileNotFoundException("[" + file + "] must be present with a valid key");
}
return null;
return new SecretKeySpec(keyBytes, KEY_ALGO);
}
/**
@ -126,15 +118,8 @@ public class CryptoService extends AbstractComponent {
* @return character array representing the encrypted data
*/
public char[] encrypt(char[] chars) {
SecretKey key = this.encryptionKey;
if (key == null) {
logger.warn("encrypt called without a key, returning plain text. run syskeygen and copy same key to all nodes to enable " +
"encryption");
return chars;
}
byte[] charBytes = CharArrays.toUtf8Bytes(chars);
String base64 = Base64.getEncoder().encodeToString(encryptInternal(charBytes, key));
String base64 = Base64.getEncoder().encodeToString(encryptInternal(charBytes, encryptionKey));
return ENCRYPTED_TEXT_PREFIX.concat(base64).toCharArray();
}
@ -144,10 +129,6 @@ public class CryptoService extends AbstractComponent {
* @return plaintext chars
*/
public char[] decrypt(char[] chars) {
if (encryptionKey == null) {
return chars;
}
if (!isEncrypted(chars)) {
// Not encrypted
return chars;
@ -170,18 +151,10 @@ public class CryptoService extends AbstractComponent {
* @param chars the chars to check if they are encrypted
* @return true is data is encrypted
*/
public boolean isEncrypted(char[] chars) {
protected boolean isEncrypted(char[] chars) {
return CharArrays.charsBeginsWith(ENCRYPTED_TEXT_PREFIX, chars);
}
/**
* Flag for callers to determine if values will actually be encrypted or returned plaintext
* @return true if values will be encrypted
*/
public boolean isEncryptionEnabled() {
return this.encryptionKey != null;
}
private byte[] encryptInternal(byte[] bytes, SecretKey key) {
byte[] iv = new byte[ivLength];
secureRandom.nextBytes(iv);
@ -217,7 +190,7 @@ public class CryptoService extends AbstractComponent {
}
static Cipher cipher(int mode, String encryptionAlgorithm, SecretKey key, byte[] initializationVector) {
private static Cipher cipher(int mode, String encryptionAlgorithm, SecretKey key, byte[] initializationVector) {
try {
Cipher cipher = Cipher.getInstance(encryptionAlgorithm);
cipher.init(mode, key, new IvParameterSpec(initializationVector));
@ -227,11 +200,7 @@ public class CryptoService extends AbstractComponent {
}
}
static SecretKey encryptionKey(SecretKey systemKey, int keyLength, String algorithm) throws NoSuchAlgorithmException {
if (systemKey == null) {
return null;
}
private static SecretKey encryptionKey(SecretKey systemKey, int keyLength, String algorithm) throws NoSuchAlgorithmException {
byte[] bytes = systemKey.getEncoded();
if ((bytes.length * 8) < keyLength) {
throw new IllegalArgumentException("at least " + keyLength + " bits should be provided as key data");
@ -253,6 +222,5 @@ public class CryptoService extends AbstractComponent {
settings.add(ENCRYPTION_KEY_LENGTH_SETTING);
settings.add(ENCRYPTION_KEY_ALGO_SETTING);
settings.add(ENCRYPTION_ALGO_SETTING);
settings.add(SYSTEM_KEY_REQUIRED_SETTING);
}
}

View File

@ -15,6 +15,7 @@ import org.elasticsearch.common.SuppressForbidden;
import org.elasticsearch.common.io.PathUtils;
import org.elasticsearch.common.util.set.Sets;
import org.elasticsearch.env.Environment;
import org.elasticsearch.xpack.XPackPlugin;
import org.elasticsearch.xpack.security.crypto.CryptoService;
import java.nio.file.Files;
@ -61,7 +62,7 @@ public class SystemKeyTool extends EnvironmentAwareCommand {
}
keyPath = parsePath(args.get(0));
} else {
keyPath = CryptoService.resolveSystemKey(env);
keyPath = env.configFile().resolve(XPackPlugin.NAME).resolve("system_key");
}
// write the key
@ -75,7 +76,7 @@ public class SystemKeyTool extends EnvironmentAwareCommand {
if (view != null) {
view.setPermissions(PERMISSION_OWNER_READ_WRITE);
terminal.println("Ensure the generated key can be read by the user that Elasticsearch runs as, "
+ "permissions are set to owner read/write only");
+ "permissions are set to owner read/write only");
}
}
@ -84,4 +85,4 @@ public class SystemKeyTool extends EnvironmentAwareCommand {
return PathUtils.get(path);
}
}
}

View File

@ -17,6 +17,7 @@ import org.elasticsearch.common.util.concurrent.ThreadContext;
import org.elasticsearch.license.XPackLicenseState;
import org.elasticsearch.tasks.Task;
import org.elasticsearch.threadpool.ThreadPool;
import org.elasticsearch.transport.TcpTransport;
import org.elasticsearch.transport.Transport;
import org.elasticsearch.transport.TransportChannel;
import org.elasticsearch.transport.TransportException;
@ -28,7 +29,6 @@ import org.elasticsearch.transport.TransportResponse;
import org.elasticsearch.transport.TransportResponseHandler;
import org.elasticsearch.transport.TransportService;
import org.elasticsearch.transport.TransportService.ContextRestoreResponseHandler;
import org.elasticsearch.transport.TransportSettings;
import org.elasticsearch.xpack.XPackSettings;
import org.elasticsearch.xpack.security.SecurityContext;
import org.elasticsearch.xpack.security.authc.AuthenticationService;
@ -168,9 +168,9 @@ public class SecurityServerTransportInterceptor extends AbstractComponent implem
}
}
if (!profileFilters.containsKey(TransportSettings.DEFAULT_PROFILE)) {
if (!profileFilters.containsKey(TcpTransport.DEFAULT_PROFILE)) {
final boolean extractClientCert = sslService.isSSLClientAuthEnabled(transportSSLSettings);
profileFilters.put(TransportSettings.DEFAULT_PROFILE, new ServerTransportFilter.NodeProfile(authcService, authzService,
profileFilters.put(TcpTransport.DEFAULT_PROFILE, new ServerTransportFilter.NodeProfile(authcService, authzService,
threadPool.getThreadContext(), extractClientCert, destructiveOperations, reservedRealmEnabled, securityContext));
}

View File

@ -18,7 +18,7 @@ import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.common.transport.BoundTransportAddress;
import org.elasticsearch.common.transport.TransportAddress;
import org.elasticsearch.license.XPackLicenseState;
import org.elasticsearch.transport.TransportSettings;
import org.elasticsearch.transport.TcpTransport;
import org.elasticsearch.xpack.security.audit.AuditTrailService;
import java.net.InetSocketAddress;
@ -118,7 +118,7 @@ public class IPFilter {
isHttpFilterEnabled = IP_FILTER_ENABLED_HTTP_SETTING.get(settings);
isIpFilterEnabled = IP_FILTER_ENABLED_SETTING.get(settings);
this.transportGroups = TransportSettings.TRANSPORT_PROFILES_SETTING.get(settings).getAsGroups(); // this is pretty crazy that we
this.transportGroups = TcpTransport.TRANSPORT_PROFILES_SETTING.get(settings).getAsGroups(); // this is pretty crazy that we
// allow this to be updateable!!! - we have to fix this very soon
clusterSettings.addSettingsUpdateConsumer(IP_FILTER_ENABLED_HTTP_SETTING, this::setHttpFiltering);
clusterSettings.addSettingsUpdateConsumer(IP_FILTER_ENABLED_SETTING, this::setTransportFiltering);
@ -126,7 +126,7 @@ public class IPFilter {
clusterSettings.addSettingsUpdateConsumer(TRANSPORT_FILTER_DENY_SETTING, this::setTransportDenyFilter);
clusterSettings.addSettingsUpdateConsumer(HTTP_FILTER_ALLOW_SETTING, this::setHttpAllowFilter);
clusterSettings.addSettingsUpdateConsumer(HTTP_FILTER_DENY_SETTING, this::setHttpDenyFilter);
clusterSettings.addSettingsUpdateConsumer(TransportSettings.TRANSPORT_PROFILES_SETTING, this::setTransportProfiles);
clusterSettings.addSettingsUpdateConsumer(TcpTransport.TRANSPORT_PROFILES_SETTING, this::setTransportProfiles);
updateRules();
}

View File

@ -19,7 +19,7 @@ import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.common.util.BigArrays;
import org.elasticsearch.indices.breaker.CircuitBreakerService;
import org.elasticsearch.threadpool.ThreadPool;
import org.elasticsearch.transport.TransportSettings;
import org.elasticsearch.transport.TcpTransport;
import org.elasticsearch.transport.netty4.Netty4Transport;
import org.elasticsearch.xpack.ssl.SSLConfiguration;
import org.elasticsearch.xpack.ssl.SSLService;
@ -65,8 +65,8 @@ public class SecurityNetty4Transport extends Netty4Transport {
profileConfiguration.put(entry.getKey(), configuration);
}
if (profileConfiguration.containsKey(TransportSettings.DEFAULT_PROFILE) == false) {
profileConfiguration.put(TransportSettings.DEFAULT_PROFILE, sslConfiguration);
if (profileConfiguration.containsKey(TcpTransport.DEFAULT_PROFILE) == false) {
profileConfiguration.put(TcpTransport.DEFAULT_PROFILE, sslConfiguration);
}

View File

@ -7,6 +7,9 @@ package org.elasticsearch.xpack.security.user;
import org.elasticsearch.xpack.security.support.MetadataUtils;
import java.util.HashMap;
import java.util.Map;
/**
* The reserved {@code elastic} superuser. Has full permission/access to the cluster/indices and can
* run as any other user.
@ -15,8 +18,27 @@ 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) {
super(NAME, new String[] { ROLE_NAME }, null, null, MetadataUtils.DEFAULT_RESERVED_METADATA, 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;
}
}
}

View File

@ -16,7 +16,7 @@ import org.elasticsearch.common.Strings;
import org.elasticsearch.common.component.AbstractComponent;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.env.Environment;
import org.elasticsearch.transport.TransportSettings;
import org.elasticsearch.transport.TcpTransport;
import org.elasticsearch.xpack.XPackSettings;
import org.elasticsearch.xpack.common.socket.SocketAccess;
import org.elasticsearch.xpack.security.Security;
@ -852,7 +852,7 @@ public class SSLService extends AbstractComponent {
private static List<Settings> getTransportProfileSSLSettings(Settings settings) {
List<Settings> sslSettings = new ArrayList<>();
Map<String, Settings> profiles = TransportSettings.TRANSPORT_PROFILES_SETTING.get(settings).getAsGroups(true);
Map<String, Settings> profiles = TcpTransport.TRANSPORT_PROFILES_SETTING.get(settings).getAsGroups(true);
for (Entry<String, Settings> entry : profiles.entrySet()) {
Settings profileSettings = entry.getValue().getByPrefix("xpack.security.ssl.");
if (profileSettings.isEmpty() == false) {

View File

@ -0,0 +1,54 @@
/*
* 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.watcher;
import org.elasticsearch.bootstrap.BootstrapCheck;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.env.Environment;
import org.elasticsearch.xpack.XPackPlugin;
import java.nio.file.Files;
import java.nio.file.Path;
final class EncryptSensitiveDataBootstrapCheck implements BootstrapCheck {
private final Settings settings;
private final Environment environment;
EncryptSensitiveDataBootstrapCheck(Settings settings, Environment environment) {
this.settings = settings;
this.environment = environment;
}
@Override
public boolean check() {
return Watcher.ENCRYPT_SENSITIVE_DATA_SETTING.get(settings) && Watcher.ENCRYPTION_KEY_SETTING.exists(settings) == false;
}
@Override
public String errorMessage() {
final Path sysKeyPath = environment.configFile().resolve(XPackPlugin.NAME).resolve("system_key").toAbsolutePath();
if (Files.exists(sysKeyPath)) {
return "Encryption of sensitive data requires the key to be placed in the secure setting store. Run " +
"'bin/elasticsearch-keystore add-file " + Watcher.ENCRYPTION_KEY_SETTING.getKey() + " " +
environment.configFile().resolve(XPackPlugin.NAME).resolve("system_key").toAbsolutePath() +
"' to import the file.\nAfter importing, the system_key file should be removed from the " +
"filesystem.\nRepeat this on every node in the cluster.";
} else {
return "Encryption of sensitive data requires a key to be placed in the secure setting store. First run the " +
"bin/x-pack/syskeygen tool to generate a key file.\nThen run 'bin/elasticsearch-keystore add-file " +
Watcher.ENCRYPTION_KEY_SETTING.getKey() + " " +
environment.configFile().resolve(XPackPlugin.NAME).resolve("system_key").toAbsolutePath() + "' to import the key into" +
" the secure setting store. Finally, remove the system_key file from the filesystem.\n" +
"Repeat this on every node in the cluster";
}
}
@Override
public boolean alwaysEnforce() {
return true;
}
}

View File

@ -8,6 +8,7 @@ package org.elasticsearch.xpack.watcher;
import org.apache.logging.log4j.Logger;
import org.elasticsearch.action.ActionRequest;
import org.elasticsearch.action.ActionResponse;
import org.elasticsearch.bootstrap.BootstrapCheck;
import org.elasticsearch.cluster.NamedDiff;
import org.elasticsearch.cluster.metadata.IndexNameExpressionResolver;
import org.elasticsearch.cluster.metadata.IndexTemplateMetaData;
@ -25,12 +26,14 @@ import org.elasticsearch.common.logging.Loggers;
import org.elasticsearch.common.regex.Regex;
import org.elasticsearch.common.settings.ClusterSettings;
import org.elasticsearch.common.settings.IndexScopedSettings;
import org.elasticsearch.common.settings.SecureSetting;
import org.elasticsearch.common.settings.Setting;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.common.settings.SettingsFilter;
import org.elasticsearch.common.unit.TimeValue;
import org.elasticsearch.common.util.concurrent.EsExecutors;
import org.elasticsearch.common.xcontent.NamedXContentRegistry;
import org.elasticsearch.env.Environment;
import org.elasticsearch.index.IndexModule;
import org.elasticsearch.license.XPackLicenseState;
import org.elasticsearch.plugins.ActionPlugin;
@ -153,6 +156,7 @@ import org.elasticsearch.xpack.watcher.watch.Watch;
import org.joda.time.DateTime;
import org.joda.time.DateTimeZone;
import java.io.InputStream;
import java.time.Clock;
import java.util.ArrayList;
import java.util.Arrays;
@ -177,6 +181,7 @@ public class Watcher implements ActionPlugin {
new Setting<>("index.xpack.watcher.template.version", "", Function.identity(), Setting.Property.IndexScope);
public static final Setting<Boolean> ENCRYPT_SENSITIVE_DATA_SETTING =
Setting.boolSetting("xpack.watcher.encrypt_sensitive_data", false, Setting.Property.NodeScope);
public static final Setting<InputStream> ENCRYPTION_KEY_SETTING = SecureSetting.secureFile("xpack.watcher.encryption_key", null);
public static final Setting<TimeValue> MAX_STOP_TIMEOUT_SETTING =
Setting.timeSetting("xpack.watcher.stop.timeout", TimeValue.timeValueSeconds(30), Setting.Property.NodeScope);
@ -367,6 +372,7 @@ public class Watcher implements ActionPlugin {
settings.add(Setting.intSetting("xpack.watcher.execution.scroll.size", 0, Setting.Property.NodeScope));
settings.add(Setting.intSetting("xpack.watcher.watch.scroll.size", 0, Setting.Property.NodeScope));
settings.add(ENCRYPT_SENSITIVE_DATA_SETTING);
settings.add(ENCRYPTION_KEY_SETTING);
settings.add(Setting.simpleString("xpack.watcher.internal.ops.search.default_timeout", Setting.Property.NodeScope));
settings.add(Setting.simpleString("xpack.watcher.internal.ops.bulk.default_timeout", Setting.Property.NodeScope));
@ -379,6 +385,8 @@ public class Watcher implements ActionPlugin {
settings.add(Setting.simpleString("xpack.watcher.execution.scroll.timeout", Setting.Property.NodeScope));
settings.add(Setting.simpleString("xpack.watcher.start_immediately", Setting.Property.NodeScope));
// encryption settings
CryptoService.addSettings(settings);
return settings;
}
@ -512,4 +520,8 @@ public class Watcher implements ActionPlugin {
return map;
};
}
public List<BootstrapCheck> getBootstrapChecks() {
return Collections.singletonList(new EncryptSensitiveDataBootstrapCheck(settings, new Environment(settings)));
}
}

View File

@ -12,7 +12,6 @@ import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.common.xcontent.NamedXContentRegistry;
import org.elasticsearch.common.xcontent.XContentFactory;
import org.elasticsearch.common.xcontent.XContentParser;
import org.elasticsearch.index.query.QueryParseContext;
import org.elasticsearch.script.Script;
import org.elasticsearch.script.ScriptService;
import org.elasticsearch.script.TemplateScript;
@ -63,7 +62,7 @@ public class WatcherSearchTemplateService extends AbstractComponent {
BytesReference source = request.getSearchSource();
if (source != null && source.length() > 0) {
try (XContentParser parser = XContentFactory.xContent(source).createParser(xContentRegistry, source)) {
sourceBuilder.parseXContent(new QueryParseContext(parser));
sourceBuilder.parseXContent(parser);
searchRequest.source(sourceBuilder);
}
}

View File

@ -22,7 +22,6 @@ import org.elasticsearch.common.xcontent.XContentType;
import org.elasticsearch.xpack.common.secret.Secret;
import org.elasticsearch.xpack.security.crypto.CryptoService;
import org.elasticsearch.xpack.support.clock.HaltedClock;
import org.elasticsearch.xpack.watcher.Watcher;
import org.elasticsearch.xpack.watcher.actions.ActionRegistry;
import org.elasticsearch.xpack.watcher.actions.ActionStatus;
import org.elasticsearch.xpack.watcher.actions.ActionWrapper;
@ -209,7 +208,7 @@ public class Watch implements ToXContentObject {
this.triggerService = triggerService;
this.actionRegistry = actionRegistry;
this.inputRegistry = inputRegistry;
this.cryptoService = Watcher.ENCRYPT_SENSITIVE_DATA_SETTING.get(settings) ? cryptoService : null;
this.cryptoService = cryptoService;
this.defaultInput = new ExecutableNoneInput(logger);
this.defaultCondition = AlwaysCondition.INSTANCE;
this.defaultActions = Collections.emptyList();

View File

@ -74,8 +74,8 @@ public class BulkUpdateTests extends SecurityIntegTestCase {
public void testThatBulkUpdateDoesNotLoseFieldsHttp() throws IOException {
final String path = "/index1/type/1";
final Header basicAuthHeader = new BasicHeader("Authorization",
UsernamePasswordToken.basicAuthHeaderValue(SecuritySettingsSource.DEFAULT_USER_NAME,
new SecureString(SecuritySettingsSource.DEFAULT_PASSWORD.toCharArray())));
UsernamePasswordToken.basicAuthHeaderValue(SecuritySettingsSource.TEST_USER_NAME,
new SecureString(SecuritySettingsSource.TEST_PASSWORD.toCharArray())));
StringEntity body = new StringEntity("{\"test\":\"test\"}", ContentType.APPLICATION_JSON);
Response response = getRestClient().performRequest("PUT", path, Collections.emptyMap(), body, basicAuthHeader);

View File

@ -18,6 +18,7 @@ import org.elasticsearch.test.SecurityIntegTestCase;
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.IncomingRequest;
import org.elasticsearch.xpack.security.authc.Realm;
import org.elasticsearch.xpack.security.authc.Realms;
import org.elasticsearch.xpack.security.authc.support.Hasher;
@ -40,6 +41,7 @@ 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())));
@ -164,8 +166,8 @@ public class ClearRealmsCacheTests extends SecurityIntegTestCase {
static void executeHttpRequest(String path, Map<String, String> params) throws Exception {
Response response = getRestClient().performRequest("POST", path, params,
new BasicHeader(UsernamePasswordToken.BASIC_AUTH_HEADER,
UsernamePasswordToken.basicAuthHeaderValue(SecuritySettingsSource.DEFAULT_USER_NAME,
new SecureString(SecuritySettingsSource.DEFAULT_PASSWORD.toCharArray()))));
UsernamePasswordToken.basicAuthHeaderValue(SecuritySettingsSource.TEST_USER_NAME,
new SecureString(SecuritySettingsSource.TEST_PASSWORD.toCharArray()))));
assertNotNull(response.getEntity());
assertTrue(EntityUtils.toString(response.getEntity()).contains("cluster_name"));
}
@ -233,7 +235,7 @@ public class ClearRealmsCacheTests extends SecurityIntegTestCase {
for (Realm realm : realms) {
for (String username : usernames) {
PlainActionFuture<User> future = new PlainActionFuture<>();
realm.authenticate(tokens.get(username), future);
realm.authenticate(tokens.get(username), future, mock(IncomingRequest.class));
User user = future.actionGet();
assertThat(user, notNullValue());
Map<Realm, User> realmToUser = users.get(username);
@ -250,7 +252,7 @@ public class ClearRealmsCacheTests extends SecurityIntegTestCase {
for (String username : usernames) {
for (Realm realm : realms) {
PlainActionFuture<User> future = new PlainActionFuture<>();
realm.authenticate(tokens.get(username), future);
realm.authenticate(tokens.get(username), future, mock(IncomingRequest.class));
User user = future.actionGet();
assertThat(user, sameInstance(users.get(username).get(realm)));
}
@ -263,7 +265,7 @@ public class ClearRealmsCacheTests extends SecurityIntegTestCase {
for (String username : usernames) {
for (Realm realm : realms) {
PlainActionFuture<User> future = new PlainActionFuture<>();
realm.authenticate(tokens.get(username), future);
realm.authenticate(tokens.get(username), future, mock(IncomingRequest.class));
User user = future.actionGet();
assertThat(user, notNullValue());
scenario.assertEviction(users.get(username).get(realm), user);

View File

@ -33,7 +33,7 @@ public class MultipleIndicesPermissionsTests extends SecurityIntegTestCase {
@Override
protected String configRoles() {
return SecuritySettingsSource.DEFAULT_ROLE + ":\n" +
return SecuritySettingsSource.TEST_ROLE + ":\n" +
" cluster: [ all ]\n" +
" indices:\n" +
" - names: '*'\n" +

View File

@ -7,7 +7,6 @@ package org.elasticsearch.integration;
import org.elasticsearch.ElasticsearchSecurityException;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.common.settings.SecureString;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.indices.TermsLookup;
import org.elasticsearch.test.SecurityIntegTestCase;
@ -26,7 +25,7 @@ public class SecurityCachePermissionTests extends SecurityIntegTestCase {
@Override
public String configUsers() {
return super.configUsers()
+ READ_ONE_IDX_USER + ":" + SecuritySettingsSource.DEFAULT_PASSWORD_HASHED + "\n";
+ READ_ONE_IDX_USER + ":" + SecuritySettingsSource.TEST_PASSWORD_HASHED + "\n";
}
@Override
@ -61,7 +60,7 @@ public class SecurityCachePermissionTests extends SecurityIntegTestCase {
// Repeat with unauthorized user!!!!
try {
response = client().filterWithHeader(singletonMap("Authorization", basicAuthHeaderValue(READ_ONE_IDX_USER,
new SecureString("changeme".toCharArray()))))
SecuritySettingsSource.TEST_PASSWORD_SECURE_STRING)))
.prepareSearch("data").setTypes("a").setQuery(QueryBuilders.constantScoreQuery(
QueryBuilders.termsLookupQuery("token", new TermsLookup("tokens", "tokens", "1", "tokens"))))
.execute().actionGet();

View File

@ -78,7 +78,7 @@ import static org.hamcrest.Matchers.notNullValue;
@TestLogging("org.elasticsearch.cluster.service:TRACE,org.elasticsearch.discovery.zen:TRACE")
public class LicensingTests extends SecurityIntegTestCase {
public static final String ROLES =
SecuritySettingsSource.DEFAULT_ROLE + ":\n" +
SecuritySettingsSource.TEST_ROLE + ":\n" +
" cluster: [ all ]\n" +
" indices:\n" +
" - names: '*'\n" +
@ -204,8 +204,8 @@ public class LicensingTests extends SecurityIntegTestCase {
e = expectThrows(ResponseException.class, () -> getRestClient().performRequest("GET", "/_xpack/security/_authenticate"));
assertThat(e.getResponse().getStatusLine().getStatusCode(), is(401));
final String basicAuthValue = UsernamePasswordToken.basicAuthHeaderValue(SecuritySettingsSource.DEFAULT_USER_NAME,
new SecureString(SecuritySettingsSource.DEFAULT_PASSWORD.toCharArray()));
final String basicAuthValue = UsernamePasswordToken.basicAuthHeaderValue(SecuritySettingsSource.TEST_USER_NAME,
new SecureString(SecuritySettingsSource.TEST_PASSWORD.toCharArray()));
response = getRestClient().performRequest("GET", "/", new BasicHeader("Authorization", basicAuthValue));
assertThat(response.getStatusLine().getStatusCode(), is(200));
response = getRestClient()

View File

@ -5,10 +5,28 @@
*/
package org.elasticsearch.test;
import org.apache.http.HttpEntity;
import org.apache.http.entity.ContentType;
import org.apache.http.message.BasicHeader;
import org.apache.http.nio.entity.NStringEntity;
import org.elasticsearch.client.Response;
import org.elasticsearch.common.network.NetworkModule;
import org.elasticsearch.common.settings.SecureString;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.xpack.security.authc.support.UsernamePasswordToken;
import org.elasticsearch.xpack.security.client.SecurityClient;
import org.elasticsearch.xpack.security.user.BeatsSystemUser;
import org.elasticsearch.xpack.security.user.ElasticUser;
import org.elasticsearch.xpack.security.user.KibanaUser;
import org.elasticsearch.xpack.security.user.LogstashSystemUser;
import org.junit.After;
import org.junit.Before;
import java.io.IOException;
import java.util.Arrays;
import java.util.Collections;
/**
* Test case with method to handle the starting and stopping the stores for native users and roles
*/
@ -17,6 +35,7 @@ public abstract class NativeRealmIntegTestCase extends SecurityIntegTestCase {
@Before
public void ensureNativeStoresStarted() throws Exception {
assertSecurityIndexActive();
setupReservedPasswords();
}
@After
@ -29,4 +48,41 @@ public abstract class NativeRealmIntegTestCase extends SecurityIntegTestCase {
client.prepareClearRealmCache().get();
}
}
@Override
protected Settings nodeSettings(int nodeOrdinal) {
return Settings.builder()
.put(super.nodeSettings(nodeOrdinal))
.put(NetworkModule.HTTP_ENABLED.getKey(), true)
.build();
}
private SecureString reservedPassword = SecuritySettingsSource.TEST_PASSWORD_SECURE_STRING;
protected SecureString getReservedPassword() {
return reservedPassword;
}
protected boolean shouldSetReservedUserPasswords() {
return true;
}
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;
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));
String route = "/_xpack/security/user/" + username + "/_password";
Response response = getRestClient().performRequest("PUT", route, Collections.emptyMap(), entity, authHeader);
}
logger.info("setting up reserved passwords finished");
}
}

View File

@ -244,8 +244,8 @@ public abstract class SecurityIntegTestCase extends ESIntegTestCase {
@Override
protected Settings externalClusterClientSettings() {
return Settings.builder()
.put(Security.USER_SETTING.getKey(), SecuritySettingsSource.DEFAULT_USER_NAME + ":"
+ SecuritySettingsSource.DEFAULT_PASSWORD)
.put(Security.USER_SETTING.getKey(), SecuritySettingsSource.TEST_USER_NAME + ":"
+ SecuritySettingsSource.TEST_PASSWORD)
.build();
}

View File

@ -52,25 +52,25 @@ public class SecuritySettingsSource extends ClusterDiscoveryConfiguration.Unicas
public static final Settings DEFAULT_SETTINGS = Settings.EMPTY;
public static final String DEFAULT_USER_NAME = "test_user";
public static final String DEFAULT_PASSWORD = "changeme";
public static final SecureString DEFAULT_PASSWORD_SECURE_STRING = new SecureString("changeme".toCharArray());
public static final String DEFAULT_PASSWORD_HASHED = new String(Hasher.BCRYPT.hash(new SecureString(DEFAULT_PASSWORD.toCharArray())));
public static final String DEFAULT_ROLE = "user";
public static final String TEST_USER_NAME = "test_user";
public static final String TEST_PASSWORD = "x-pack-test-password";
public static final SecureString TEST_PASSWORD_SECURE_STRING = new SecureString("x-pack-test-password".toCharArray());
public static final String TEST_PASSWORD_HASHED = new String(Hasher.BCRYPT.hash(new SecureString(TEST_PASSWORD.toCharArray())));
public static final String TEST_ROLE = "user";
public static final String DEFAULT_TRANSPORT_CLIENT_ROLE = "transport_client";
public static final String DEFAULT_TRANSPORT_CLIENT_USER_NAME = "test_trans_client_user";
public static final String CONFIG_STANDARD_USER =
DEFAULT_USER_NAME + ":" + DEFAULT_PASSWORD_HASHED + "\n" +
DEFAULT_TRANSPORT_CLIENT_USER_NAME + ":" + DEFAULT_PASSWORD_HASHED + "\n";
TEST_USER_NAME + ":" + TEST_PASSWORD_HASHED + "\n" +
DEFAULT_TRANSPORT_CLIENT_USER_NAME + ":" + TEST_PASSWORD_HASHED + "\n";
public static final String CONFIG_STANDARD_USER_ROLES =
DEFAULT_ROLE + ":" + DEFAULT_USER_NAME + "," + DEFAULT_TRANSPORT_CLIENT_USER_NAME + "\n" +
TEST_ROLE + ":" + TEST_USER_NAME + "," + DEFAULT_TRANSPORT_CLIENT_USER_NAME + "\n" +
DEFAULT_TRANSPORT_CLIENT_ROLE + ":" + DEFAULT_TRANSPORT_CLIENT_USER_NAME+ "\n";
public static final String CONFIG_ROLE_ALLOW_ALL =
DEFAULT_ROLE + ":\n" +
TEST_ROLE + ":\n" +
" cluster: [ ALL ]\n" +
" indices:\n" +
" - names: '*'\n" +
@ -174,11 +174,11 @@ public class SecuritySettingsSource extends ClusterDiscoveryConfiguration.Unicas
}
protected String nodeClientUsername() {
return DEFAULT_USER_NAME;
return TEST_USER_NAME;
}
protected SecureString nodeClientPassword() {
return new SecureString(DEFAULT_PASSWORD.toCharArray());
return new SecureString(TEST_PASSWORD.toCharArray());
}
protected String transportClientUsername() {
@ -186,7 +186,7 @@ public class SecuritySettingsSource extends ClusterDiscoveryConfiguration.Unicas
}
protected SecureString transportClientPassword() {
return new SecureString(DEFAULT_PASSWORD.toCharArray());
return new SecureString(TEST_PASSWORD.toCharArray());
}
protected Class<? extends XPackPlugin> xpackPluginClass() {

View File

@ -55,7 +55,7 @@ public class SecurityTestsUtils {
public static void assertAuthorizationExceptionDefaultUsers(Throwable throwable, String action) {
assertAuthorizationException(throwable, either(containsString("[" + action + "] is unauthorized for user ["
+ SecuritySettingsSource.DEFAULT_USER_NAME + "]")).or(containsString("[" + action + "] is unauthorized for user ["
+ SecuritySettingsSource.TEST_USER_NAME + "]")).or(containsString("[" + action + "] is unauthorized for user ["
+ SecuritySettingsSource.DEFAULT_TRANSPORT_CLIENT_USER_NAME + "]")));
}

View File

@ -11,9 +11,9 @@ import org.apache.http.message.BasicHeader;
import org.elasticsearch.client.Response;
import org.elasticsearch.client.ResponseException;
import org.elasticsearch.client.RestClient;
import org.elasticsearch.common.settings.SecureString;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.common.util.concurrent.ThreadContext;
import org.elasticsearch.test.SecuritySettingsSource;
import org.elasticsearch.test.rest.ESRestTestCase;
import org.elasticsearch.xpack.ml.MachineLearning;
import org.junit.After;
@ -33,9 +33,9 @@ import static org.hamcrest.Matchers.equalTo;
public class DatafeedJobsRestIT extends ESRestTestCase {
private static final String BASIC_AUTH_VALUE_ELASTIC =
basicAuthHeaderValue("elastic", new SecureString("changeme".toCharArray()));
basicAuthHeaderValue("elastic", SecuritySettingsSource.TEST_PASSWORD_SECURE_STRING);
private static final String BASIC_AUTH_VALUE_ML_ADMIN =
basicAuthHeaderValue("ml_admin", new SecureString("changeme".toCharArray()));
basicAuthHeaderValue("ml_admin", SecuritySettingsSource.TEST_PASSWORD_SECURE_STRING);
@Override
protected Settings restClientSettings() {
@ -50,11 +50,16 @@ 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
String user = "{"
+ " \"password\" : \"changeme\","
+ " \"password\" : \"" + password + "\","
+ " \"roles\" : [ \"machine_learning_admin\" ]"
+ "}";

View File

@ -9,11 +9,11 @@ import org.apache.http.entity.ContentType;
import org.apache.http.entity.StringEntity;
import org.elasticsearch.client.Response;
import org.elasticsearch.client.ResponseException;
import org.elasticsearch.common.settings.SecureString;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.common.util.concurrent.ConcurrentCollections;
import org.elasticsearch.common.util.concurrent.ConcurrentMapLong;
import org.elasticsearch.common.util.concurrent.ThreadContext;
import org.elasticsearch.test.SecuritySettingsSource;
import org.elasticsearch.test.rest.ESRestTestCase;
import org.elasticsearch.xpack.ml.MachineLearning;
import org.elasticsearch.xpack.ml.job.persistence.AnomalyDetectorsIndex;
@ -36,7 +36,7 @@ import static org.hamcrest.Matchers.not;
public class MlJobIT extends ESRestTestCase {
private static final String BASIC_AUTH_VALUE = basicAuthHeaderValue("elastic", new SecureString("changeme".toCharArray()));
private static final String BASIC_AUTH_VALUE = basicAuthHeaderValue("elastic", SecuritySettingsSource.TEST_PASSWORD_SECURE_STRING);
@Override
protected Settings restClientSettings() {

View File

@ -20,6 +20,7 @@ import org.elasticsearch.common.xcontent.json.JsonXContent;
import org.elasticsearch.search.SearchModule;
import org.elasticsearch.tasks.Task;
import org.elasticsearch.test.SecurityIntegTestCase;
import org.elasticsearch.test.SecuritySettingsSource;
import org.elasticsearch.xpack.XPackSettings;
import org.elasticsearch.xpack.ml.MlMetadata;
import org.elasticsearch.xpack.ml.action.CloseJobAction;
@ -80,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:changeme");
builder.put(Security.USER_SETTING.getKey(), "elastic:" + SecuritySettingsSource.TEST_PASSWORD_SECURE_STRING);
builder.put(XPackSettings.MACHINE_LEARNING_ENABLED.getKey(), true);
return builder.build();
}

View File

@ -16,9 +16,7 @@ import org.elasticsearch.xpack.ml.job.results.Bucket;
import org.junit.After;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
import static org.hamcrest.Matchers.equalTo;
@ -57,16 +55,14 @@ public class UpdateInterimResultsIT extends MlNativeAutodetectIntegTestCase {
openJob(job.getId());
time = 1400000000;
Map<Long, Integer> anomalies = new HashMap<>();
anomalies.put(1400021500L, 14);
// push some data, flush job, verify no interim results
assertThat(postData(job.getId(), createData(50, anomalies)).getProcessedRecordCount(), equalTo(50L));
assertThat(postData(job.getId(), createData(50)).getProcessedRecordCount(), equalTo(50L));
flushJob(job.getId(), false);
assertThat(getInterimResults(job.getId()).isEmpty(), is(true));
// push some more data, flush job, verify no interim results
assertThat(postData(job.getId(), createData(30, anomalies)).getProcessedRecordCount(), equalTo(30L));
assertThat(postData(job.getId(), createData(30)).getProcessedRecordCount(), equalTo(30L));
flushJob(job.getId(), false);
assertThat(getInterimResults(job.getId()).isEmpty(), is(true));
assertThat(time, equalTo(1400040000L));
@ -81,7 +77,7 @@ public class UpdateInterimResultsIT extends MlNativeAutodetectIntegTestCase {
// We might need to retry this while waiting for a refresh
assertBusy(() -> {
List<Bucket> firstInterimBuckets = getInterimResults(job.getId());
assertThat(firstInterimBuckets.size(), equalTo(2));
assertThat("interim buckets were: " + firstInterimBuckets, firstInterimBuckets.size(), equalTo(2));
assertThat(firstInterimBuckets.get(0).getTimestamp().getTime(), equalTo(1400039000000L));
assertThat(firstInterimBuckets.get(1).getTimestamp().getTime(), equalTo(1400040000000L));
assertThat(firstInterimBuckets.get(1).getRecords().get(0).getActual().get(0), equalTo(16.0));
@ -101,7 +97,7 @@ public class UpdateInterimResultsIT extends MlNativeAutodetectIntegTestCase {
// push rest of data, close, verify no interim results
time += BUCKET_SPAN_SECONDS;
assertThat(postData(job.getId(), createData(30, anomalies)).getProcessedRecordCount(), equalTo(30L));
assertThat(postData(job.getId(), createData(30)).getProcessedRecordCount(), equalTo(30L));
closeJob(job.getId());
assertThat(getInterimResults(job.getId()).isEmpty(), is(true));
@ -114,10 +110,10 @@ public class UpdateInterimResultsIT extends MlNativeAutodetectIntegTestCase {
assertThat(bucket.get(0).getRecords().get(0).getActual().get(0), equalTo(14.0));
}
private String createData(int halfBuckets, Map<Long, Integer> timeToValueMap) {
private String createData(int halfBuckets) {
StringBuilder data = new StringBuilder();
for (int i = 0; i < halfBuckets; i++) {
int value = timeToValueMap.getOrDefault(time, randomIntBetween(1, 3));
int value = randomIntBetween(1, 3);
data.append("{\"time\":").append(time).append(", \"value\":").append(value).append("}\n");
time += BUCKET_SPAN_SECONDS / 2;
}

View File

@ -84,8 +84,8 @@ public class OldMonitoringIndicesBackwardsCompatibilityTests extends AbstractOld
httpExporter.put("type", "http");
httpExporter.put("enabled", port == null ? "false" : "true");
httpExporter.put("host", "http://localhost:" + (port == null ? "does_not_matter" : port));
httpExporter.put("auth.username", SecuritySettingsSource.DEFAULT_USER_NAME);
httpExporter.put("auth.password", SecuritySettingsSource.DEFAULT_PASSWORD);
httpExporter.put("auth.username", SecuritySettingsSource.TEST_USER_NAME);
httpExporter.put("auth.password", SecuritySettingsSource.TEST_PASSWORD);
settings.putProperties(httpExporter, k -> MonitoringSettings.EXPORTERS_SETTINGS.getKey() + "my_exporter." + k);
}

View File

@ -27,6 +27,7 @@ import org.elasticsearch.index.IndexNotFoundException;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.plugins.Plugin;
import org.elasticsearch.test.ESIntegTestCase;
import org.elasticsearch.test.SecuritySettingsSource;
import org.elasticsearch.test.TestCluster;
import org.elasticsearch.test.store.MockFSIndexStore;
import org.elasticsearch.test.transport.MockTransportService;
@ -157,7 +158,7 @@ public abstract class MonitoringIntegTestCase extends ESIntegTestCase {
return Settings.builder()
.put(super.transportClientSettings())
.put("client.transport.sniff", false)
.put(Security.USER_SETTING.getKey(), "test:changeme")
.put(Security.USER_SETTING.getKey(), "test:" + SecuritySettings.TEST_PASSWORD)
.put(NetworkModule.TRANSPORT_TYPE_KEY, Security.NAME4)
.put(NetworkModule.HTTP_TYPE_KEY, Security.NAME4)
.put(XPackSettings.WATCHER_ENABLED.getKey(), watcherEnabled)
@ -467,7 +468,7 @@ public abstract class MonitoringIntegTestCase extends ESIntegTestCase {
public static class SecuritySettings {
public static final String TEST_USERNAME = "test";
public static final String TEST_PASSWORD = "changeme";
public static final String TEST_PASSWORD = SecuritySettingsSource.TEST_PASSWORD;
private static final String TEST_PASSWORD_HASHED = new String(Hasher.BCRYPT.hash(new SecureString(TEST_PASSWORD.toCharArray())));
static boolean auditLogsEnabled = SystemPropertyUtil.getBoolean("tests.audit_logs", true);

View File

@ -6,10 +6,12 @@
package org.elasticsearch.xpack.notification.email;
import org.elasticsearch.action.get.GetResponse;
import org.elasticsearch.common.settings.MockSecureSettings;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.common.xcontent.support.XContentMapValues;
import org.elasticsearch.xpack.notification.email.support.EmailServer;
import org.elasticsearch.xpack.security.crypto.CryptoService;
import org.elasticsearch.xpack.watcher.Watcher;
import org.elasticsearch.xpack.watcher.client.WatcherClient;
import org.elasticsearch.xpack.watcher.condition.AlwaysCondition;
import org.elasticsearch.xpack.watcher.execution.ActionExecutionMode;
@ -43,6 +45,7 @@ public class EmailSecretsIntegrationTests extends AbstractWatcherIntegrationTest
private EmailServer server;
private Boolean encryptSensitiveData;
private byte[] encryptionKey;
@Override
public void setUp() throws Exception {
@ -58,15 +61,23 @@ public class EmailSecretsIntegrationTests extends AbstractWatcherIntegrationTest
@Override
protected Settings nodeSettings(int nodeOrdinal) {
if (encryptSensitiveData == null) {
encryptSensitiveData = securityEnabled() && randomBoolean();
encryptSensitiveData = randomBoolean();
if (encryptSensitiveData) {
encryptionKey = CryptoService.generateKey();
}
}
return Settings.builder()
Settings.Builder builder = Settings.builder()
.put(super.nodeSettings(nodeOrdinal))
.put("xpack.notification.email.account.test.smtp.auth", true)
.put("xpack.notification.email.account.test.smtp.port", server.port())
.put("xpack.notification.email.account.test.smtp.host", "localhost")
.put("xpack.watcher.encrypt_sensitive_data", encryptSensitiveData)
.build();
.put("xpack.watcher.encrypt_sensitive_data", encryptSensitiveData);
if (encryptSensitiveData) {
MockSecureSettings secureSettings = new MockSecureSettings();
secureSettings.setFile(Watcher.ENCRYPTION_KEY_SETTING.getKey(), encryptionKey);
builder.setSecureSettings(secureSettings);
}
return builder.build();
}
public void testEmail() throws Exception {
@ -91,9 +102,12 @@ public class EmailSecretsIntegrationTests extends AbstractWatcherIntegrationTest
Map<String, Object> source = response.getSource();
Object value = XContentMapValues.extractValue("actions._email.email.password", source);
assertThat(value, notNullValue());
if (securityEnabled() && encryptSensitiveData) {
if (encryptSensitiveData) {
assertThat(value, not(is(EmailServer.PASSWORD)));
CryptoService cryptoService = getInstanceFromMaster(CryptoService.class);
MockSecureSettings mockSecureSettings = new MockSecureSettings();
mockSecureSettings.setFile(Watcher.ENCRYPTION_KEY_SETTING.getKey(), encryptionKey);
Settings settings = Settings.builder().setSecureSettings(mockSecureSettings).build();
CryptoService cryptoService = new CryptoService(settings);
assertThat(new String(cryptoService.decrypt(((String) value).toCharArray())), is(EmailServer.PASSWORD));
} else {
assertThat(value, is(EmailServer.PASSWORD));

View File

@ -43,8 +43,8 @@ public class SecurityPluginTests extends SecurityIntegTestCase {
logger.info("executing authorized request to /_xpack infos");
Response response = getRestClient().performRequest("GET", "/_xpack",
new BasicHeader(UsernamePasswordToken.BASIC_AUTH_HEADER,
basicAuthHeaderValue(SecuritySettingsSource.DEFAULT_USER_NAME,
new SecureString(SecuritySettingsSource.DEFAULT_PASSWORD.toCharArray()))));
basicAuthHeaderValue(SecuritySettingsSource.TEST_USER_NAME,
new SecureString(SecuritySettingsSource.TEST_PASSWORD.toCharArray()))));
assertThat(response.getStatusLine().getStatusCode(), is(OK.getStatus()));
}
}

View File

@ -5,15 +5,22 @@
*/
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;
import org.elasticsearch.common.UUIDs;
import org.elasticsearch.common.network.NetworkModule;
import org.elasticsearch.common.settings.MockSecureSettings;
import org.elasticsearch.common.settings.SecureSettings;
import org.elasticsearch.common.settings.SecureString;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.common.unit.TimeValue;
@ -33,11 +40,14 @@ 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;
@ -76,7 +86,16 @@ public class SecurityTribeIT extends NativeRealmIntegTestCase {
super.setUp();
if (cluster2 == null) {
SecuritySettingsSource cluster2SettingsSource =
new SecuritySettingsSource(defaultMaxNumberOfNodes(), useGeneratedSSL, createTempDir(), Scope.SUITE);
new SecuritySettingsSource(defaultMaxNumberOfNodes(), useGeneratedSSL, createTempDir(), Scope.SUITE) {
@Override
public Settings nodeSettings(int nodeOrdinal) {
return Settings.builder()
.put(super.nodeSettings(nodeOrdinal))
.put(NetworkModule.HTTP_ENABLED.getKey(), true)
.build();
}
};
cluster2 = new InternalTestCluster(randomLong(), createTempDir(), true, true, 1, 2,
UUIDs.randomBase64UUID(random()), cluster2SettingsSource, 0, false, SECOND_CLUSTER_NODE_PREFIX, getMockPlugins(),
getClientWrapper());
@ -85,6 +104,11 @@ public class SecurityTribeIT extends NativeRealmIntegTestCase {
}
}
@Override
public boolean shouldSetReservedUserPasswords() {
return false;
}
@Override
public boolean useGeneratedSSLConfig() {
return useGeneratedSSL;
@ -138,8 +162,17 @@ public class SecurityTribeIT extends NativeRealmIntegTestCase {
private void setupTribeNode(Settings settings) throws NodeValidationException, InterruptedException {
SecuritySettingsSource cluster2SettingsSource =
new SecuritySettingsSource(1, useGeneratedSSL, createTempDir(), Scope.TEST);
Map<String,String> asMap = new HashMap<>(cluster2SettingsSource.nodeSettings(0).getAsMap());
new SecuritySettingsSource(1, useGeneratedSSL, createTempDir(), Scope.TEST) {
@Override
public Settings nodeSettings(int nodeOrdinal) {
return Settings.builder()
.put(super.nodeSettings(nodeOrdinal))
.put(NetworkModule.HTTP_ENABLED.getKey(), true)
.build();
}
};
Map<String, String> asMap = new HashMap<>(cluster2SettingsSource.nodeSettings(0).getAsMap());
asMap.remove(NodeEnvironment.MAX_LOCAL_STORAGE_NODES_SETTING.getKey());
Settings.Builder tribe1Defaults = Settings.builder();
Settings.Builder tribe2Defaults = Settings.builder();
@ -216,9 +249,25 @@ public class SecurityTribeIT extends NativeRealmIntegTestCase {
}
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);
ClusterHealthResponse response = tribeClient.filterWithHeader(Collections.singletonMap("Authorization",
UsernamePasswordToken.basicAuthHeaderValue("elastic", new SecureString("changeme".toCharArray()))))
UsernamePasswordToken.basicAuthHeaderValue("elastic", SecuritySettingsSource.TEST_PASSWORD_SECURE_STRING)))
.admin().cluster().prepareHealth().get();
assertNoTimeout(response);
}
@ -308,7 +357,7 @@ public class SecurityTribeIT extends NativeRealmIntegTestCase {
PutUserResponse response =
securityClient(nonPreferredClient).preparePutUser(username, "password".toCharArray(), "superuser").get();
assertTrue(response.created());
shouldBeSuccessfulUsers.add(username);
shouldBeSuccessfulUsers.add(username);
}
assertTribeNodeHasAllIndices();

View File

@ -9,8 +9,8 @@ import org.elasticsearch.ElasticsearchSecurityException;
import org.elasticsearch.action.ActionListener;
import org.elasticsearch.action.support.ActionFilters;
import org.elasticsearch.cluster.metadata.IndexNameExpressionResolver;
import org.elasticsearch.common.settings.SecureString;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.test.SecuritySettingsSource;
import org.elasticsearch.xpack.security.authc.esnative.NativeUsersStore;
import org.elasticsearch.xpack.security.authc.support.Hasher;
import org.elasticsearch.xpack.security.user.AnonymousUser;
@ -54,7 +54,7 @@ public class TransportChangePasswordActionTests extends ESTestCase {
ChangePasswordRequest request = new ChangePasswordRequest();
request.username(anonymousUser.principal());
request.passwordHash(Hasher.BCRYPT.hash(new SecureString("changeme".toCharArray())));
request.passwordHash(Hasher.BCRYPT.hash(SecuritySettingsSource.TEST_PASSWORD_SECURE_STRING));
final AtomicReference<Throwable> throwableRef = new AtomicReference<>();
final AtomicReference<ChangePasswordResponse> responseRef = new AtomicReference<>();
@ -85,7 +85,7 @@ public class TransportChangePasswordActionTests extends ESTestCase {
ChangePasswordRequest request = new ChangePasswordRequest();
request.username(randomFrom(SystemUser.INSTANCE.principal(), XPackUser.INSTANCE.principal()));
request.passwordHash(Hasher.BCRYPT.hash(new SecureString("changeme".toCharArray())));
request.passwordHash(Hasher.BCRYPT.hash(SecuritySettingsSource.TEST_PASSWORD_SECURE_STRING));
final AtomicReference<Throwable> throwableRef = new AtomicReference<>();
final AtomicReference<ChangePasswordResponse> responseRef = new AtomicReference<>();
@ -112,15 +112,13 @@ public class TransportChangePasswordActionTests extends ESTestCase {
NativeUsersStore usersStore = mock(NativeUsersStore.class);
ChangePasswordRequest request = new ChangePasswordRequest();
request.username(user.principal());
request.passwordHash(Hasher.BCRYPT.hash(new SecureString("changeme".toCharArray())));
doAnswer(new Answer() {
public Void answer(InvocationOnMock invocation) {
Object[] args = invocation.getArguments();
assert args.length == 2;
ActionListener<Void> listener = (ActionListener<Void>) args[1];
listener.onResponse(null);
return null;
}
request.passwordHash(Hasher.BCRYPT.hash(SecuritySettingsSource.TEST_PASSWORD_SECURE_STRING));
doAnswer(invocation -> {
Object[] args = invocation.getArguments();
assert args.length == 2;
ActionListener<Void> listener = (ActionListener<Void>) args[1];
listener.onResponse(null);
return null;
}).when(usersStore).changePassword(eq(request), any(ActionListener.class));
TransportService transportService = new TransportService(Settings.EMPTY, null, null, TransportService.NOOP_TRANSPORT_INTERCEPTOR,
x -> null, null);
@ -152,7 +150,7 @@ public class TransportChangePasswordActionTests extends ESTestCase {
NativeUsersStore usersStore = mock(NativeUsersStore.class);
ChangePasswordRequest request = new ChangePasswordRequest();
request.username(user.principal());
request.passwordHash(Hasher.BCRYPT.hash(new SecureString("changeme".toCharArray())));
request.passwordHash(Hasher.BCRYPT.hash(SecuritySettingsSource.TEST_PASSWORD_SECURE_STRING));
final Exception e = randomFrom(new ElasticsearchSecurityException(""), new IllegalStateException(), new RuntimeException());
doAnswer(new Answer() {
public Void answer(InvocationOnMock invocation) {

View File

@ -20,6 +20,7 @@ import org.elasticsearch.xpack.security.authc.esnative.NativeUsersStore;
import org.elasticsearch.xpack.security.authc.esnative.ReservedRealm;
import org.elasticsearch.xpack.security.authc.esnative.ReservedRealmTests;
import org.elasticsearch.xpack.security.user.AnonymousUser;
import org.elasticsearch.xpack.security.user.ElasticUser;
import org.elasticsearch.xpack.security.user.SystemUser;
import org.elasticsearch.xpack.security.user.User;
import org.elasticsearch.test.ESTestCase;
@ -180,9 +181,11 @@ public class TransportGetUsersActionTests extends ESTestCase {
}
});
User[] users = responseRef.get().users();
assertThat(throwableRef.get(), is(nullValue()));
assertThat(responseRef.get(), is(notNullValue()));
assertThat(responseRef.get().users(), arrayContaining(reservedUsers.toArray(new User[reservedUsers.size()])));
assertThat(users, arrayContaining(reservedUsers.toArray(new User[reservedUsers.size()])));
}
public void testGetAllUsers() {

View File

@ -11,10 +11,10 @@ import org.elasticsearch.action.support.ActionFilters;
import org.elasticsearch.action.support.PlainActionFuture;
import org.elasticsearch.cluster.metadata.IndexNameExpressionResolver;
import org.elasticsearch.common.ValidationException;
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.SecuritySettingsSource;
import org.elasticsearch.xpack.security.SecurityLifecycleService;
import org.elasticsearch.xpack.security.authc.esnative.NativeUsersStore;
import org.elasticsearch.xpack.security.authc.esnative.ReservedRealm;
@ -163,7 +163,7 @@ public class TransportPutUserActionTests extends ESTestCase {
final PutUserRequest request = new PutUserRequest();
request.username(user.principal());
if (isCreate) {
request.passwordHash(Hasher.BCRYPT.hash(new SecureString("changeme".toCharArray())));
request.passwordHash(Hasher.BCRYPT.hash(SecuritySettingsSource.TEST_PASSWORD_SECURE_STRING));
}
final boolean created = isCreate ? randomBoolean() : false; // updates should always return false for create
doAnswer(new Answer() {

View File

@ -15,8 +15,6 @@ import java.util.concurrent.atomic.AtomicReference;
import org.apache.http.message.BasicHeader;
import org.elasticsearch.action.ActionFuture;
import org.elasticsearch.action.admin.indices.exists.indices.IndicesExistsResponse;
import org.elasticsearch.action.admin.indices.recovery.RecoveryAction;
import org.elasticsearch.action.admin.indices.recovery.RecoveryRequestBuilder;
import org.elasticsearch.action.search.SearchRequest;
import org.elasticsearch.action.support.PlainActionFuture;
import org.elasticsearch.client.Client;
@ -24,7 +22,6 @@ import org.elasticsearch.client.Requests;
import org.elasticsearch.client.ResponseException;
import org.elasticsearch.common.network.NetworkModule;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.common.unit.TimeValue;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.search.SearchHit;
import org.elasticsearch.test.SecurityIntegTestCase;
@ -37,7 +34,7 @@ import org.elasticsearch.xpack.security.authc.support.UsernamePasswordToken;
import org.joda.time.DateTime;
import org.joda.time.DateTimeZone;
import static org.elasticsearch.test.SecuritySettingsSource.DEFAULT_PASSWORD_SECURE_STRING;
import static org.elasticsearch.test.SecuritySettingsSource.TEST_PASSWORD_SECURE_STRING;
import static org.hamcrest.Matchers.arrayContaining;
import static org.hamcrest.Matchers.containsInAnyOrder;
import static org.hamcrest.Matchers.equalTo;
@ -70,7 +67,7 @@ public class AuditTrailTests extends SecurityIntegTestCase {
@Override
public String configUsers() {
return super.configUsers()
+ AUTHENTICATE_USER + ":" + SecuritySettingsSource.DEFAULT_PASSWORD_HASHED + "\n"
+ AUTHENTICATE_USER + ":" + SecuritySettingsSource.TEST_PASSWORD_HASHED + "\n"
+ EXECUTE_USER + ":xx_no_password_xx\n";
}
@ -90,7 +87,7 @@ public class AuditTrailTests extends SecurityIntegTestCase {
try {
getRestClient().performRequest("GET", "/.security/_search",
new BasicHeader(UsernamePasswordToken.BASIC_AUTH_HEADER,
UsernamePasswordToken.basicAuthHeaderValue(AUTHENTICATE_USER, DEFAULT_PASSWORD_SECURE_STRING)),
UsernamePasswordToken.basicAuthHeaderValue(AUTHENTICATE_USER, TEST_PASSWORD_SECURE_STRING)),
new BasicHeader(AuthenticationService.RUN_AS_USER_HEADER, EXECUTE_USER));
fail("request should have failed");
} catch (ResponseException e) {
@ -112,7 +109,7 @@ public class AuditTrailTests extends SecurityIntegTestCase {
try {
getRestClient().performRequest("GET", "/.security/_search",
new BasicHeader(UsernamePasswordToken.BASIC_AUTH_HEADER,
UsernamePasswordToken.basicAuthHeaderValue(AUTHENTICATE_USER, DEFAULT_PASSWORD_SECURE_STRING)),
UsernamePasswordToken.basicAuthHeaderValue(AUTHENTICATE_USER, TEST_PASSWORD_SECURE_STRING)),
new BasicHeader(AuthenticationService.RUN_AS_USER_HEADER, ""));
fail("request should have failed");
} catch (ResponseException e) {

View File

@ -183,8 +183,8 @@ public class IndexAuditTrailTests extends SecurityIntegTestCase {
Settings.Builder builder = Settings.builder()
.put("xpack.security.audit.index.client." + XPackSettings.SECURITY_ENABLED.getKey(), useSecurity)
.put(remoteSettings(NetworkAddress.format(inet.address().getAddress()), inet.address().getPort(), cluster2Name))
.put("xpack.security.audit.index.client.xpack.security.user", SecuritySettingsSource.DEFAULT_USER_NAME + ":" +
SecuritySettingsSource.DEFAULT_PASSWORD);
.put("xpack.security.audit.index.client.xpack.security.user", SecuritySettingsSource.TEST_USER_NAME + ":" +
SecuritySettingsSource.TEST_PASSWORD);
if (useGeneratedSSL == false) {
cluster2SettingsSource.addClientSSLSettings(builder, "xpack.security.audit.index.client.");

View File

@ -101,7 +101,7 @@ public class RemoteIndexAuditTrailStartingTests extends SecurityIntegTestCase {
.put("xpack.security.audit.outputs", randomFrom("index", "index,logfile"))
.putArray("xpack.security.audit.index.client.hosts", addresses.toArray(new String[addresses.size()]))
.put("xpack.security.audit.index.client.cluster.name", clusterName)
.put("xpack.security.audit.index.client.xpack.security.user", DEFAULT_USER_NAME + ":" + DEFAULT_PASSWORD);
.put("xpack.security.audit.index.client.xpack.security.user", TEST_USER_NAME + ":" + TEST_PASSWORD);
addClientSSLSettings(builder, "xpack.security.audit.index.client.");
return builder.build();

View File

@ -5,16 +5,6 @@
*/
package org.elasticsearch.xpack.security.authc;
import java.io.IOException;
import java.time.Clock;
import java.util.Arrays;
import java.util.Base64;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.atomic.AtomicBoolean;
import org.apache.lucene.util.SetOnce;
import org.elasticsearch.ElasticsearchException;
import org.elasticsearch.ElasticsearchSecurityException;
@ -24,11 +14,14 @@ import org.elasticsearch.action.get.GetRequest;
import org.elasticsearch.action.get.GetResponse;
import org.elasticsearch.action.support.PlainActionFuture;
import org.elasticsearch.client.Client;
import org.elasticsearch.common.SuppressForbidden;
import org.elasticsearch.common.io.stream.BytesStreamOutput;
import org.elasticsearch.common.io.stream.StreamInput;
import org.elasticsearch.common.settings.SecureString;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.common.transport.TransportAddress;
import org.elasticsearch.common.util.concurrent.ThreadContext;
import org.elasticsearch.common.xcontent.NamedXContentRegistry;
import org.elasticsearch.env.Environment;
import org.elasticsearch.license.XPackLicenseState;
import org.elasticsearch.rest.RestRequest;
@ -53,6 +46,18 @@ import org.elasticsearch.xpack.security.user.User;
import org.junit.After;
import org.junit.Before;
import java.io.IOException;
import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.time.Clock;
import java.util.Arrays;
import java.util.Base64;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.atomic.AtomicBoolean;
import static org.elasticsearch.test.SecurityTestsUtils.assertAuthenticationException;
import static org.elasticsearch.xpack.security.support.Exceptions.authenticationError;
import static org.hamcrest.Matchers.arrayContaining;
@ -93,12 +98,16 @@ public class AuthenticationServiceTests extends ESTestCase {
private TokenService tokenService;
private SecurityLifecycleService lifecycleService;
private Client client;
private InetSocketAddress remoteAddress;
@Before
@SuppressForbidden(reason = "Allow accessing localhost")
public void init() throws Exception {
token = mock(AuthenticationToken.class);
message = new InternalMessage();
restRequest = new FakeRestRequest();
remoteAddress = new InetSocketAddress(InetAddress.getLocalHost(), 100);
message.remoteAddress(new TransportAddress(remoteAddress));
restRequest = new FakeRestRequest.Builder(NamedXContentRegistry.EMPTY).withRemoteAddress(remoteAddress).build();
threadContext = new ThreadContext(Settings.EMPTY);
firstRealm = mock(Realm.class);
@ -206,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));
verify(firstRealm, never()).authenticate(eq(token), any(ActionListener.class), any(IncomingRequest.class));
assertTrue(completed.get());
}
@ -562,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));
.when(secondRealm).authenticate(eq(token), any(ActionListener.class), any(IncomingRequest.class));
try {
authenticateBlocking("_action", message, null);
fail("exception should bubble out");
@ -577,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));
.when(secondRealm).authenticate(eq(token), any(ActionListener.class), any(IncomingRequest.class));
try {
authenticateBlocking(restRequest);
fail("exception should bubble out");
@ -869,7 +878,7 @@ public class AuthenticationServiceTests extends ESTestCase {
ActionListener listener = (ActionListener) i.getArguments()[1];
listener.onResponse(user);
return null;
}).when(realm).authenticate(eq(token), any(ActionListener.class));
}).when(realm).authenticate(eq(token), any(ActionListener.class), any(IncomingRequest.class));
}
private Authentication authenticateBlocking(RestRequest restRequest) {

View File

@ -436,7 +436,7 @@ public class RealmsTests extends ESTestCase {
}
@Override
public void authenticate(AuthenticationToken token, ActionListener<User> listener) {
public void authenticate(AuthenticationToken token, ActionListener<User> listener, IncomingRequest incomingRequest) {
listener.onResponse(null);
}

View File

@ -29,7 +29,7 @@ import java.util.HashMap;
import java.util.List;
import java.util.Map;
import static org.elasticsearch.test.SecuritySettingsSource.DEFAULT_PASSWORD_SECURE_STRING;
import static org.elasticsearch.test.SecuritySettingsSource.TEST_PASSWORD_SECURE_STRING;
import static org.hamcrest.Matchers.containsString;
import static org.hamcrest.Matchers.greaterThan;
import static org.hamcrest.Matchers.is;
@ -40,7 +40,7 @@ public class RunAsIntegTests extends SecurityIntegTestCase {
private static final String TRANSPORT_CLIENT_USER = "transport_user";
private static final String ROLES =
"run_as_role:\n" +
" run_as: [ '" + SecuritySettingsSource.DEFAULT_USER_NAME + "', 'idontexist' ]\n";
" run_as: [ '" + SecuritySettingsSource.TEST_USER_NAME + "', 'idontexist' ]\n";
// indicates whether the RUN_AS_USER that is being authenticated is also a superuser
private static boolean runAsHasSuperUserRole;
@ -66,8 +66,8 @@ public class RunAsIntegTests extends SecurityIntegTestCase {
@Override
public String configUsers() {
return super.configUsers()
+ RUN_AS_USER + ":" + SecuritySettingsSource.DEFAULT_PASSWORD_HASHED + "\n"
+ TRANSPORT_CLIENT_USER + ":" + SecuritySettingsSource.DEFAULT_PASSWORD_HASHED + "\n";
+ RUN_AS_USER + ":" + SecuritySettingsSource.TEST_PASSWORD_HASHED + "\n"
+ TRANSPORT_CLIENT_USER + ":" + SecuritySettingsSource.TEST_PASSWORD_HASHED + "\n";
}
@Override
@ -89,7 +89,7 @@ public class RunAsIntegTests extends SecurityIntegTestCase {
public void testUserImpersonation() throws Exception {
try (TransportClient client = getTransportClient(Settings.builder()
.put(Security.USER_SETTING.getKey(), TRANSPORT_CLIENT_USER + ":" + SecuritySettingsSource.DEFAULT_PASSWORD).build())) {
.put(Security.USER_SETTING.getKey(), TRANSPORT_CLIENT_USER + ":" + SecuritySettingsSource.TEST_PASSWORD).build())) {
//ensure the client can connect
assertBusy(() -> assertThat(client.connectedNodes().size(), greaterThan(0)));
@ -104,7 +104,7 @@ public class RunAsIntegTests extends SecurityIntegTestCase {
// let's run as without authorization
try {
Map<String, String> headers = Collections.singletonMap(AuthenticationService.RUN_AS_USER_HEADER,
SecuritySettingsSource.DEFAULT_USER_NAME);
SecuritySettingsSource.TEST_USER_NAME);
client.filterWithHeader(headers)
.admin().cluster().prepareHealth().get();
fail("run as should be unauthorized for the transport client user");
@ -115,8 +115,8 @@ public class RunAsIntegTests extends SecurityIntegTestCase {
Map<String, String> headers = new HashMap<>();
headers.put("Authorization", UsernamePasswordToken.basicAuthHeaderValue(RUN_AS_USER,
new SecureString(SecuritySettingsSource.DEFAULT_PASSWORD.toCharArray())));
headers.put(AuthenticationService.RUN_AS_USER_HEADER, SecuritySettingsSource.DEFAULT_USER_NAME);
new SecureString(SecuritySettingsSource.TEST_PASSWORD.toCharArray())));
headers.put(AuthenticationService.RUN_AS_USER_HEADER, SecuritySettingsSource.TEST_USER_NAME);
// lets set the user
ClusterHealthResponse response = client.filterWithHeader(headers).admin().cluster().prepareHealth().get();
assertThat(response.isTimedOut(), is(false));
@ -129,8 +129,8 @@ public class RunAsIntegTests extends SecurityIntegTestCase {
getRestClient().performRequest("GET", "/_nodes",
new BasicHeader(UsernamePasswordToken.BASIC_AUTH_HEADER,
UsernamePasswordToken.basicAuthHeaderValue(TRANSPORT_CLIENT_USER,
DEFAULT_PASSWORD_SECURE_STRING)),
new BasicHeader(AuthenticationService.RUN_AS_USER_HEADER, SecuritySettingsSource.DEFAULT_USER_NAME));
TEST_PASSWORD_SECURE_STRING)),
new BasicHeader(AuthenticationService.RUN_AS_USER_HEADER, SecuritySettingsSource.TEST_USER_NAME));
fail("request should have failed");
} catch(ResponseException e) {
assertThat(e.getResponse().getStatusLine().getStatusCode(), is(403));
@ -142,7 +142,7 @@ public class RunAsIntegTests extends SecurityIntegTestCase {
getRestClient().performRequest("GET", "/_nodes",
new BasicHeader(UsernamePasswordToken.BASIC_AUTH_HEADER,
UsernamePasswordToken.basicAuthHeaderValue(RUN_AS_USER,
DEFAULT_PASSWORD_SECURE_STRING)));
TEST_PASSWORD_SECURE_STRING)));
fail("request should have failed");
} catch (ResponseException e) {
assertThat(e.getResponse().getStatusLine().getStatusCode(), is(403));
@ -153,14 +153,14 @@ public class RunAsIntegTests extends SecurityIntegTestCase {
Response response = getRestClient().performRequest("GET", "/_nodes",
new BasicHeader(UsernamePasswordToken.BASIC_AUTH_HEADER,
UsernamePasswordToken.basicAuthHeaderValue(RUN_AS_USER,
DEFAULT_PASSWORD_SECURE_STRING)),
new BasicHeader(AuthenticationService.RUN_AS_USER_HEADER, SecuritySettingsSource.DEFAULT_USER_NAME));
TEST_PASSWORD_SECURE_STRING)),
new BasicHeader(AuthenticationService.RUN_AS_USER_HEADER, SecuritySettingsSource.TEST_USER_NAME));
assertThat(response.getStatusLine().getStatusCode(), is(200));
}
public void testEmptyUserImpersonationHeader() throws Exception {
try (TransportClient client = getTransportClient(Settings.builder()
.put(Security.USER_SETTING.getKey(), TRANSPORT_CLIENT_USER + ":" + SecuritySettingsSource.DEFAULT_PASSWORD).build())) {
.put(Security.USER_SETTING.getKey(), TRANSPORT_CLIENT_USER + ":" + SecuritySettingsSource.TEST_PASSWORD).build())) {
//ensure the client can connect
awaitBusy(() -> {
return client.connectedNodes().size() > 0;
@ -169,7 +169,7 @@ public class RunAsIntegTests extends SecurityIntegTestCase {
try {
Map<String, String> headers = new HashMap<>();
headers.put("Authorization", UsernamePasswordToken.basicAuthHeaderValue(RUN_AS_USER,
new SecureString(SecuritySettingsSource.DEFAULT_PASSWORD.toCharArray())));
new SecureString(SecuritySettingsSource.TEST_PASSWORD.toCharArray())));
headers.put(AuthenticationService.RUN_AS_USER_HEADER, "");
client.filterWithHeader(headers).admin().cluster().prepareHealth().get();
@ -185,7 +185,7 @@ public class RunAsIntegTests extends SecurityIntegTestCase {
getRestClient().performRequest("GET", "/_nodes",
new BasicHeader(UsernamePasswordToken.BASIC_AUTH_HEADER,
UsernamePasswordToken.basicAuthHeaderValue(RUN_AS_USER,
DEFAULT_PASSWORD_SECURE_STRING)),
TEST_PASSWORD_SECURE_STRING)),
new BasicHeader(AuthenticationService.RUN_AS_USER_HEADER, ""));
fail("request should have failed");
} catch(ResponseException e) {
@ -195,7 +195,7 @@ public class RunAsIntegTests extends SecurityIntegTestCase {
public void testNonExistentRunAsUser() throws Exception {
try (TransportClient client = getTransportClient(Settings.builder()
.put(Security.USER_SETTING.getKey(), TRANSPORT_CLIENT_USER + ":" + SecuritySettingsSource.DEFAULT_PASSWORD).build())) {
.put(Security.USER_SETTING.getKey(), TRANSPORT_CLIENT_USER + ":" + SecuritySettingsSource.TEST_PASSWORD).build())) {
//ensure the client can connect
awaitBusy(() -> {
return client.connectedNodes().size() > 0;
@ -204,7 +204,7 @@ public class RunAsIntegTests extends SecurityIntegTestCase {
try {
Map<String, String> headers = new HashMap<>();
headers.put("Authorization", UsernamePasswordToken.basicAuthHeaderValue(RUN_AS_USER,
new SecureString(SecuritySettingsSource.DEFAULT_PASSWORD.toCharArray())));
new SecureString(SecuritySettingsSource.TEST_PASSWORD.toCharArray())));
headers.put(AuthenticationService.RUN_AS_USER_HEADER, "idontexist");
client.filterWithHeader(headers).admin().cluster().prepareHealth().get();
@ -220,7 +220,7 @@ public class RunAsIntegTests extends SecurityIntegTestCase {
getRestClient().performRequest("GET", "/_nodes",
new BasicHeader(UsernamePasswordToken.BASIC_AUTH_HEADER,
UsernamePasswordToken.basicAuthHeaderValue(RUN_AS_USER,
DEFAULT_PASSWORD_SECURE_STRING)),
TEST_PASSWORD_SECURE_STRING)),
new BasicHeader(AuthenticationService.RUN_AS_USER_HEADER, "idontexist"));
fail("request should have failed");
} catch (ResponseException e) {

View File

@ -50,8 +50,8 @@ public class TokenAuthIntegTests extends SecurityIntegTestCase {
SecurityClient securityClient = new SecurityClient(client);
CreateTokenResponse response = securityClient.prepareCreateToken()
.setGrantType("password")
.setUsername(SecuritySettingsSource.DEFAULT_USER_NAME)
.setPassword(new SecureString(SecuritySettingsSource.DEFAULT_PASSWORD.toCharArray()))
.setUsername(SecuritySettingsSource.TEST_USER_NAME)
.setPassword(new SecureString(SecuritySettingsSource.TEST_PASSWORD.toCharArray()))
.get();
Instant created = Instant.now();
@ -90,8 +90,8 @@ public class TokenAuthIntegTests extends SecurityIntegTestCase {
public void testExpireMultipleTimes() throws Exception {
CreateTokenResponse response = securityClient().prepareCreateToken()
.setGrantType("password")
.setUsername(SecuritySettingsSource.DEFAULT_USER_NAME)
.setPassword(new SecureString(SecuritySettingsSource.DEFAULT_PASSWORD.toCharArray()))
.setUsername(SecuritySettingsSource.TEST_USER_NAME)
.setPassword(new SecureString(SecuritySettingsSource.TEST_PASSWORD.toCharArray()))
.get();
InvalidateTokenResponse invalidateResponse = securityClient().prepareInvalidateToken(response.getTokenString()).get();

View File

@ -17,6 +17,7 @@ import org.elasticsearch.test.SecuritySettingsSource;
import org.elasticsearch.xpack.security.SecurityLifecycleService;
import org.elasticsearch.xpack.security.authc.support.CharArrays;
import org.elasticsearch.xpack.security.client.SecurityClient;
import org.junit.AfterClass;
import org.junit.BeforeClass;
import java.nio.charset.StandardCharsets;
@ -39,6 +40,11 @@ public class ESNativeMigrateToolTests extends NativeRealmIntegTestCase {
useSSL = randomBoolean();
}
@Override
public boolean shouldSetReservedUserPasswords() {
return false;
}
@Override
public Settings nodeSettings(int nodeOrdinal) {
logger.info("--> use SSL? {}", useSSL);

View File

@ -15,6 +15,7 @@ import org.elasticsearch.cli.Terminal.Verbosity;
import org.elasticsearch.common.Strings;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.env.Environment;
import org.elasticsearch.test.SecuritySettingsSource;
import org.elasticsearch.xpack.security.authz.RoleDescriptor;
import java.io.FileNotFoundException;
@ -104,9 +105,12 @@ public class ESNativeRealmMigrateToolTests extends CommandTestCase {
Files.createDirectories(xpackConfDir);
ESNativeRealmMigrateTool.MigrateUserOrRoles muor = new ESNativeRealmMigrateTool.MigrateUserOrRoles();
OptionSet options = muor.getParser().parse("-u", "elastic", "-p", "changeme", "-U", "http://localhost:9200");
OptionSet options = muor.getParser().parse("-u", "elastic", "-p", SecuritySettingsSource.TEST_PASSWORD,
"-U", "http://localhost:9200");
Settings settings = Settings.builder().put("path.home", homeDir).build();
Environment environment = new Environment(settings, confDir);
MockTerminal mockTerminal = new MockTerminal();
FileNotFoundException fnfe = expectThrows(FileNotFoundException.class,

View File

@ -252,13 +252,13 @@ public class NativeRealmIntegTests extends NativeRealmIntegTestCase {
public void testUpdatingUserAndAuthentication() throws Exception {
SecurityClient c = securityClient();
logger.error("--> creating user");
c.preparePutUser("joe", "s3krit".toCharArray(), SecuritySettingsSource.DEFAULT_ROLE).get();
c.preparePutUser("joe", "s3krit".toCharArray(), SecuritySettingsSource.TEST_ROLE).get();
logger.error("--> waiting for .security index");
ensureGreen(SecurityLifecycleService.SECURITY_INDEX_NAME);
logger.info("--> retrieving user");
GetUsersResponse resp = c.prepareGetUsers("joe").get();
assertTrue("user should exist", resp.hasUsers());
assertThat(resp.users()[0].roles(), arrayContaining(SecuritySettingsSource.DEFAULT_ROLE));
assertThat(resp.users()[0].roles(), arrayContaining(SecuritySettingsSource.TEST_ROLE));
createIndex("idx");
ensureGreen("idx");
@ -269,7 +269,7 @@ public class NativeRealmIntegTests extends NativeRealmIntegTestCase {
assertEquals(searchResp.getHits().getTotalHits(), 1L);
c.preparePutUser("joe", "s3krit2".toCharArray(), SecuritySettingsSource.DEFAULT_ROLE).get();
c.preparePutUser("joe", "s3krit2".toCharArray(), SecuritySettingsSource.TEST_ROLE).get();
try {
client().filterWithHeader(Collections.singletonMap("Authorization", token)).prepareSearch("idx").get();
@ -287,13 +287,13 @@ public class NativeRealmIntegTests extends NativeRealmIntegTestCase {
public void testCreateDeleteAuthenticate() {
SecurityClient c = securityClient();
logger.error("--> creating user");
c.preparePutUser("joe", "s3krit".toCharArray(), SecuritySettingsSource.DEFAULT_ROLE).get();
c.preparePutUser("joe", "s3krit".toCharArray(), SecuritySettingsSource.TEST_ROLE).get();
logger.error("--> waiting for .security index");
ensureGreen(SecurityLifecycleService.SECURITY_INDEX_NAME);
logger.info("--> retrieving user");
GetUsersResponse resp = c.prepareGetUsers("joe").get();
assertTrue("user should exist", resp.hasUsers());
assertThat(resp.users()[0].roles(), arrayContaining(SecuritySettingsSource.DEFAULT_ROLE));
assertThat(resp.users()[0].roles(), arrayContaining(SecuritySettingsSource.TEST_ROLE));
createIndex("idx");
ensureGreen("idx");
@ -417,9 +417,9 @@ public class NativeRealmIntegTests extends NativeRealmIntegTestCase {
assertThat(client.prepareGetUsers("joes").get().hasUsers(), is(false));
// create joe with a password and verify the user works
client.preparePutUser("joe", "changeme".toCharArray(), "admin_role").get();
client.preparePutUser("joe", SecuritySettingsSource.TEST_PASSWORD.toCharArray(), "admin_role").get();
assertThat(client.prepareGetUsers("joe").get().hasUsers(), is(true));
final String token = basicAuthHeaderValue("joe", new SecureString("changeme".toCharArray()));
final String token = basicAuthHeaderValue("joe", SecuritySettingsSource.TEST_PASSWORD_SECURE_STRING);
ClusterHealthResponse response = client().filterWithHeader(Collections.singletonMap("Authorization", token)).admin().cluster()
.prepareHealth().get();
assertFalse(response.isTimedOut());
@ -445,7 +445,8 @@ public class NativeRealmIntegTests extends NativeRealmIntegTestCase {
}
// update the user with password and admin role again
client.preparePutUser("joe", "changeme2".toCharArray(), "admin_role").fullName("Joe Smith").get();
String secondPassword = SecuritySettingsSource.TEST_PASSWORD + "2";
client.preparePutUser("joe", secondPassword.toCharArray(), "admin_role").fullName("Joe Smith").get();
getUsersResponse = client.prepareGetUsers("joe").get();
assertThat(getUsersResponse.hasUsers(), is(true));
assertThat(getUsersResponse.users().length, is(1));
@ -465,7 +466,7 @@ public class NativeRealmIntegTests extends NativeRealmIntegTestCase {
response = client()
.filterWithHeader(
Collections.singletonMap("Authorization",
basicAuthHeaderValue("joe", new SecureString("changeme2".toCharArray()))))
basicAuthHeaderValue("joe", new SecureString(secondPassword.toCharArray()))))
.admin().cluster().prepareHealth().get();
assertFalse(response.isTimedOut());
}
@ -493,7 +494,7 @@ public class NativeRealmIntegTests extends NativeRealmIntegTestCase {
SecurityClient client = securityClient();
if (randomBoolean()) {
client.preparePutUser("joe", "s3krit".toCharArray(), SecuritySettingsSource.DEFAULT_ROLE).get();
client.preparePutUser("joe", "s3krit".toCharArray(), SecuritySettingsSource.TEST_ROLE).get();
} else {
client.preparePutRole("read_role")
.cluster("none")
@ -512,7 +513,8 @@ public class NativeRealmIntegTests extends NativeRealmIntegTestCase {
public void testOperationsOnReservedUsers() throws Exception {
final String username = randomFrom(ElasticUser.NAME, KibanaUser.NAME);
IllegalArgumentException exception = expectThrows(IllegalArgumentException.class,
() -> securityClient().preparePutUser(username, randomBoolean() ? "changeme".toCharArray() : null, "admin").get());
() -> securityClient().preparePutUser(username, randomBoolean() ? SecuritySettingsSource.TEST_PASSWORD.toCharArray()
: null, "admin").get());
assertThat(exception.getMessage(), containsString("Username [" + username + "] is reserved"));
exception = expectThrows(IllegalArgumentException.class,
@ -551,7 +553,7 @@ public class NativeRealmIntegTests extends NativeRealmIntegTestCase {
// authenticate should work
AuthenticateResponse authenticateResponse = client()
.filterWithHeader(Collections.singletonMap("Authorization",
basicAuthHeaderValue(username, new SecureString("changeme".toCharArray()))))
basicAuthHeaderValue(username, getReservedPassword())))
.execute(AuthenticateAction.INSTANCE, new AuthenticateRequest(username))
.get();
assertThat(authenticateResponse.user().principal(), is(username));
@ -574,7 +576,7 @@ public class NativeRealmIntegTests extends NativeRealmIntegTestCase {
}
public void testCreateAndChangePassword() throws Exception {
securityClient().preparePutUser("joe", "s3krit".toCharArray(), SecuritySettingsSource.DEFAULT_ROLE).get();
securityClient().preparePutUser("joe", "s3krit".toCharArray(), SecuritySettingsSource.TEST_ROLE).get();
final String token = basicAuthHeaderValue("joe", new SecureString("s3krit".toCharArray()));
ClusterHealthResponse response = client().filterWithHeader(Collections.singletonMap("Authorization", token))
.admin().cluster().prepareHealth().get();
@ -582,7 +584,7 @@ public class NativeRealmIntegTests extends NativeRealmIntegTestCase {
ChangePasswordResponse passwordResponse = securityClient(
client().filterWithHeader(Collections.singletonMap("Authorization", token)))
.prepareChangePassword("joe", "changeme".toCharArray())
.prepareChangePassword("joe", SecuritySettingsSource.TEST_PASSWORD.toCharArray())
.get();
assertThat(passwordResponse, notNullValue());
@ -594,7 +596,7 @@ public class NativeRealmIntegTests extends NativeRealmIntegTestCase {
response = client()
.filterWithHeader(
Collections.singletonMap("Authorization",
basicAuthHeaderValue("joe", new SecureString("changeme".toCharArray()))))
basicAuthHeaderValue("joe", SecuritySettingsSource.TEST_PASSWORD_SECURE_STRING)))
.admin().cluster().prepareHealth().get();
assertThat(response.isTimedOut(), is(false));
}
@ -660,7 +662,7 @@ public class NativeRealmIntegTests extends NativeRealmIntegTestCase {
}
public void testSetEnabled() throws Exception {
securityClient().preparePutUser("joe", "s3krit".toCharArray(), SecuritySettingsSource.DEFAULT_ROLE).get();
securityClient().preparePutUser("joe", "s3krit".toCharArray(), SecuritySettingsSource.TEST_ROLE).get();
final String token = basicAuthHeaderValue("joe", new SecureString("s3krit".toCharArray()));
ClusterHealthResponse response = client().filterWithHeader(Collections.singletonMap("Authorization", token))
.admin().cluster().prepareHealth().get();
@ -720,7 +722,7 @@ public class NativeRealmIntegTests extends NativeRealmIntegTestCase {
* the loader returned a null value, while the other caller(s) would get a null value unexpectedly
*/
public void testConcurrentRunAs() throws Exception {
securityClient().preparePutUser("joe", "s3krit".toCharArray(), SecuritySettingsSource.DEFAULT_ROLE).get();
securityClient().preparePutUser("joe", "s3krit".toCharArray(), SecuritySettingsSource.TEST_ROLE).get();
securityClient().preparePutUser("executor", "s3krit".toCharArray(), "superuser").get();
final String token = basicAuthHeaderValue("executor", new SecureString("s3krit".toCharArray()));
final Client client = client().filterWithHeader(MapBuilder.<String, String>newMapBuilder()

View File

@ -168,7 +168,7 @@ public class NativeRealmMigratorTests extends ESTestCase {
this.reservedUsers = Collections.singletonMap(
KibanaUser.NAME,
MapBuilder.<String, Object>newMapBuilder()
.put(User.Fields.PASSWORD.getPreferredName(), new String(Hasher.BCRYPT.hash(ReservedRealm.DEFAULT_PASSWORD_TEXT)))
.put(User.Fields.PASSWORD.getPreferredName(), new String(Hasher.BCRYPT.hash(ReservedRealm.EMPTY_PASSWORD_TEXT)))
.put(User.Fields.ENABLED.getPreferredName(), false)
.immutableMap()
);
@ -181,7 +181,7 @@ public class NativeRealmMigratorTests extends ESTestCase {
this.reservedUsers = Collections.singletonMap(
KibanaUser.NAME,
MapBuilder.<String, Object>newMapBuilder()
.put(User.Fields.PASSWORD.getPreferredName(), new String(Hasher.BCRYPT.hash(ReservedRealm.DEFAULT_PASSWORD_TEXT)))
.put(User.Fields.PASSWORD.getPreferredName(), new String(Hasher.BCRYPT.hash(ReservedRealm.EMPTY_PASSWORD_TEXT)))
.put(User.Fields.ENABLED.getPreferredName(), false)
.immutableMap()
);
@ -195,7 +195,7 @@ public class NativeRealmMigratorTests extends ESTestCase {
.stream().collect(Collectors.toMap(Function.identity(),
name -> MapBuilder.<String, Object>newMapBuilder()
.put(User.Fields.PASSWORD.getPreferredName(),
new String(Hasher.BCRYPT.hash(ReservedRealm.DEFAULT_PASSWORD_TEXT)))
new String(Hasher.BCRYPT.hash(ReservedRealm.EMPTY_PASSWORD_TEXT)))
.put(User.Fields.ENABLED.getPreferredName(), randomBoolean())
.immutableMap()
));

View File

@ -111,9 +111,9 @@ public class NativeUsersStoreTests extends ESTestCase {
actionRespond(GetRequest.class, new GetResponse(result));
final NativeUsersStore.ReservedUserInfo userInfo = future.get();
assertThat(userInfo.hasDefaultPassword, equalTo(true));
assertThat(userInfo.hasEmptyPassword, equalTo(true));
assertThat(userInfo.enabled, equalTo(true));
assertThat(userInfo.passwordHash, equalTo(ReservedRealm.DEFAULT_PASSWORD_HASH));
assertThat(userInfo.passwordHash, equalTo(ReservedRealm.EMPTY_PASSWORD_HASH));
}
public void testInContainerTrueReturnsEmptyPasswordForNonElasticReservedUsers() throws Exception {
@ -142,9 +142,9 @@ public class NativeUsersStoreTests extends ESTestCase {
actionRespond(GetRequest.class, new GetResponse(result));
final NativeUsersStore.ReservedUserInfo userInfo = future.get();
assertThat(userInfo.hasDefaultPassword, equalTo(true));
assertThat(userInfo.hasEmptyPassword, equalTo(true));
assertThat(userInfo.enabled, equalTo(true));
assertThat(userInfo.passwordHash, equalTo(ReservedRealm.DEFAULT_PASSWORD_HASH));
assertThat(userInfo.passwordHash, equalTo(ReservedRealm.EMPTY_PASSWORD_HASH));
}
public void testInContainerTrueReturnsBootstrapPasswordForElastic() throws Exception {
@ -171,7 +171,7 @@ public class NativeUsersStoreTests extends ESTestCase {
actionRespond(GetRequest.class, new GetResponse(result));
final NativeUsersStore.ReservedUserInfo userInfo = future.get();
assertThat(userInfo.hasDefaultPassword, equalTo(false));
assertThat(userInfo.hasEmptyPassword, equalTo(false));
assertThat(userInfo.enabled, equalTo(true));
assertThat(userInfo.passwordHash, equalTo(passwordHash));
}

View File

@ -8,11 +8,13 @@ package org.elasticsearch.xpack.security.authc.esnative;
import org.elasticsearch.ElasticsearchSecurityException;
import org.elasticsearch.action.admin.cluster.health.ClusterHealthResponse;
import org.elasticsearch.common.settings.SecureString;
import org.elasticsearch.test.NativeRealmIntegTestCase;
import org.elasticsearch.xpack.security.action.user.ChangePasswordResponse;
import org.elasticsearch.xpack.security.client.SecurityClient;
import org.elasticsearch.xpack.security.user.BeatsSystemUser;
import org.elasticsearch.xpack.security.user.ElasticUser;
import org.elasticsearch.xpack.security.user.KibanaUser;
import org.elasticsearch.xpack.security.action.user.ChangePasswordResponse;
import org.elasticsearch.test.NativeRealmIntegTestCase;
import org.elasticsearch.xpack.security.user.LogstashSystemUser;
import java.util.Arrays;
@ -27,12 +29,10 @@ import static org.hamcrest.Matchers.notNullValue;
*/
public class ReservedRealmIntegTests extends NativeRealmIntegTestCase {
private static final SecureString DEFAULT_PASSWORD = new SecureString("changeme".toCharArray());
public void testAuthenticate() {
for (String username : Arrays.asList(ElasticUser.NAME, KibanaUser.NAME)) {
for (String username : Arrays.asList(ElasticUser.NAME, KibanaUser.NAME, BeatsSystemUser.NAME, LogstashSystemUser.NAME)) {
ClusterHealthResponse response = client()
.filterWithHeader(singletonMap("Authorization", basicAuthHeaderValue(username, DEFAULT_PASSWORD)))
.filterWithHeader(singletonMap("Authorization", basicAuthHeaderValue(username, getReservedPassword())))
.admin()
.cluster()
.prepareHealth()
@ -43,15 +43,15 @@ public class ReservedRealmIntegTests extends NativeRealmIntegTestCase {
}
/**
* Enabling a user forces a doc to be written to the security index, and "user doc with default password" has a special case code in
* Enabling a user forces a doc to be written to the security index, and "user doc with empty password" has a special case code in
* the reserved realm.
*/
public void testAuthenticateAfterEnablingUser() {
final SecurityClient c = securityClient();
for (String username : Arrays.asList(ElasticUser.NAME, KibanaUser.NAME)) {
for (String username : Arrays.asList(ElasticUser.NAME, KibanaUser.NAME, BeatsSystemUser.NAME, LogstashSystemUser.NAME)) {
c.prepareSetEnabled(username, true).get();
ClusterHealthResponse response = client()
.filterWithHeader(singletonMap("Authorization", basicAuthHeaderValue(username, DEFAULT_PASSWORD)))
.filterWithHeader(singletonMap("Authorization", basicAuthHeaderValue(username, getReservedPassword())))
.admin()
.cluster()
.prepareHealth()
@ -62,12 +62,12 @@ public class ReservedRealmIntegTests extends NativeRealmIntegTestCase {
}
public void testChangingPassword() {
String username = randomFrom(ElasticUser.NAME, KibanaUser.NAME);
String username = randomFrom(ElasticUser.NAME, KibanaUser.NAME, BeatsSystemUser.NAME, LogstashSystemUser.NAME);
final char[] newPassword = "supersecretvalue".toCharArray();
if (randomBoolean()) {
ClusterHealthResponse response = client()
.filterWithHeader(singletonMap("Authorization", basicAuthHeaderValue(username, DEFAULT_PASSWORD)))
.filterWithHeader(singletonMap("Authorization", basicAuthHeaderValue(username, getReservedPassword())))
.admin()
.cluster()
.prepareHealth()
@ -81,7 +81,7 @@ public class ReservedRealmIntegTests extends NativeRealmIntegTestCase {
assertThat(response, notNullValue());
ElasticsearchSecurityException elasticsearchSecurityException = expectThrows(ElasticsearchSecurityException.class, () -> client()
.filterWithHeader(singletonMap("Authorization", basicAuthHeaderValue(username, DEFAULT_PASSWORD)))
.filterWithHeader(singletonMap("Authorization", basicAuthHeaderValue(username, getReservedPassword())))
.admin()
.cluster()
.prepareHealth()
@ -100,7 +100,7 @@ public class ReservedRealmIntegTests extends NativeRealmIntegTestCase {
public void testDisablingUser() throws Exception {
// validate the user works
ClusterHealthResponse response = client()
.filterWithHeader(singletonMap("Authorization", basicAuthHeaderValue(ElasticUser.NAME, DEFAULT_PASSWORD)))
.filterWithHeader(singletonMap("Authorization", basicAuthHeaderValue(ElasticUser.NAME, getReservedPassword())))
.admin()
.cluster()
.prepareHealth()
@ -110,7 +110,7 @@ public class ReservedRealmIntegTests extends NativeRealmIntegTestCase {
// disable user
securityClient().prepareSetEnabled(ElasticUser.NAME, false).get();
ElasticsearchSecurityException elasticsearchSecurityException = expectThrows(ElasticsearchSecurityException.class, () -> client()
.filterWithHeader(singletonMap("Authorization", basicAuthHeaderValue(ElasticUser.NAME, DEFAULT_PASSWORD)))
.filterWithHeader(singletonMap("Authorization", basicAuthHeaderValue(ElasticUser.NAME, getReservedPassword())))
.admin()
.cluster()
.prepareHealth()
@ -120,7 +120,7 @@ public class ReservedRealmIntegTests extends NativeRealmIntegTestCase {
//enable
securityClient().prepareSetEnabled(ElasticUser.NAME, true).get();
response = client()
.filterWithHeader(singletonMap("Authorization", basicAuthHeaderValue(ElasticUser.NAME, DEFAULT_PASSWORD)))
.filterWithHeader(singletonMap("Authorization", basicAuthHeaderValue(ElasticUser.NAME, getReservedPassword())))
.admin()
.cluster()
.prepareHealth()

View File

@ -1,64 +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.esnative;
import org.elasticsearch.ElasticsearchSecurityException;
import org.elasticsearch.action.admin.cluster.health.ClusterHealthResponse;
import org.elasticsearch.common.settings.SecureString;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.test.NativeRealmIntegTestCase;
import org.elasticsearch.xpack.security.client.SecurityClient;
import org.elasticsearch.xpack.security.user.KibanaUser;
import static java.util.Collections.singletonMap;
import static org.elasticsearch.xpack.security.authc.support.UsernamePasswordToken.basicAuthHeaderValue;
import static org.hamcrest.Matchers.containsString;
import static org.hamcrest.Matchers.is;
/**
* Integration tests for the built in realm with default passwords disabled
*/
public class ReservedRealmNoDefaultPasswordIntegTests extends NativeRealmIntegTestCase {
private static final SecureString DEFAULT_PASSWORD = new SecureString("changeme".toCharArray());
@Override
protected Settings nodeSettings(int nodeOrdinal) {
Settings.Builder builder = Settings.builder()
.put(super.nodeSettings(nodeOrdinal))
.put(ReservedRealm.ACCEPT_DEFAULT_PASSWORD_SETTING.getKey(), false);
return builder.build();
}
/**
* This ensures that if a user is explicitly enabled, thus creating an entry in the security index, but no password is ever set,
* then the user is treated as having a default password, and cannot login.
*/
public void testEnablingUserWithoutPasswordCannotLogin() throws Exception {
final SecurityClient c = securityClient();
c.prepareSetEnabled(KibanaUser.NAME, true).get();
ElasticsearchSecurityException elasticsearchSecurityException = expectThrows(ElasticsearchSecurityException.class, () -> client()
.filterWithHeader(singletonMap("Authorization", basicAuthHeaderValue(KibanaUser.NAME, DEFAULT_PASSWORD)))
.admin()
.cluster()
.prepareHealth()
.get());
assertThat(elasticsearchSecurityException.getMessage(), containsString("authenticate"));
final SecureString newPassword = new SecureString("not-the-default-password".toCharArray());
c.prepareChangePassword(KibanaUser.NAME, newPassword.clone().getChars()).get();
ClusterHealthResponse response = client()
.filterWithHeader(singletonMap("Authorization", basicAuthHeaderValue(KibanaUser.NAME, newPassword)))
.admin()
.cluster()
.prepareHealth()
.get();
assertThat(response.getClusterName(), is(cluster().getClusterName()));
}
}

View File

@ -9,6 +9,7 @@ import org.elasticsearch.ElasticsearchSecurityException;
import org.elasticsearch.Version;
import org.elasticsearch.action.ActionListener;
import org.elasticsearch.action.support.PlainActionFuture;
import org.elasticsearch.common.SuppressForbidden;
import org.elasticsearch.common.settings.SecureString;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.common.util.concurrent.ThreadContext;
@ -16,6 +17,7 @@ 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.IncomingRequest;
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;
@ -28,6 +30,9 @@ 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.net.UnknownHostException;
import java.util.Collection;
import java.util.Collections;
import java.util.Map;
@ -58,62 +63,38 @@ import static org.mockito.Mockito.when;
*/
public class ReservedRealmTests extends ESTestCase {
private static final SecureString DEFAULT_PASSWORD = new SecureString("changeme".toCharArray());
private static final SecureString EMPTY_PASSWORD = new SecureString("".toCharArray());
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());
}
public void testMappingVersionFromBeforeUserExisted() throws ExecutionException, InterruptedException {
@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 = randomFrom(ElasticUser.NAME, KibanaUser.NAME, LogstashSystemUser.NAME);
final String principal = ElasticUser.NAME;
PlainActionFuture<User> future = new PlainActionFuture<>();
reservedRealm.authenticate(new UsernamePasswordToken(principal, DEFAULT_PASSWORD), future);
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().enabled(), equalTo(false));
}
public void testSuccessfulDefaultPasswordAuthentication() throws Throwable {
final User expected = randomFrom(new ElasticUser(true), new KibanaUser(true), new LogstashSystemUser(true));
final String principal = expected.principal();
final boolean securityIndexExists = randomBoolean();
if (securityIndexExists) {
when(securityLifecycleService.isSecurityIndexExisting()).thenReturn(true);
doAnswer((i) -> {
ActionListener listener = (ActionListener) i.getArguments()[1];
listener.onResponse(null);
return null;
}).when(usersStore).getReservedUserInfo(eq(principal), any(ActionListener.class));
}
final ReservedRealm reservedRealm =
new ReservedRealm(mock(Environment.class), Settings.EMPTY, usersStore,
new AnonymousUser(Settings.EMPTY), securityLifecycleService, new ThreadContext(Settings.EMPTY));
PlainActionFuture<User> listener = new PlainActionFuture<>();
reservedRealm.doAuthenticate(new UsernamePasswordToken(principal, DEFAULT_PASSWORD), listener);
final User authenticated = listener.actionGet();
assertEquals(expected, authenticated);
verify(securityLifecycleService).isSecurityIndexExisting();
if (securityIndexExists) {
verify(usersStore).getReservedUserInfo(eq(principal), any(ActionListener.class));
}
final ArgumentCaptor<Predicate> predicateCaptor = ArgumentCaptor.forClass(Predicate.class);
verify(securityLifecycleService).checkSecurityMappingVersion(predicateCaptor.capture());
verifyVersionPredicate(principal, predicateCaptor.getValue());
verifyNoMoreInteractions(usersStore);
}
public void testDisableDefaultPasswordAuthentication() throws Throwable {
final User expected = randomFrom(new ElasticUser(true), new KibanaUser(true), new LogstashSystemUser(true));
@ -135,7 +116,51 @@ public class ReservedRealmTests extends ESTestCase {
assertThat(e.getMessage(), containsString("failed to authenticate"));
}
};
reservedRealm.doAuthenticate(new UsernamePasswordToken(expected.principal(), DEFAULT_PASSWORD), listener);
reservedRealm.doAuthenticate(new UsernamePasswordToken(expected.principal(), EMPTY_PASSWORD), listener, incomingRequest);
}
public void testElasticEmptyPasswordAuthenticationFailsFromNonLocalhost() throws Throwable {
final User expected = new ElasticUser(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<User> 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);
ElasticsearchSecurityException actual = expectThrows(ElasticsearchSecurityException.class, listener::actionGet);
assertThat(actual.getMessage(), containsString("failed to authenticate user [" + 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<User> 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();
assertEquals(expected, user);
assertNotEquals(new ElasticUser(true, false), user);
}
public void testAuthenticationDisabled() throws Throwable {
@ -151,7 +176,7 @@ public class ReservedRealmTests extends ESTestCase {
final String principal = expected.principal();
PlainActionFuture<User> listener = new PlainActionFuture<>();
reservedRealm.doAuthenticate(new UsernamePasswordToken(principal, DEFAULT_PASSWORD), listener);
reservedRealm.doAuthenticate(new UsernamePasswordToken(principal, EMPTY_PASSWORD), listener, mock(IncomingRequest.class));
final User authenticated = listener.actionGet();
assertNull(authenticated);
verifyZeroInteractions(usersStore);
@ -179,9 +204,9 @@ public class ReservedRealmTests extends ESTestCase {
return null;
}).when(usersStore).getReservedUserInfo(eq(principal), any(ActionListener.class));
// test default password
// test empty password
final PlainActionFuture<User> listener = new PlainActionFuture<>();
reservedRealm.doAuthenticate(new UsernamePasswordToken(principal, DEFAULT_PASSWORD), listener);
reservedRealm.doAuthenticate(new UsernamePasswordToken(principal, EMPTY_PASSWORD), listener, incomingRequest);
ElasticsearchSecurityException expected = expectThrows(ElasticsearchSecurityException.class, listener::actionGet);
assertThat(expected.getMessage(), containsString("failed to authenticate user [" + principal));
@ -194,7 +219,7 @@ public class ReservedRealmTests extends ESTestCase {
// test new password
final PlainActionFuture<User> authListener = new PlainActionFuture<>();
reservedRealm.doAuthenticate(new UsernamePasswordToken(principal, newPassword), authListener);
reservedRealm.doAuthenticate(new UsernamePasswordToken(principal, newPassword), authListener, incomingRequest);
final User authenticated = authListener.actionGet();
assertEquals(expectedUser, authenticated);
assertThat(expectedUser.enabled(), is(enabled));
@ -211,7 +236,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), new KibanaUser(true), new LogstashSystemUser(true));
final User expectedUser = randomFrom(new ElasticUser(true, true), new KibanaUser(true), new LogstashSystemUser(true));
final String principal = expectedUser.principal();
PlainActionFuture<User> listener = new PlainActionFuture<>();
@ -299,7 +324,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), new KibanaUser(true),
assertThat(userFuture.actionGet(), containsInAnyOrder(new ElasticUser(true, true), new KibanaUser(true),
new LogstashSystemUser(true), new BeatsSystemUser(true)));
}
@ -321,19 +346,29 @@ public class ReservedRealmTests extends ESTestCase {
}
}
public void testFailedAuthentication() {
@SuppressForbidden(reason = "allow getting localhost")
public void testFailedAuthentication() throws UnknownHostException {
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<User> future = new PlainActionFuture<>();
reservedRealm.authenticate(new UsernamePasswordToken(ElasticUser.NAME, new SecureString("changeme".toCharArray())), future);
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);
User user = future.actionGet();
assertEquals(new ElasticUser(true), user);
assertEquals(new ElasticUser(true, true), user);
}
PlainActionFuture<User> future = new PlainActionFuture<>();
reservedRealm.authenticate(new UsernamePasswordToken(ElasticUser.NAME, new SecureString("foobar".toCharArray())), future);
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);
ElasticsearchSecurityException e = expectThrows(ElasticsearchSecurityException.class, future::actionGet);
assertThat(e.getMessage(), containsString("failed to authenticate"));
}

View File

@ -61,7 +61,7 @@ public class SetupPasswordToolTests extends CommandTestCase {
execute("auto", pathHomeParameter, "-b", "true");
ArgumentCaptor<String> passwordCaptor = ArgumentCaptor.forClass(String.class);
SecureString defaultPassword = new SecureString("changeme".toCharArray());
SecureString defaultPassword = new SecureString("".toCharArray());
InOrder inOrder = Mockito.inOrder(httpClient);
String elasticUrl = "http://localhost:9200/_xpack/security/user/elastic/_password";
@ -80,7 +80,7 @@ public class SetupPasswordToolTests extends CommandTestCase {
execute("auto", pathHomeParameter, "-u", url, "-b");
ArgumentCaptor<String> passwordCaptor = ArgumentCaptor.forClass(String.class);
SecureString defaultPassword = new SecureString("changeme".toCharArray());
SecureString defaultPassword = new SecureString("".toCharArray());
InOrder inOrder = Mockito.inOrder(httpClient);
String elasticUrl = url + "/_xpack/security/user/elastic/_password";
@ -99,7 +99,7 @@ public class SetupPasswordToolTests extends CommandTestCase {
execute("interactive", pathHomeParameter);
SecureString defaultPassword = new SecureString("changeme".toCharArray());
SecureString defaultPassword = new SecureString("".toCharArray());
InOrder inOrder = Mockito.inOrder(httpClient);
String elasticUrl = "http://localhost:9200/_xpack/security/user/elastic/_password";

View File

@ -10,6 +10,7 @@ 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.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;
@ -53,7 +54,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<User> future = new PlainActionFuture<>();
realm.authenticate(new UsernamePasswordToken("user1", new SecureString("test123")), future);
realm.authenticate(new UsernamePasswordToken("user1", new SecureString("test123")), future, mock(IncomingRequest.class));
User user = future.actionGet();
assertThat(user, notNullValue());
assertThat(user.principal(), equalTo("user1"));
@ -71,10 +72,10 @@ public class FileRealmTests extends ESTestCase {
when(userRolesStore.roles("user1")).thenReturn(new String[]{"role1", "role2"});
FileRealm realm = new FileRealm(config, userPasswdStore, userRolesStore);
PlainActionFuture<User> future = new PlainActionFuture<>();
realm.authenticate(new UsernamePasswordToken("user1", new SecureString("test123")), future);
realm.authenticate(new UsernamePasswordToken("user1", new SecureString("test123")), future, mock(IncomingRequest.class));
User user1 = future.actionGet();
future = new PlainActionFuture<>();
realm.authenticate(new UsernamePasswordToken("user1", new SecureString("test123")), future);
realm.authenticate(new UsernamePasswordToken("user1", new SecureString("test123")), future, mock(IncomingRequest.class));
User user2 = future.actionGet();
assertThat(user1, sameInstance(user2));
}
@ -87,32 +88,32 @@ public class FileRealmTests extends ESTestCase {
doReturn(new String[] { "role1", "role2" }).when(userRolesStore).roles("user1");
FileRealm realm = new FileRealm(config, userPasswdStore, userRolesStore);
PlainActionFuture<User> future = new PlainActionFuture<>();
realm.authenticate(new UsernamePasswordToken("user1", new SecureString("test123")), future);
realm.authenticate(new UsernamePasswordToken("user1", new SecureString("test123")), future, mock(IncomingRequest.class));
User user1 = future.actionGet();
future = new PlainActionFuture<>();
realm.authenticate(new UsernamePasswordToken("user1", new SecureString("test123")), future);
realm.authenticate(new UsernamePasswordToken("user1", new SecureString("test123")), future, mock(IncomingRequest.class));
User user2 = future.actionGet();
assertThat(user1, sameInstance(user2));
userPasswdStore.notifyRefresh();
future = new PlainActionFuture<>();
realm.authenticate(new UsernamePasswordToken("user1", new SecureString("test123")), future);
realm.authenticate(new UsernamePasswordToken("user1", new SecureString("test123")), future, mock(IncomingRequest.class));
User user3 = future.actionGet();
assertThat(user2, not(sameInstance(user3)));
future = new PlainActionFuture<>();
realm.authenticate(new UsernamePasswordToken("user1", new SecureString("test123")), future);
realm.authenticate(new UsernamePasswordToken("user1", new SecureString("test123")), future, mock(IncomingRequest.class));
User user4 = future.actionGet();
assertThat(user3, sameInstance(user4));
userRolesStore.notifyRefresh();
future = new PlainActionFuture<>();
realm.authenticate(new UsernamePasswordToken("user1", new SecureString("test123")), future);
realm.authenticate(new UsernamePasswordToken("user1", new SecureString("test123")), future, mock(IncomingRequest.class));
User user5 = future.actionGet();
assertThat(user4, not(sameInstance(user5)));
future = new PlainActionFuture<>();
realm.authenticate(new UsernamePasswordToken("user1", new SecureString("test123")), future);
realm.authenticate(new UsernamePasswordToken("user1", new SecureString("test123")), future, mock(IncomingRequest.class));
User user6 = future.actionGet();
assertThat(user5, sameInstance(user6));
}

View File

@ -17,6 +17,7 @@ import org.elasticsearch.common.io.PathUtilsForTesting;
import org.elasticsearch.common.settings.SecureString;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.env.Environment;
import org.elasticsearch.test.SecuritySettingsSource;
import org.elasticsearch.xpack.XPackSettings;
import org.elasticsearch.xpack.security.authc.support.Hasher;
import org.elasticsearch.xpack.security.authz.store.ReservedRolesStore;
@ -64,10 +65,11 @@ public class UsersToolTests extends CommandTestCase {
IOUtils.rm(homeDir);
confDir = homeDir.resolve("config").resolve(XPackPlugin.NAME);
Files.createDirectories(confDir);
String defaultPassword = SecuritySettingsSource.TEST_PASSWORD;
Files.write(confDir.resolve("users"), Arrays.asList(
"existing_user:" + new String(Hasher.BCRYPT.hash(new SecureString("changeme".toCharArray()))),
"existing_user2:" + new String(Hasher.BCRYPT.hash(new SecureString("changeme2".toCharArray()))),
"existing_user3:" + new String(Hasher.BCRYPT.hash(new SecureString("changeme3".toCharArray())))
"existing_user:" + new String(Hasher.BCRYPT.hash(SecuritySettingsSource.TEST_PASSWORD_SECURE_STRING)),
"existing_user2:" + new String(Hasher.BCRYPT.hash(new SecureString((defaultPassword + "2").toCharArray()))),
"existing_user3:" + new String(Hasher.BCRYPT.hash(new SecureString((defaultPassword + "3").toCharArray())))
), StandardCharsets.UTF_8);
Files.write(confDir.resolve("users_roles"), Arrays.asList(
"test_admin:existing_user,existing_user2",
@ -268,20 +270,20 @@ public class UsersToolTests extends CommandTestCase {
}
public void testUseraddNoPassword() throws Exception {
terminal.addSecretInput("changeme");
terminal.addSecretInput("changeme");
terminal.addSecretInput(SecuritySettingsSource.TEST_PASSWORD);
terminal.addSecretInput(SecuritySettingsSource.TEST_PASSWORD);
execute("useradd", pathHomeParameter, fileTypeParameter, "username");
assertUser("username", "changeme");
assertUser("username", SecuritySettingsSource.TEST_PASSWORD);
}
public void testUseraddPasswordOption() throws Exception {
execute("useradd", pathHomeParameter, fileTypeParameter, "username", "-p", "changeme");
assertUser("username", "changeme");
execute("useradd", pathHomeParameter, fileTypeParameter, "username", "-p", SecuritySettingsSource.TEST_PASSWORD);
assertUser("username", SecuritySettingsSource.TEST_PASSWORD);
}
public void testUseraddUserExists() throws Exception {
UserException e = expectThrows(UserException.class, () -> {
execute("useradd", pathHomeParameter, fileTypeParameter, "existing_user", "-p", "changeme");
execute("useradd", pathHomeParameter, fileTypeParameter, "existing_user", "-p", SecuritySettingsSource.TEST_PASSWORD);
});
assertEquals(ExitCodes.CODE_ERROR, e.exitCode);
assertEquals("User [existing_user] already exists", e.getMessage());
@ -290,7 +292,7 @@ public class UsersToolTests extends CommandTestCase {
public void testUseraddReservedUser() throws Exception {
final String name = randomFrom(ElasticUser.NAME, KibanaUser.NAME);
UserException e = expectThrows(UserException.class, () -> {
execute("useradd", pathHomeParameter, fileTypeParameter, name, "-p", "changeme");
execute("useradd", pathHomeParameter, fileTypeParameter, name, "-p", SecuritySettingsSource.TEST_PASSWORD);
});
assertEquals(ExitCodes.DATA_ERROR, e.exitCode);
assertEquals("Invalid username [" + name + "]... Username [" + name + "] is reserved and may not be used.", e.getMessage());
@ -299,7 +301,7 @@ public class UsersToolTests extends CommandTestCase {
public void testUseraddNoRoles() throws Exception {
Files.delete(confDir.resolve("users_roles"));
Files.createFile(confDir.resolve("users_roles"));
execute("useradd", pathHomeParameter, fileTypeParameter, "username", "-p", "changeme");
execute("useradd", pathHomeParameter, fileTypeParameter, "username", "-p", SecuritySettingsSource.TEST_PASSWORD);
List<String> lines = Files.readAllLines(confDir.resolve("users_roles"), StandardCharsets.UTF_8);
assertTrue(lines.toString(), lines.isEmpty());
}
@ -319,7 +321,7 @@ public class UsersToolTests extends CommandTestCase {
public void testPasswdUnknownUser() throws Exception {
UserException e = expectThrows(UserException.class, () -> {
execute("passwd", pathHomeParameter, fileTypeParameter, "unknown", "-p", "changeme");
execute("passwd", pathHomeParameter, fileTypeParameter, "unknown", "-p", SecuritySettingsSource.TEST_PASSWORD);
});
assertEquals(ExitCodes.NO_USER, e.exitCode);
assertTrue(e.getMessage(), e.getMessage().contains("User [unknown] doesn't exist"));
@ -365,7 +367,8 @@ public class UsersToolTests extends CommandTestCase {
}
public void testRolesRemoveLeavesExisting() throws Exception {
execute("useradd", pathHomeParameter, fileTypeParameter, "username", "-p", "changeme", "-r", "test_admin");
execute("useradd", pathHomeParameter, fileTypeParameter, "username", "-p", SecuritySettingsSource.TEST_PASSWORD,
"-r", "test_admin");
execute("roles", pathHomeParameter, fileTypeParameter, "existing_user", "-r", "test_admin");
assertRole("test_admin", "username");
}
@ -407,7 +410,8 @@ public class UsersToolTests extends CommandTestCase {
}
public void testListUnknownRoles() throws Exception {
execute("useradd", pathHomeParameter, fileTypeParameter, "username", "-p", "changeme", "-r", "test_r1,r2,r3");
execute("useradd", pathHomeParameter, fileTypeParameter, "username", "-p", SecuritySettingsSource.TEST_PASSWORD,
"-r", "test_r1,r2,r3");
String output = execute("list", pathHomeParameter, fileTypeParameter, "username");
assertTrue(output, output.contains("username"));
assertTrue(output, output.contains("r2*,r3*,test_r1"));

View File

@ -19,6 +19,7 @@ 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.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;
@ -53,6 +54,7 @@ import static org.hamcrest.Matchers.is;
import static org.hamcrest.Matchers.notNullValue;
import static org.mockito.Matchers.any;
import static org.mockito.Matchers.eq;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
@ -138,7 +140,7 @@ public class ActiveDirectoryRealmTests extends ESTestCase {
LdapRealm realm = new LdapRealm(LdapRealm.AD_TYPE, config, sessionFactory, roleMapper, threadPool);
PlainActionFuture<User> future = new PlainActionFuture<>();
realm.authenticate(new UsernamePasswordToken("CN=ironman", new SecureString(PASSWORD)), future);
realm.authenticate(new UsernamePasswordToken("CN=ironman", new SecureString(PASSWORD)), future, mock(IncomingRequest.class));
User user = future.actionGet();
assertThat(user, is(notNullValue()));
assertThat(user.roles(), arrayContaining(containsString("Avengers")));
@ -153,7 +155,7 @@ public class ActiveDirectoryRealmTests extends ESTestCase {
// Thor does not have a UPN of form CN=Thor@ad.test.elasticsearch.com
PlainActionFuture<User> future = new PlainActionFuture<>();
realm.authenticate(new UsernamePasswordToken("CN=Thor", new SecureString(PASSWORD)), future);
realm.authenticate(new UsernamePasswordToken("CN=Thor", new SecureString(PASSWORD)), future, mock(IncomingRequest.class));
User user = future.actionGet();
assertThat(user, is(notNullValue()));
assertThat(user.roles(), arrayContaining(containsString("Avengers")));
@ -178,7 +180,7 @@ public class ActiveDirectoryRealmTests extends ESTestCase {
int count = randomIntBetween(2, 10);
for (int i = 0; i < count; i++) {
PlainActionFuture<User> future = new PlainActionFuture<>();
realm.authenticate(new UsernamePasswordToken("CN=ironman", new SecureString(PASSWORD)), future);
realm.authenticate(new UsernamePasswordToken("CN=ironman", new SecureString(PASSWORD)), future, mock(IncomingRequest.class));
future.actionGet();
}
@ -196,7 +198,7 @@ public class ActiveDirectoryRealmTests extends ESTestCase {
int count = randomIntBetween(2, 10);
for (int i = 0; i < count; i++) {
PlainActionFuture<User> future = new PlainActionFuture<>();
realm.authenticate(new UsernamePasswordToken("CN=ironman", new SecureString(PASSWORD)), future);
realm.authenticate(new UsernamePasswordToken("CN=ironman", new SecureString(PASSWORD)), future, mock(IncomingRequest.class));
future.actionGet();
}
@ -214,7 +216,7 @@ public class ActiveDirectoryRealmTests extends ESTestCase {
int count = randomIntBetween(2, 10);
for (int i = 0; i < count; i++) {
PlainActionFuture<User> future = new PlainActionFuture<>();
realm.authenticate(new UsernamePasswordToken("CN=ironman", new SecureString(PASSWORD)), future);
realm.authenticate(new UsernamePasswordToken("CN=ironman", new SecureString(PASSWORD)), future, mock(IncomingRequest.class));
future.actionGet();
}
@ -226,7 +228,7 @@ public class ActiveDirectoryRealmTests extends ESTestCase {
for (int i = 0; i < count; i++) {
PlainActionFuture<User> future = new PlainActionFuture<>();
realm.authenticate(new UsernamePasswordToken("CN=ironman", new SecureString(PASSWORD)), future);
realm.authenticate(new UsernamePasswordToken("CN=ironman", new SecureString(PASSWORD)), future, mock(IncomingRequest.class));
future.actionGet();
}
@ -243,7 +245,7 @@ public class ActiveDirectoryRealmTests extends ESTestCase {
LdapRealm realm = new LdapRealm(LdapRealm.AD_TYPE, config, sessionFactory, roleMapper, threadPool);
PlainActionFuture<User> future = new PlainActionFuture<>();
realm.authenticate(new UsernamePasswordToken("CN=ironman", new SecureString(PASSWORD)), future);
realm.authenticate(new UsernamePasswordToken("CN=ironman", new SecureString(PASSWORD)), future, mock(IncomingRequest.class));
User user = future.actionGet();
assertThat(user, is(notNullValue()));
assertThat(user.roles(), arrayContaining(equalTo("group_role")));
@ -259,7 +261,7 @@ public class ActiveDirectoryRealmTests extends ESTestCase {
LdapRealm realm = new LdapRealm(LdapRealm.AD_TYPE, config, sessionFactory, roleMapper, threadPool);
PlainActionFuture<User> future = new PlainActionFuture<>();
realm.authenticate(new UsernamePasswordToken("CN=Thor", new SecureString(PASSWORD)), future);
realm.authenticate(new UsernamePasswordToken("CN=Thor", new SecureString(PASSWORD)), future, mock(IncomingRequest.class));
User user = future.actionGet();
assertThat(user, is(notNullValue()));
assertThat(user.roles(), arrayContainingInAnyOrder(equalTo("group_role"), equalTo("user_role")));

Some files were not shown because too many files have changed in this diff Show More