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 { try {
httpURLConnection = (HttpURLConnection) new URL("http://${node.httpUri()}/_cluster/health").openConnection(); httpURLConnection = (HttpURLConnection) new URL("http://${node.httpUri()}/_cluster/health").openConnection();
httpURLConnection.setRequestProperty("Authorization", "Basic " + 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.setRequestMethod("GET");
httpURLConnection.setConnectTimeout(1000); httpURLConnection.setConnectTimeout(1000);
httpURLConnection.setReadTimeout(30000); httpURLConnection.setReadTimeout(30000);
@ -145,7 +145,7 @@ Closure waitWithAuth = { NodeInfo node, AntBuilder ant ->
integTestCluster { integTestCluster {
plugin ':x-pack-elasticsearch:plugin' plugin ':x-pack-elasticsearch:plugin'
setupCommand 'setupTestAdmin', 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 waitCondition = waitWithAuth
} }

View File

@ -6,7 +6,6 @@
:es-repo-dir: {docdir}/../../../../elasticsearch/docs :es-repo-dir: {docdir}/../../../../elasticsearch/docs
:es-test-dir: {docdir}/../../../../elasticsearch/docs/src/test :es-test-dir: {docdir}/../../../../elasticsearch/docs/src/test
:plugins-examples-dir: {docdir}/../../../../elasticsearch/plugins/examples :plugins-examples-dir: {docdir}/../../../../elasticsearch/plugins/examples
:docs-dir: {docdir}/../../../../docs
include::{es-repo-dir}/Versions.asciidoc[] 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. {dfeeds}, and results.
By default, you can perform all of the steps in this tutorial by using the 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 built-in `elastic` super user. However, the password must be set before the user
`changeme`. For information about how to change that password, see can do anything. For information about how to set that password, see
<<security-getting-started>>. <<security-getting-started>>.
If you are performing these steps in a production environment, take extra care If you are performing these steps in a production environment, take extra care
@ -191,7 +191,7 @@ mapping for the data set:
[source,shell] [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 '{ http://localhost:9200/server-metrics -d '{
"settings":{ "settings":{
"number_of_shards":1, "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. actual password.
//// ////
@ -247,16 +247,16 @@ example, which loads the four JSON files:
[source,shell] [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" 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" 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" 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" 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] [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: 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 POST _xpack/security/user/elastic/_password
{ {
"password": "changeme" "password": "x-pack-test-password"
} }
-------------------------------------------------- --------------------------------------------------
// CONSOLE // CONSOLE

View File

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

View File

@ -15,9 +15,11 @@ see <<managing-native-users, Managing Native Users>>.
=== Built-in Users === Built-in Users
{security} provides built-in user credentials to help you get up and running. {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`. These users have a fixed set of privileges and cannot be authenticated until their
Please read <<reset-built-in-user-passwords,Reset Built-in User Passwords>> and passwords have been set. The exception is the `elastic` user which can be authenticated
<<disabling-default-password, Disable Default Password Functionality>> below. 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 .{security} Built-in Users
|======== |========
@ -48,8 +50,7 @@ be disabled individually, using the
==== Reset Built-in User Passwords ==== Reset Built-in User Passwords
[IMPORTANT] [IMPORTANT]
============================================================================= =============================================================================
You must reset the default passwords for all built-in users, and then You must set the passwords for all built-in users.
<<disabling-default-password, disable default password support>>.
You can update passwords from the *Management > Users* UI in Kibana or with the 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]: {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 ==== Disable Default Password Functionality
[IMPORTANT] [IMPORTANT]
============================================================================= =============================================================================
The default password of `changeme` is provided as a convenience that allows you to quickly This setting is deprecated. The elastic user no longer has a default password. The password must
setup your Elasticsearch stack. It should not be used when running in production. be set before the user can be used.
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.
============================================================================= =============================================================================

View File

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

View File

@ -21,7 +21,7 @@ Run the migrate tool after you install the X-Pack plugin. For example:
[source, sh] [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 -n lee,foo -r role1,role2,role3,role4,foo
starting migration of users and roles... starting migration of users and roles...
importing users from [/home/es/config/shield/users]... 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] [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 type: pki
truststore: truststore:
path: "/path/to/pki_truststore.jks" path: "/path/to/pki_truststore.jks"
password: "changeme" password: "x-pack-test-password"
------------------------------------------------------------ ------------------------------------------------------------
. Restart Elasticsearch. . Restart Elasticsearch.

View File

@ -36,7 +36,8 @@ curl -XPUT -u elastic 'localhost:9200/_xpack/security/user/logstash_system/_pass
---------------------------------------------------------- ----------------------------------------------------------
// NOTCONSOLE // 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 // 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]]
. Enable Auditing to keep track of attempted and successful interactions with . Enable Auditing to keep track of attempted and successful interactions with
your Elasticsearch cluster: 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 Elasticsearch has built-in protections against accidental data loss and
corruption. However, there's nothing to stop deliberate tampering or data corruption. However, there's nothing to stop deliberate tampering or data
interception. {security} preserves the integrity of your data by interception. {security} preserves the integrity of your data by
<<ssl-tls, encrypting communications>> to and from nodes and <<ssl-tls, encrypting communications>> to and from nodes.
<<enable-message-authentication, authenticating messages>> to verify that they For even greater protection, you can increase the <<ciphers, encryption strength>> and
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
<<separating-node-client-traffic, separate client traffic from node-to-node communications>>. <<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 * `CONFIG_DIR/x-pack/log4j2.properties` contains audit information (read more
<<logging-file, here>>). <<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]] [[security-files-location]]
IMPORTANT: Any files that {security} uses must be stored in the Elasticsearch IMPORTANT: Any files that {security} uses must be stored in the Elasticsearch

View File

@ -102,7 +102,7 @@ March 15, 2016
.Bug Fixes .Bug Fixes
* Enable <<field-and-document-access-control,document and field level security>> by default. * 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. authentication codes.
* Built in <<setting-up-authentication, realms>> no longer throw an exception if the `Authorization` header does not contain a basic * Built in <<setting-up-authentication, realms>> no longer throw an exception if the `Authorization` header does not contain a basic
authentication token. authentication token.
@ -209,7 +209,7 @@ the correct user to index the audit events.
July 21, 2015 July 21, 2015
.Bug Fixes .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] ** 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. 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 July 21, 2015
.Bug Fixes .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] ** 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. 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: transport.profiles.client.xpack.security.ssl.truststore:
path: /path/to/another/truststore path: /path/to/another/truststore
password: changeme password: x-pack-test-password
transport.profiles.client.xpack.security.ssl.keystore: transport.profiles.client.xpack.security.ssl.keystore:
path: /path/to/another/keystore path: /path/to/another/keystore
password: changeme password: x-pack-test-password
-------------------------------------------------- --------------------------------------------------
To change the default behavior that requires certificates for transport clients, 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 POST /_xpack/security/user/packetbeat_internal
{ {
"password" : "changeme", "password" : "x-pack-test-password",
"roles" : [ "packetbeat_writer"], "roles" : [ "packetbeat_writer"],
"full_name" : "Internal Packetbeat User" "full_name" : "Internal Packetbeat User"
} }
@ -87,7 +87,7 @@ output.elasticsearch:
hosts: ["localhost:9200"] hosts: ["localhost:9200"]
index: "packetbeat" index: "packetbeat"
username: "packetbeat_internal" username: "packetbeat_internal"
password: "changeme" password: "x-pack-test-password"
-------------------------------------------------- --------------------------------------------------
.. To use PKI authentication, configure the `certificate` and .. To use PKI authentication, configure the `certificate` and
@ -144,7 +144,7 @@ the `packetbeat_reader` role:
--------------------------------------------------------------- ---------------------------------------------------------------
POST /_xpack/security/user/packetbeat_user POST /_xpack/security/user/packetbeat_user
{ {
"password" : "changeme", "password" : "x-pack-test-password",
"roles" : [ "packetbeat_reader"], "roles" : [ "packetbeat_reader"],
"full_name" : "Packetbeat User" "full_name" : "Packetbeat User"
} }

View File

@ -137,7 +137,7 @@ import org.elasticsearch.xpack.client.PreBuiltXPackTransportClient;
TransportClient client = new PreBuiltXPackTransportClient(Settings.builder() TransportClient client = new PreBuiltXPackTransportClient(Settings.builder()
.put("cluster.name", "myClusterName") .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("localhost", 9300)) .addTransportAddress(new InetSocketTransportAddress("localhost", 9300))
@ -169,14 +169,14 @@ import static org.elasticsearch.xpack.security.authc.support.UsernamePasswordTok
TransportClient client = new PreBuiltXPackTransportClient(Settings.builder() TransportClient client = new PreBuiltXPackTransportClient(Settings.builder()
.put("cluster.name", "myClusterName") .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())
.build() .build()
.addTransportAddress(new InetSocketTransportAddress(InetAddress.getByName("localhost"), 9300)) .addTransportAddress(new InetSocketTransportAddress(InetAddress.getByName("localhost"), 9300))
.addTransportAddress(new InetSocketTransportAddress(InetAddress.getByName("localhost"), 9301)) .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)) client.filterWithHeader(Collections.singletonMap("Authorization", token))
.prepareSearch().get(); .prepareSearch().get();
@ -198,7 +198,7 @@ import org.elasticsearch.xpack.client.PreBuiltXPackTransportClient;
TransportClient client = new PreBuiltXPackTransportClient(Settings.builder() TransportClient client = new PreBuiltXPackTransportClient(Settings.builder()
.put("cluster.name", "myClusterName") .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.key", "/path/to/client.key")
.put("xpack.ssl.certificate", "/path/to/client.crt") .put("xpack.ssl.certificate", "/path/to/client.crt")
.put("xpack.ssl.certificate_authorities", "/path/to/ca.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() TransportClient client = new PreBuiltXPackTransportClient(Settings.builder()
.put("cluster.name", "myClusterName") .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.key", "/path/to/client.key")
.put("xpack.ssl.certificate", "/path/to/client.crt") .put("xpack.ssl.certificate", "/path/to/client.crt")
.put("xpack.ssl.certificate_authorities", "/path/to/ca.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() TransportClient client = new PreBuiltXPackTransportClient(Settings.builder()
.put("cluster.name", "myClusterName") .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.ssl.certificate_authorities", "/path/to/ca.crt")
.put("xpack.security.transport.ssl.enabled", "true") .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. requests as this user to access the cluster monitoring APIs and the `.kibana` index.
The server does _not_ need access to user indices. The server does _not_ need access to user indices.
+ +
By default, the `kibana` user password is set to `changeme`. Change this password By default, the `kibana` does not have a password. The user will not be enabled until
through the reset password API: a password is set. Set the password through the reset password API:
+ +
[source,shell] [source,shell]
-------------------------------------------------------------------------------- --------------------------------------------------------------------------------

View File

@ -61,7 +61,7 @@ the `user` API:
--------------------------------------------------------------- ---------------------------------------------------------------
POST _xpack/security/user/logstash_internal POST _xpack/security/user/logstash_internal
{ {
"password" : "changeme", "password" : "x-pack-test-password",
"roles" : [ "logstash_writer"], "roles" : [ "logstash_writer"],
"full_name" : "Internal Logstash User" "full_name" : "Internal Logstash User"
} }
@ -76,18 +76,18 @@ plugins in your Logstash `.conf` file. For example:
input { input {
... ...
user => logstash_internal user => logstash_internal
password => changeme password => x-pack-test-password
} }
filter { filter {
... ...
user => logstash_internal user => logstash_internal
password => changeme password => x-pack-test-password
} }
output { output {
elasticsearch { elasticsearch {
... ...
user => logstash_internal user => logstash_internal
password => changeme password => x-pack-test-password
} }
-------------------------------------------------- --------------------------------------------------
@ -126,7 +126,7 @@ the `user` API:
--------------------------------------------------------------- ---------------------------------------------------------------
POST _xpack/security/user/logstash_user POST _xpack/security/user/logstash_user
{ {
"password" : "changeme", "password" : "x-pack-test-password",
"roles" : [ "logstash_reader"], "roles" : [ "logstash_reader"],
"full_name" : "Kibana User" "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 _should not_ be used for any other purpose - it is specifically _not intended_ for
use within a Logstash pipeline. use within a Logstash pipeline.
By default, the `logstash_system` user password is set to `changeme`. By default, the `logstash_system` does not have a password. The user will not be enabled until
Change this password through the reset password API: a password is set. Set the password through the reset password API:
[source,js] [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.url: ["http://es-mon-1:9200", "http://es-mon2:9200"]
xpack.monitoring.elasticsearch.username: "remote_monitor" 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: .. If SSL/TLS is enabled on the monitoring cluster:
@ -176,6 +176,6 @@ Alternatively, you can configure trusted certificates using a truststore
[source,yaml] [source,yaml]
-------------------------------------------------- --------------------------------------------------
xpack.monitoring.elasticsearch.ssl.truststore.path: /path/to/file 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 POST /_xpack/security/user/reporter
{ {
"password" : "changeme", "password" : "x-pack-test-password",
"roles" : ["kibana_user", "reporting_user"], "roles" : ["kibana_user", "reporting_user"],
"full_name" : "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. . 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 . Enable encryption globally. To encrypt communications, you must enable
<<ssl-tls,enable SSL/TLS>> on every node. <<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 ==== Default Password Security Settings
`xpack.security.authc.accept_default_password`:: `xpack.security.authc.accept_default_password`::
In `elasticsearch.yml`, set this to `false` to disable support for the default "changeme" 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] [float]
[[anonymous-access-settings]] [[anonymous-access-settings]]

View File

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

View File

@ -33,7 +33,7 @@ output { <2>
elasticsearch { elasticsearch {
hosts => "http://localhost:9200" hosts => "http://localhost:9200"
user => "elastic" 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; import static org.elasticsearch.xpack.security.authc.support.UsernamePasswordToken.basicAuthHeaderValue;
public class XDocsClientYamlTestSuiteIT extends ESClientYamlSuiteTestCase { 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) { public XDocsClientYamlTestSuiteIT(@Name("yaml") ClientYamlTestCandidate testCandidate) {
super(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 fi
cd "$ES_HOME" > /dev/null 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=$? status=$?
cd - > /dev/null cd - > /dev/null
exit $status 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. rem you may not use this file except in compliance with the Elastic License.
PUSHD "%~dp0" PUSHD "%~dp0"
CALL "%~dp0.in.bat" org.elasticsearch.xpack.security.crypto.tool.SystemKeyTool %* CALL "%~dp0.in.bat" org.elasticsearch.common.settings.EncKeyTool %*
POPD POPD

View File

@ -210,13 +210,50 @@ integTestCluster {
waitCondition = { NodeInfo node, AntBuilder ant -> waitCondition = { NodeInfo node, AntBuilder ant ->
File tmpFile = new File(node.cwd, 'wait.success') 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++) { 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 // 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; HttpURLConnection httpURLConnection = null;
try { try {
httpURLConnection = (HttpURLConnection) new URL("http://${node.httpUri()}/_cluster/health?wait_for_nodes=${numNodes}&wait_for_status=yellow").openConnection(); httpURLConnection = (HttpURLConnection) new URL("http://${node.httpUri()}/_cluster/health?wait_for_nodes=${numNodes}&wait_for_status=yellow").openConnection();
httpURLConnection.setRequestProperty("Authorization", "Basic " + 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.setRequestMethod("GET");
httpURLConnection.connect(); httpURLConnection.connect();
if (httpURLConnection.getResponseCode() == 200) { 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.SecurityFeatureSet;
import org.elasticsearch.xpack.security.authc.AuthenticationService; import org.elasticsearch.xpack.security.authc.AuthenticationService;
import org.elasticsearch.xpack.security.authc.support.UsernamePasswordToken; 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.sql.plugin.SqlPlugin;
import org.elasticsearch.xpack.ssl.SSLConfigurationReloader; import org.elasticsearch.xpack.ssl.SSLConfigurationReloader;
import org.elasticsearch.xpack.ssl.SSLService; import org.elasticsearch.xpack.ssl.SSLService;
@ -122,9 +123,12 @@ import java.util.Set;
import java.util.function.Supplier; import java.util.function.Supplier;
import java.util.function.UnaryOperator; import java.util.function.UnaryOperator;
import java.util.stream.Collectors; import java.util.stream.Collectors;
import java.util.stream.Stream;
import javax.security.auth.DestroyFailedException; 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 class XPackPlugin extends Plugin implements ScriptPlugin, ActionPlugin, IngestPlugin, NetworkPlugin {
public static final String NAME = "x-pack"; public static final String NAME = "x-pack";
@ -203,6 +207,7 @@ public class XPackPlugin extends Plugin implements ScriptPlugin, ActionPlugin, I
protected Graph graph; protected Graph graph;
protected MachineLearning machineLearning; protected MachineLearning machineLearning;
protected Logstash logstash; protected Logstash logstash;
protected CryptoService cryptoService;
protected Deprecation deprecation; protected Deprecation deprecation;
protected Upgrade upgrade; protected Upgrade upgrade;
protected SqlPlugin sql; protected SqlPlugin sql;
@ -232,6 +237,7 @@ public class XPackPlugin extends Plugin implements ScriptPlugin, ActionPlugin, I
} else { } else {
this.extensionsService = null; this.extensionsService = null;
} }
cryptoService = ENCRYPT_SENSITIVE_DATA_SETTING.get(settings) ? new CryptoService(settings) : null;
} }
// For tests only // For tests only
@ -286,7 +292,7 @@ public class XPackPlugin extends Plugin implements ScriptPlugin, ActionPlugin, I
// watcher http stuff // watcher http stuff
Map<String, HttpAuthFactory> httpAuthFactories = new HashMap<>(); 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 // TODO: add more auth types, or remove this indirection
HttpAuthRegistry httpAuthRegistry = new HttpAuthRegistry(httpAuthFactories); HttpAuthRegistry httpAuthRegistry = new HttpAuthRegistry(httpAuthFactories);
HttpRequestTemplate.Parser httpTemplateParser = new HttpRequestTemplate.Parser(httpAuthRegistry); 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(notificationComponents);
components.addAll(watcher.createComponents(getClock(), scriptService, internalClient, licenseState, 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)); 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, HttpRequestTemplate.Parser httpTemplateParser, ScriptService scriptService,
HttpAuthRegistry httpAuthRegistry) { HttpAuthRegistry httpAuthRegistry) {
List<Object> components = new ArrayList<>(); 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 HipChatService(settings, httpClient, clusterSettings));
components.add(new JiraService(settings, httpClient, clusterSettings)); components.add(new JiraService(settings, httpClient, clusterSettings));
components.add(new SlackService(settings, httpClient, clusterSettings)); components.add(new SlackService(settings, httpClient, clusterSettings));
@ -582,7 +588,10 @@ public class XPackPlugin extends Plugin implements ScriptPlugin, ActionPlugin, I
@Override @Override
public List<BootstrapCheck> getBootstrapChecks() { 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.settings.Settings;
import org.elasticsearch.common.unit.TimeValue; import org.elasticsearch.common.unit.TimeValue;
import org.elasticsearch.common.xcontent.XContentParser; import org.elasticsearch.common.xcontent.XContentParser;
import org.elasticsearch.index.query.QueryParseContext;
import org.elasticsearch.rest.RestController; import org.elasticsearch.rest.RestController;
import org.elasticsearch.rest.RestRequest; import org.elasticsearch.rest.RestRequest;
import org.elasticsearch.rest.action.RestToXContentListener; import org.elasticsearch.rest.action.RestToXContentListener;
@ -28,10 +27,10 @@ import java.util.HashMap;
import java.util.HashSet; import java.util.HashSet;
import java.util.Map; 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.GET;
import static org.elasticsearch.rest.RestRequest.Method.POST; import static org.elasticsearch.rest.RestRequest.Method.POST;
import static org.elasticsearch.xpack.graph.action.GraphExploreAction.INSTANCE; import static org.elasticsearch.xpack.graph.action.GraphExploreAction.INSTANCE;
/** /**
* @see GraphExploreRequest * @see GraphExploreRequest
*/ */
@ -89,7 +88,6 @@ public class RestGraphAction extends XPackRestHandler {
Hop currentHop = graphRequest.createNextHop(null); Hop currentHop = graphRequest.createNextHop(null);
try (XContentParser parser = request.contentOrSourceParamParser()) { try (XContentParser parser = request.contentOrSourceParamParser()) {
QueryParseContext context = new QueryParseContext(parser);
XContentParser.Token token = parser.nextToken(); 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", throw new ElasticsearchParseException("failed to parse search source. source must be an object, but found [{}] instead",
token.name()); token.name());
} }
parseHop(parser, context, currentHop, graphRequest); parseHop(parser, currentHop, graphRequest);
} }
graphRequest.types(Strings.splitStringByCommaToArray(request.param("type"))); graphRequest.types(Strings.splitStringByCommaToArray(request.param("type")));
return channel -> client.es().execute(INSTANCE, graphRequest, new RestToXContentListener<>(channel)); return channel -> client.es().execute(INSTANCE, graphRequest, new RestToXContentListener<>(channel));
} }
private void parseHop(XContentParser parser, QueryParseContext context, Hop currentHop, private void parseHop(XContentParser parser, Hop currentHop, GraphExploreRequest graphRequest) throws IOException {
GraphExploreRequest graphRequest) throws IOException {
String fieldName = null; String fieldName = null;
XContentParser.Token token; XContentParser.Token token;
@ -121,15 +118,15 @@ public class RestGraphAction extends XPackRestHandler {
} }
} else if (token == XContentParser.Token.START_OBJECT) { } else if (token == XContentParser.Token.START_OBJECT) {
if (QUERY_FIELD.match(fieldName)) { if (QUERY_FIELD.match(fieldName)) {
currentHop.guidingQuery(context.parseInnerQueryBuilder()); currentHop.guidingQuery(parseInnerQueryBuilder(parser));
} else if (CONNECTIONS_FIELD.match(fieldName)) { } 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)) { } else if (CONTROLS_FIELD.match(fieldName)) {
if (currentHop.getParentHop() != null) { if (currentHop.getParentHop() != null) {
throw new ElasticsearchParseException( throw new ElasticsearchParseException(
"Controls are a global setting that can only be set in the root " + fieldName, token.name()); "Controls are a global setting that can only be set in the root " + fieldName, token.name());
} }
parseControls(parser, context, graphRequest); parseControls(parser, graphRequest);
} else { } else {
throw new ElasticsearchParseException("Illegal object property in graph definition " + fieldName, token.name()); 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()+ "Graph vertices definition cannot contain both "+ INCLUDE_FIELD.getPreferredName()+
" and "+EXCLUDE_FIELD.getPreferredName()+" clauses", token.name()); " and "+EXCLUDE_FIELD.getPreferredName()+" clauses", token.name());
} }
excludes = new HashSet<String>(); excludes = new HashSet<>();
while ((token = parser.nextToken()) != XContentParser.Token.END_ARRAY) { while ((token = parser.nextToken()) != XContentParser.Token.END_ARRAY) {
excludes.add(parser.text()); 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; XContentParser.Token token;
String fieldName = null; 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.ToXContentObject;
import org.elasticsearch.common.xcontent.XContentBuilder; import org.elasticsearch.common.xcontent.XContentBuilder;
import org.elasticsearch.common.xcontent.XContentParser; import org.elasticsearch.common.xcontent.XContentParser;
import org.elasticsearch.index.query.AbstractQueryBuilder;
import org.elasticsearch.index.query.QueryBuilder; import org.elasticsearch.index.query.QueryBuilder;
import org.elasticsearch.index.query.QueryBuilders; import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.index.query.QueryParseContext;
import org.elasticsearch.search.aggregations.AggregationBuilder; import org.elasticsearch.search.aggregations.AggregationBuilder;
import org.elasticsearch.search.aggregations.AggregatorFactories; import org.elasticsearch.search.aggregations.AggregatorFactories;
import org.elasticsearch.search.aggregations.bucket.histogram.DateHistogramAggregationBuilder; import org.elasticsearch.search.aggregations.bucket.histogram.DateHistogramAggregationBuilder;
@ -87,14 +87,14 @@ public class DatafeedConfig extends AbstractDiffable<DatafeedConfig> implements
PARSER.declareString((builder, val) -> PARSER.declareString((builder, val) ->
builder.setFrequency(TimeValue.parseTimeValue(val, FREQUENCY.getPreferredName())), FREQUENCY); builder.setFrequency(TimeValue.parseTimeValue(val, FREQUENCY.getPreferredName())), FREQUENCY);
PARSER.declareObject(Builder::setQuery, PARSER.declareObject(Builder::setQuery,
(p, c) -> new QueryParseContext(p).parseInnerQueryBuilder(), QUERY); (p, c) -> AbstractQueryBuilder.parseInnerQueryBuilder(p), QUERY);
PARSER.declareObject(Builder::setAggregations, (p, c) -> AggregatorFactories.parseAggregators(new QueryParseContext(p)), PARSER.declareObject(Builder::setAggregations, (p, c) -> AggregatorFactories.parseAggregators(p),
AGGREGATIONS); 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) -> { PARSER.declareObject(Builder::setScriptFields, (p, c) -> {
List<SearchSourceBuilder.ScriptField> parsedScriptFields = new ArrayList<>(); List<SearchSourceBuilder.ScriptField> parsedScriptFields = new ArrayList<>();
while (p.nextToken() != XContentParser.Token.END_OBJECT) { 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)); parsedScriptFields.sort(Comparator.comparing(SearchSourceBuilder.ScriptField::fieldName));
return parsedScriptFields; 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.ToXContentObject;
import org.elasticsearch.common.xcontent.XContentBuilder; import org.elasticsearch.common.xcontent.XContentBuilder;
import org.elasticsearch.common.xcontent.XContentParser; import org.elasticsearch.common.xcontent.XContentParser;
import org.elasticsearch.index.query.AbstractQueryBuilder;
import org.elasticsearch.index.query.QueryBuilder; import org.elasticsearch.index.query.QueryBuilder;
import org.elasticsearch.index.query.QueryParseContext;
import org.elasticsearch.search.aggregations.AggregatorFactories; import org.elasticsearch.search.aggregations.AggregatorFactories;
import org.elasticsearch.search.builder.SearchSourceBuilder; import org.elasticsearch.search.builder.SearchSourceBuilder;
import org.elasticsearch.xpack.ml.job.config.Job; import org.elasticsearch.xpack.ml.job.config.Job;
@ -49,15 +49,15 @@ public class DatafeedUpdate implements Writeable, ToXContentObject {
PARSER.declareString((builder, val) -> builder.setFrequency( PARSER.declareString((builder, val) -> builder.setFrequency(
TimeValue.parseTimeValue(val, DatafeedConfig.FREQUENCY.getPreferredName())), DatafeedConfig.FREQUENCY); TimeValue.parseTimeValue(val, DatafeedConfig.FREQUENCY.getPreferredName())), DatafeedConfig.FREQUENCY);
PARSER.declareObject(Builder::setQuery, PARSER.declareObject(Builder::setQuery,
(p, c) -> new QueryParseContext(p).parseInnerQueryBuilder(), DatafeedConfig.QUERY); (p, c) -> AbstractQueryBuilder.parseInnerQueryBuilder(p), DatafeedConfig.QUERY);
PARSER.declareObject(Builder::setAggregations, (p, c) -> AggregatorFactories.parseAggregators(new QueryParseContext(p)), PARSER.declareObject(Builder::setAggregations, (p, c) -> AggregatorFactories.parseAggregators(p),
DatafeedConfig.AGGREGATIONS); DatafeedConfig.AGGREGATIONS);
PARSER.declareObject(Builder::setAggregations,(p, c) -> AggregatorFactories.parseAggregators(new QueryParseContext(p)), PARSER.declareObject(Builder::setAggregations,(p, c) -> AggregatorFactories.parseAggregators(p),
DatafeedConfig.AGGS); DatafeedConfig.AGGS);
PARSER.declareObject(Builder::setScriptFields, (p, c) -> { PARSER.declareObject(Builder::setScriptFields, (p, c) -> {
List<SearchSourceBuilder.ScriptField> parsedScriptFields = new ArrayList<>(); List<SearchSourceBuilder.ScriptField> parsedScriptFields = new ArrayList<>();
while (p.nextToken() != XContentParser.Token.END_OBJECT) { 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)); parsedScriptFields.sort(Comparator.comparing(SearchSourceBuilder.ScriptField::fieldName));
return parsedScriptFields; return parsedScriptFields;

View File

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

View File

@ -200,7 +200,6 @@ public class Security implements ActionPlugin, IngestPlugin, NetworkPlugin {
private final boolean enabled; private final boolean enabled;
private final boolean transportClientMode; private final boolean transportClientMode;
private final XPackLicenseState licenseState; private final XPackLicenseState licenseState;
private final CryptoService cryptoService;
private final SSLService sslService; 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 /* 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 * 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); this.enabled = XPackSettings.SECURITY_ENABLED.get(settings);
if (enabled && transportClientMode == false) { if (enabled && transportClientMode == false) {
validateAutoCreateIndex(settings); validateAutoCreateIndex(settings);
cryptoService = new CryptoService(settings, env);
} else {
cryptoService = null;
} }
this.licenseState = licenseState; this.licenseState = licenseState;
this.sslService = sslService; this.sslService = sslService;
} }
public CryptoService getCryptoService() {
return cryptoService;
}
public Collection<Module> nodeModules() { public Collection<Module> nodeModules() {
List<Module> modules = new ArrayList<>(); List<Module> modules = new ArrayList<>();
if (enabled == false || transportClientMode) { if (enabled == false || transportClientMode) {
@ -254,7 +246,6 @@ public class Security implements ActionPlugin, IngestPlugin, NetworkPlugin {
if (enabled == false) { if (enabled == false) {
modules.add(b -> { modules.add(b -> {
b.bind(CryptoService.class).toProvider(Providers.of(null));
b.bind(Realms.class).toProvider(Providers.of(null)); // for SecurityFeatureSet b.bind(Realms.class).toProvider(Providers.of(null)); // for SecurityFeatureSet
b.bind(CompositeRolesStore.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 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 // which might not be the case during Plugin class instantiation. Once nodeModules are pulled
// everything should have been loaded // everything should have been loaded
modules.add(b -> { modules.add(b -> {
b.bind(CryptoService.class).toInstance(cryptoService);
if (XPackSettings.AUDIT_ENABLED.get(settings)) { if (XPackSettings.AUDIT_ENABLED.get(settings)) {
b.bind(AuditTrail.class).to(AuditTrailService.class); // interface used by some actions... 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_INTERVAL);
settingsList.add(TokenService.DELETE_TIMEOUT); settingsList.add(TokenService.DELETE_TIMEOUT);
// encryption settings
CryptoService.addSettings(settingsList);
// hide settings // hide settings
settingsList.add(Setting.listSetting(setting("hide_settings"), Collections.emptyList(), Function.identity(), settingsList.add(Setting.listSetting(setting("hide_settings"), Collections.emptyList(), Function.identity(),
Property.NodeScope, Property.Filtered)); 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;
import org.elasticsearch.common.settings.Setting.Property; import org.elasticsearch.common.settings.Setting.Property;
import org.elasticsearch.common.settings.Settings; import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.common.transport.TransportAddress;
import org.elasticsearch.common.util.concurrent.ThreadContext; import org.elasticsearch.common.util.concurrent.ThreadContext;
import org.elasticsearch.node.Node; import org.elasticsearch.node.Node;
import org.elasticsearch.rest.RestRequest; 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.AnonymousUser;
import org.elasticsearch.xpack.security.user.User; import org.elasticsearch.xpack.security.user.User;
import java.net.InetSocketAddress;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.function.BiConsumer; import java.util.function.BiConsumer;
@ -132,8 +134,8 @@ public class AuthenticationService extends AbstractComponent {
private final AuditableRequest request; private final AuditableRequest request;
private final User fallbackUser; private final User fallbackUser;
private final ActionListener<Authentication> listener;
private final ActionListener<Authentication> listener;
private RealmRef authenticatedBy = null; private RealmRef authenticatedBy = null;
private RealmRef lookedupBy = null; private RealmRef lookedupBy = null;
private AuthenticationToken authenticationToken = null; private AuthenticationToken authenticationToken = null;
@ -279,7 +281,7 @@ public class AuthenticationService extends AbstractComponent {
authenticationToken.principal(), realm.name(), ex); authenticationToken.principal(), realm.name(), ex);
logger.debug("Authentication failed due to exception", ex); logger.debug("Authentication failed due to exception", ex);
userListener.onFailure(ex); userListener.onFailure(ex);
})); }), request);
} else { } else {
userListener.onResponse(null); 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 AuditTrail auditTrail;
final AuthenticationFailureHandler failureHandler; final AuthenticationFailureHandler failureHandler;
final ThreadContext threadContext; 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.auditTrail = auditTrail;
this.failureHandler = failureHandler; this.failureHandler = failureHandler;
this.threadContext = threadContext; this.threadContext = threadContext;
this.remoteAddress = remoteAddress;
this.requestType = requestType;
} }
abstract void realmAuthenticationFailed(AuthenticationToken token, String realm); abstract void realmAuthenticationFailed(AuthenticationToken token, String realm);
@ -461,6 +468,14 @@ public class AuthenticationService extends AbstractComponent {
abstract ElasticsearchSecurityException runAsDenied(User user, AuthenticationToken token); abstract ElasticsearchSecurityException runAsDenied(User user, AuthenticationToken token);
abstract void authenticationSuccess(String realm, User user); abstract void authenticationSuccess(String realm, User user);
public InetSocketAddress getRemoteAddress() {
return remoteAddress;
}
public RequestType getType() {
return requestType;
}
} }
static class AuditableTransportRequest extends AuditableRequest { static class AuditableTransportRequest extends AuditableRequest {
@ -470,7 +485,7 @@ public class AuthenticationService extends AbstractComponent {
AuditableTransportRequest(AuditTrail auditTrail, AuthenticationFailureHandler failureHandler, ThreadContext threadContext, AuditableTransportRequest(AuditTrail auditTrail, AuthenticationFailureHandler failureHandler, ThreadContext threadContext,
String action, TransportMessage message) { String action, TransportMessage message) {
super(auditTrail, failureHandler, threadContext); super(auditTrail, failureHandler, threadContext, getType(message), getRemoteAddress(message));
this.action = action; this.action = action;
this.message = message; this.message = message;
} }
@ -523,15 +538,25 @@ public class AuthenticationService extends AbstractComponent {
public String toString() { public String toString() {
return "transport request action [" + action + "]"; 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 { static class AuditableRestRequest extends AuditableRequest {
private final RestRequest request; private final RestRequest request;
@SuppressWarnings("unchecked")
AuditableRestRequest(AuditTrail auditTrail, AuthenticationFailureHandler failureHandler, ThreadContext threadContext, AuditableRestRequest(AuditTrail auditTrail, AuthenticationFailureHandler failureHandler, ThreadContext threadContext,
RestRequest request) { RestRequest request) {
super(auditTrail, failureHandler, threadContext); super(auditTrail, failureHandler, threadContext, RequestType.REST, (InetSocketAddress) request.getRemoteAddress());
this.request = request; 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 * {@link ActionListener#onResponse} with the User associated with the given token. An unsuccessful authentication calls
* with {@code null} on the argument. * 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 token The authentication token
* @param listener The listener to pass the authentication result to * @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} * 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.action.ActionListener;
import org.elasticsearch.common.settings.Setting; 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.RealmConfig;
import org.elasticsearch.xpack.security.authc.support.CachingUsernamePasswordRealm; import org.elasticsearch.xpack.security.authc.support.CachingUsernamePasswordRealm;
import org.elasticsearch.xpack.security.authc.support.UsernamePasswordToken; import org.elasticsearch.xpack.security.authc.support.UsernamePasswordToken;
import org.elasticsearch.xpack.security.user.User; import org.elasticsearch.xpack.security.user.User;
import java.util.HashSet;
import java.util.Set; import java.util.Set;
/** /**
@ -35,7 +35,7 @@ public class NativeRealm extends CachingUsernamePasswordRealm {
} }
@Override @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); 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())) { 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)) { } else if (password.isEmpty() && containerSettings.inContainer() && username.equals(ElasticUser.NAME)) {
listener.onResponse(new ReservedUserInfo(containerSettings.getPasswordHash(), enabled, false)); listener.onResponse(new ReservedUserInfo(containerSettings.getPasswordHash(), enabled, false));
} else if (password.isEmpty()) { } 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 { } else {
listener.onResponse(new ReservedUserInfo(password.toCharArray(), enabled, false)); listener.onResponse(new ReservedUserInfo(password.toCharArray(), enabled, false));
} }
@ -607,7 +607,7 @@ public class NativeUsersStore extends AbstractComponent {
char[] passwordHash = containerSettings.getPasswordHash(); char[] passwordHash = containerSettings.getPasswordHash();
userInfos.put(searchHit.getId(), new ReservedUserInfo(passwordHash, enabled, false)); userInfos.put(searchHit.getId(), new ReservedUserInfo(passwordHash, enabled, false));
} else if (password.isEmpty()) { } 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 { } else {
userInfos.put(username, new ReservedUserInfo(password.toCharArray(), enabled, false)); userInfos.put(username, new ReservedUserInfo(password.toCharArray(), enabled, false));
} }
@ -694,12 +694,12 @@ public class NativeUsersStore extends AbstractComponent {
public final char[] passwordHash; public final char[] passwordHash;
public final boolean enabled; 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.passwordHash = passwordHash;
this.enabled = enabled; 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.XPackSettings;
import org.elasticsearch.xpack.security.Security; import org.elasticsearch.xpack.security.Security;
import org.elasticsearch.xpack.security.SecurityLifecycleService; 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.RealmConfig;
import org.elasticsearch.xpack.security.authc.esnative.NativeUsersStore.ReservedUserInfo; import org.elasticsearch.xpack.security.authc.esnative.NativeUsersStore.ReservedUserInfo;
import org.elasticsearch.xpack.security.authc.support.CachingUsernamePasswordRealm; 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.LogstashSystemUser;
import org.elasticsearch.xpack.security.user.User; 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.ArrayList;
import java.util.Arrays; import java.util.Arrays;
import java.util.Collection; import java.util.Collection;
@ -44,20 +48,20 @@ public class ReservedRealm extends CachingUsernamePasswordRealm {
public static final String TYPE = "reserved"; public static final String TYPE = "reserved";
public static final SecureString DEFAULT_PASSWORD_TEXT = new SecureString("changeme".toCharArray()); public static final SecureString EMPTY_PASSWORD_TEXT = new SecureString("".toCharArray());
static final char[] DEFAULT_PASSWORD_HASH = Hasher.BCRYPT.hash(DEFAULT_PASSWORD_TEXT); 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 DEFAULT_USER_INFO = new ReservedUserInfo(EMPTY_PASSWORD_HASH, true, true);
private static final ReservedUserInfo DISABLED_USER_INFO = new ReservedUserInfo(DEFAULT_PASSWORD_HASH, false, 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( 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 NativeUsersStore nativeUsersStore;
private final AnonymousUser anonymousUser; private final AnonymousUser anonymousUser;
private final boolean realmEnabled; private final boolean realmEnabled;
private final boolean anonymousEnabled; private final boolean anonymousEnabled;
private final boolean defaultPasswordEnabled;
private final SecurityLifecycleService securityLifecycleService; private final SecurityLifecycleService securityLifecycleService;
public ReservedRealm(Environment env, Settings settings, NativeUsersStore nativeUsersStore, AnonymousUser anonymousUser, 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.realmEnabled = XPackSettings.RESERVED_REALM_ENABLED_SETTING.get(settings);
this.anonymousUser = anonymousUser; this.anonymousUser = anonymousUser;
this.anonymousEnabled = AnonymousUser.isAnonymousEnabled(settings); this.anonymousEnabled = AnonymousUser.isAnonymousEnabled(settings);
this.defaultPasswordEnabled = ACCEPT_DEFAULT_PASSWORD_SETTING.get(settings);
this.securityLifecycleService = securityLifecycleService; this.securityLifecycleService = securityLifecycleService;
} }
@Override @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) { if (realmEnabled == false) {
listener.onResponse(null); listener.onResponse(null);
} else if (isReserved(token.principal(), config.globalSettings()) == false) { } else if (isReserved(token.principal(), config.globalSettings()) == false) {
@ -82,7 +102,10 @@ public class ReservedRealm extends CachingUsernamePasswordRealm {
Runnable action; Runnable action;
if (userInfo != null) { if (userInfo != null) {
try { 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); final User user = getUser(token.principal(), userInfo);
action = () -> listener.onResponse(user); action = () -> listener.onResponse(user);
} else { } else {
@ -90,7 +113,7 @@ public class ReservedRealm extends CachingUsernamePasswordRealm {
token.principal())); token.principal()));
} }
} finally { } finally {
if (userInfo.passwordHash != DEFAULT_PASSWORD_HASH) { if (userInfo.passwordHash != EMPTY_PASSWORD_HASH) {
Arrays.fill(userInfo.passwordHash, (char) 0); 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) { private boolean verifyPassword(ReservedUserInfo userInfo, UsernamePasswordToken token) {
if (Hasher.BCRYPT.verify(token.credentials(), userInfo.passwordHash)) { if (Hasher.BCRYPT.verify(token.credentials(), userInfo.passwordHash)) {
if (userInfo.hasDefaultPassword && this.defaultPasswordEnabled == false) {
return false;
}
return true; return true;
} }
return false; return false;
@ -154,7 +178,7 @@ public class ReservedRealm extends CachingUsernamePasswordRealm {
assert username != null; assert username != null;
switch (username) { switch (username) {
case ElasticUser.NAME: case ElasticUser.NAME:
return new ElasticUser(userInfo.enabled); return new ElasticUser(userInfo.enabled, userInfo.hasEmptyPassword);
case KibanaUser.NAME: case KibanaUser.NAME:
return new KibanaUser(userInfo.enabled); return new KibanaUser(userInfo.enabled);
case LogstashSystemUser.NAME: case LogstashSystemUser.NAME:
@ -178,7 +202,8 @@ public class ReservedRealm extends CachingUsernamePasswordRealm {
List<User> users = new ArrayList<>(4); List<User> users = new ArrayList<>(4);
ReservedUserInfo userInfo = reservedUserInfos.get(ElasticUser.NAME); 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); userInfo = reservedUserInfos.get(KibanaUser.NAME);
users.add(new KibanaUser(userInfo == null || userInfo.enabled)); users.add(new KibanaUser(userInfo == null || userInfo.enabled));

View File

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

View File

@ -11,6 +11,7 @@ import java.util.Set;
import org.elasticsearch.action.ActionListener; import org.elasticsearch.action.ActionListener;
import org.elasticsearch.common.settings.Setting; import org.elasticsearch.common.settings.Setting;
import org.elasticsearch.watcher.ResourceWatcherService; 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.RealmConfig;
import org.elasticsearch.xpack.security.authc.support.CachingUsernamePasswordRealm; import org.elasticsearch.xpack.security.authc.support.CachingUsernamePasswordRealm;
import org.elasticsearch.xpack.security.authc.support.UsernamePasswordToken; import org.elasticsearch.xpack.security.authc.support.UsernamePasswordToken;
@ -37,7 +38,7 @@ public class FileRealm extends CachingUsernamePasswordRealm {
} }
@Override @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())) { if (userPasswdStore.verifyPassword(token.principal(), token.credentials())) {
String[] roles = userRolesStore.roles(token.principal()); String[] roles = userRolesStore.roles(token.principal());
listener.onResponse(new User(token.principal(), roles)); 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.ElasticsearchTimeoutException;
import org.elasticsearch.action.ActionListener; import org.elasticsearch.action.ActionListener;
import org.elasticsearch.action.support.ContextPreservingActionListener; import org.elasticsearch.action.support.ContextPreservingActionListener;
import org.elasticsearch.common.Strings;
import org.elasticsearch.common.collect.MapBuilder; import org.elasticsearch.common.collect.MapBuilder;
import org.elasticsearch.common.settings.Setting; import org.elasticsearch.common.settings.Setting;
import org.elasticsearch.common.settings.Setting.Property; 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;
import org.elasticsearch.threadpool.ThreadPool.Names; import org.elasticsearch.threadpool.ThreadPool.Names;
import org.elasticsearch.watcher.ResourceWatcherService; 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.RealmConfig;
import org.elasticsearch.xpack.security.authc.RealmSettings; import org.elasticsearch.xpack.security.authc.RealmSettings;
import org.elasticsearch.xpack.security.authc.ldap.support.LdapLoadBalancing; 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 * This user will then be passed to the listener
*/ */
@Override @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 // 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 // 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, 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.common.util.concurrent.ThreadContext;
import org.elasticsearch.env.Environment; import org.elasticsearch.env.Environment;
import org.elasticsearch.watcher.ResourceWatcherService; 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.UserRoleMapper;
import org.elasticsearch.xpack.security.authc.support.mapper.CompositeRoleMapper; import org.elasticsearch.xpack.security.authc.support.mapper.CompositeRoleMapper;
import org.elasticsearch.xpack.security.authc.support.mapper.NativeRoleMappingStore; 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.Matcher;
import java.util.regex.Pattern; 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 class PkiRealm extends Realm {
public static final String PKI_CERT_HEADER_NAME = "__SECURITY_CLIENT_CERTIFICATE"; public static final String PKI_CERT_HEADER_NAME = "__SECURITY_CLIENT_CERTIFICATE";
@ -84,7 +82,7 @@ public class PkiRealm extends Realm {
} }
@Override @Override
public void authenticate(AuthenticationToken authToken, ActionListener<User> listener) { public void authenticate(AuthenticationToken authToken, ActionListener<User> listener, IncomingRequest incomingRequest) {
X509AuthenticationToken token = (X509AuthenticationToken)authToken; X509AuthenticationToken token = (X509AuthenticationToken)authToken;
if (isCertificateChainTrusted(trustManager, token, logger) == false) { if (isCertificateChainTrusted(trustManager, token, logger) == false) {
listener.onResponse(null); 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.settings.Setting;
import org.elasticsearch.common.unit.TimeValue; import org.elasticsearch.common.unit.TimeValue;
import org.elasticsearch.xpack.security.authc.AuthenticationToken; 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.authc.RealmConfig;
import org.elasticsearch.xpack.security.user.User; 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 * 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 * against a hash also stored in the cache. Otherwise the subclass authenticates the user via
* doAuthenticate * doAuthenticate
*
* @param authToken The authentication token * @param authToken The authentication token
* @param listener to be called at completion
* @param incomingRequest the request that is being authenticated
*/ */
@Override @Override
public final void authenticate(AuthenticationToken authToken, ActionListener<User> listener) { public final void authenticate(AuthenticationToken authToken, ActionListener<User> listener, IncomingRequest incomingRequest) {
UsernamePasswordToken token = (UsernamePasswordToken)authToken; UsernamePasswordToken token = (UsernamePasswordToken) authToken;
try { try {
if (cache == null) { if (cache == null) {
doAuthenticate(token, listener); doAuthenticate(token, listener, incomingRequest);
} else { } else {
authenticateWithCache(token, listener); authenticateWithCache(token, listener, incomingRequest);
} }
} catch (Exception e) { } catch (Exception e) {
// each realm should handle exceptions, if we get one here it should be considered fatal // 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()); UserWithHash userWithHash = cache.get(token.principal());
if (userWithHash == null) { if (userWithHash == null) {
if (logger.isDebugEnabled()) { 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()); logger.debug("realm [{}] authenticated user [{}], with roles [{}]", name(), token.principal(), user.roles());
} }
listener.onResponse(user); listener.onResponse(user);
}, listener::onFailure)); }, listener::onFailure), incomingRequest);
} else if (userWithHash.hasHash()) { } else if (userWithHash.hasHash()) {
if (userWithHash.verify(token.credentials())) { if (userWithHash.verify(token.credentials())) {
if (userWithHash.user.enabled()) { if (userWithHash.user.enabled()) {
@ -114,7 +116,7 @@ public abstract class CachingUsernamePasswordRealm extends UsernamePasswordRealm
user.enabled(), user.roles()); user.enabled(), user.roles());
} }
listener.onResponse(user); listener.onResponse(user);
}, listener::onFailure)); }, listener::onFailure), incomingRequest);
} }
} else { } else {
cache.invalidate(token.principal()); cache.invalidate(token.principal());
@ -124,7 +126,7 @@ public abstract class CachingUsernamePasswordRealm extends UsernamePasswordRealm
name(), token.principal(), user.roles()); name(), token.principal(), user.roles());
} }
listener.onResponse(user); listener.onResponse(user);
}, listener::onFailure)); }, listener::onFailure), incomingRequest);
} }
} else { } else {
cache.invalidate(token.principal()); cache.invalidate(token.principal());
@ -134,12 +136,12 @@ public abstract class CachingUsernamePasswordRealm extends UsernamePasswordRealm
"realm [{}] authenticated user [{}] with roles [{}]", name(), token.principal(), user.roles()); "realm [{}] authenticated user [{}] with roles [{}]", name(), token.principal(), user.roles());
} }
listener.onResponse(user); listener.onResponse(user);
}, listener::onFailure)); }, listener::onFailure), incomingRequest);
} }
} }
private void doAuthenticateAndCache(UsernamePasswordToken token, ActionListener<User> listener) { private void doAuthenticateAndCache(UsernamePasswordToken token, ActionListener<User> listener, IncomingRequest incomingRequest) {
doAuthenticate(token, ActionListener.wrap((user) -> { ActionListener<User> wrapped = ActionListener.wrap((user) -> {
if (user == null) { if (user == null) {
listener.onResponse(null); listener.onResponse(null);
} else { } else {
@ -148,7 +150,9 @@ public abstract class CachingUsernamePasswordRealm extends UsernamePasswordRealm
cache.put(token.principal(), userWithHash); cache.put(token.principal(), userWithHash);
listener.onResponse(user); listener.onResponse(user);
} }
}, listener::onFailure)); }, listener::onFailure);
doAuthenticate(token, wrapped, incomingRequest);
} }
@Override @Override
@ -158,7 +162,7 @@ public abstract class CachingUsernamePasswordRealm extends UsernamePasswordRealm
return stats; return stats;
} }
protected abstract void doAuthenticate(UsernamePasswordToken token, ActionListener<User> listener); protected abstract void doAuthenticate(UsernamePasswordToken token, ActionListener<User> listener, IncomingRequest incomingRequest);
@Override @Override
public final void lookupUser(String username, ActionListener<User> listener) { 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.ActionListener;
import org.elasticsearch.action.CompositeIndicesRequest; import org.elasticsearch.action.CompositeIndicesRequest;
import org.elasticsearch.action.IndicesRequest; 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.Alias;
import org.elasticsearch.action.admin.indices.alias.IndicesAliasesRequest; import org.elasticsearch.action.admin.indices.alias.IndicesAliasesRequest;
import org.elasticsearch.action.admin.indices.create.CreateIndexRequest; 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.authz.store.ReservedRolesStore;
import org.elasticsearch.xpack.security.support.Automatons; import org.elasticsearch.xpack.security.support.Automatons;
import org.elasticsearch.xpack.security.user.AnonymousUser; 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.SystemUser;
import org.elasticsearch.xpack.security.user.User; import org.elasticsearch.xpack.security.user.User;
import org.elasticsearch.xpack.security.user.XPackUser; import org.elasticsearch.xpack.security.user.XPackUser;
@ -150,6 +152,12 @@ public class AuthorizationService extends AbstractComponent {
throw denial(authentication, action, request); 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 // get the roles of the authenticated user, which may be different than the effective
Role permission = userRole; Role permission = userRole;

View File

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

View File

@ -12,10 +12,8 @@ import javax.crypto.KeyGenerator;
import javax.crypto.SecretKey; import javax.crypto.SecretKey;
import javax.crypto.spec.IvParameterSpec; import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec; import javax.crypto.spec.SecretKeySpec;
import java.io.FileNotFoundException;
import java.io.IOException; import java.io.IOException;
import java.nio.file.Files; import java.io.InputStream;
import java.nio.file.Path;
import java.security.MessageDigest; import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException; import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom; import java.security.SecureRandom;
@ -25,12 +23,12 @@ import java.util.List;
import org.elasticsearch.ElasticsearchException; import org.elasticsearch.ElasticsearchException;
import org.elasticsearch.common.component.AbstractComponent; import org.elasticsearch.common.component.AbstractComponent;
import org.elasticsearch.common.io.Streams;
import org.elasticsearch.common.settings.Setting; import org.elasticsearch.common.settings.Setting;
import org.elasticsearch.common.settings.Setting.Property; import org.elasticsearch.common.settings.Setting.Property;
import org.elasticsearch.common.settings.Settings; 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.security.authc.support.CharArrays;
import org.elasticsearch.xpack.watcher.Watcher;
import static org.elasticsearch.xpack.security.Security.setting; 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 String KEY_ALGO = "HmacSHA512";
public static final int KEY_SIZE = 1024; 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 String ENCRYPTED_TEXT_PREFIX = "::es_encrypted::";
static final int DEFAULT_KEY_LENGTH = 128;
private static final Setting<Boolean> SYSTEM_KEY_REQUIRED_SETTING = // the encryption used in this class was picked when Java 7 was still the min. supported
Setting.boolSetting(setting("system_key.required"), false, Property.NodeScope); // 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 = private static final Setting<String> ENCRYPTION_ALGO_SETTING =
new Setting<>(setting("encryption.algorithm"), s -> DEFAULT_ENCRYPTION_ALGORITHM, s -> s, Property.NodeScope); new Setting<>(setting("encryption.algorithm"), s -> DEFAULT_ENCRYPTION_ALGORITHM, s -> s, Property.NodeScope);
private static final Setting<Integer> ENCRYPTION_KEY_LENGTH_SETTING = private static final Setting<Integer> ENCRYPTION_KEY_LENGTH_SETTING =
@ -65,7 +68,7 @@ public class CryptoService extends AbstractComponent {
*/ */
private final SecretKey encryptionKey; private final SecretKey encryptionKey;
public CryptoService(Settings settings, Environment env) throws IOException { public CryptoService(Settings settings) throws IOException {
super(settings); super(settings);
this.encryptionAlgorithm = ENCRYPTION_ALGO_SETTING.get(settings); this.encryptionAlgorithm = ENCRYPTION_ALGO_SETTING.get(settings);
final int keyLength = ENCRYPTION_KEY_LENGTH_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"); throw new IllegalArgumentException("invalid key length [" + keyLength + "]. value must be a multiple of 8");
} }
Path keyFile = resolveSystemKey(env); SecretKey systemKey = readSystemKey(Watcher.ENCRYPTION_KEY_SETTING.get(settings));
SecretKey systemKey = readSystemKey(keyFile, SYSTEM_KEY_REQUIRED_SETTING.get(settings));
try { try {
encryptionKey = encryptionKey(systemKey, keyLength, keyAlgorithm); encryptionKey = encryptionKey(systemKey, keyLength, keyAlgorithm);
} catch (NoSuchAlgorithmException nsae) { } catch (NoSuchAlgorithmException nsae) {
throw new ElasticsearchException("failed to start crypto service. could not load encryption key", nsae); throw new ElasticsearchException("failed to start crypto service. could not load encryption key", nsae);
} }
if (systemKey != null) { assert encryptionKey != null : "the encryption key should never be null";
logger.info("system key [{}] has been loaded", keyFile.toAbsolutePath());
}
} }
public static byte[] generateKey() { public static byte[] generateKey() {
@ -103,21 +102,14 @@ public class CryptoService extends AbstractComponent {
} }
} }
public static Path resolveSystemKey(Environment env) { private static SecretKey readSystemKey(InputStream in) throws IOException {
return XPackPlugin.resolveConfigFile(env, FILE_NAME); final int keySizeBytes = KEY_SIZE / 8;
} final byte[] keyBytes = new byte[keySizeBytes];
final int read = Streams.readFully(in, keyBytes);
private static SecretKey readSystemKey(Path file, boolean required) throws IOException { if (read != keySizeBytes) {
if (Files.exists(file)) { throw new IllegalArgumentException("key size did not match expected value; was the key generated with syskeygen?");
byte[] bytes = Files.readAllBytes(file);
return new SecretKeySpec(bytes, KEY_ALGO);
} }
return new SecretKeySpec(keyBytes, KEY_ALGO);
if (required) {
throw new FileNotFoundException("[" + file + "] must be present with a valid key");
}
return null;
} }
/** /**
@ -126,15 +118,8 @@ public class CryptoService extends AbstractComponent {
* @return character array representing the encrypted data * @return character array representing the encrypted data
*/ */
public char[] encrypt(char[] chars) { 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); 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(); return ENCRYPTED_TEXT_PREFIX.concat(base64).toCharArray();
} }
@ -144,10 +129,6 @@ public class CryptoService extends AbstractComponent {
* @return plaintext chars * @return plaintext chars
*/ */
public char[] decrypt(char[] chars) { public char[] decrypt(char[] chars) {
if (encryptionKey == null) {
return chars;
}
if (!isEncrypted(chars)) { if (!isEncrypted(chars)) {
// Not encrypted // Not encrypted
return chars; return chars;
@ -170,18 +151,10 @@ public class CryptoService extends AbstractComponent {
* @param chars the chars to check if they are encrypted * @param chars the chars to check if they are encrypted
* @return true is data is encrypted * @return true is data is encrypted
*/ */
public boolean isEncrypted(char[] chars) { protected boolean isEncrypted(char[] chars) {
return CharArrays.charsBeginsWith(ENCRYPTED_TEXT_PREFIX, 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) { private byte[] encryptInternal(byte[] bytes, SecretKey key) {
byte[] iv = new byte[ivLength]; byte[] iv = new byte[ivLength];
secureRandom.nextBytes(iv); 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 { try {
Cipher cipher = Cipher.getInstance(encryptionAlgorithm); Cipher cipher = Cipher.getInstance(encryptionAlgorithm);
cipher.init(mode, key, new IvParameterSpec(initializationVector)); 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 { private static SecretKey encryptionKey(SecretKey systemKey, int keyLength, String algorithm) throws NoSuchAlgorithmException {
if (systemKey == null) {
return null;
}
byte[] bytes = systemKey.getEncoded(); byte[] bytes = systemKey.getEncoded();
if ((bytes.length * 8) < keyLength) { if ((bytes.length * 8) < keyLength) {
throw new IllegalArgumentException("at least " + keyLength + " bits should be provided as key data"); 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_LENGTH_SETTING);
settings.add(ENCRYPTION_KEY_ALGO_SETTING); settings.add(ENCRYPTION_KEY_ALGO_SETTING);
settings.add(ENCRYPTION_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.io.PathUtils;
import org.elasticsearch.common.util.set.Sets; import org.elasticsearch.common.util.set.Sets;
import org.elasticsearch.env.Environment; import org.elasticsearch.env.Environment;
import org.elasticsearch.xpack.XPackPlugin;
import org.elasticsearch.xpack.security.crypto.CryptoService; import org.elasticsearch.xpack.security.crypto.CryptoService;
import java.nio.file.Files; import java.nio.file.Files;
@ -61,7 +62,7 @@ public class SystemKeyTool extends EnvironmentAwareCommand {
} }
keyPath = parsePath(args.get(0)); keyPath = parsePath(args.get(0));
} else { } else {
keyPath = CryptoService.resolveSystemKey(env); keyPath = env.configFile().resolve(XPackPlugin.NAME).resolve("system_key");
} }
// write the key // write the key
@ -75,7 +76,7 @@ public class SystemKeyTool extends EnvironmentAwareCommand {
if (view != null) { if (view != null) {
view.setPermissions(PERMISSION_OWNER_READ_WRITE); view.setPermissions(PERMISSION_OWNER_READ_WRITE);
terminal.println("Ensure the generated key can be read by the user that Elasticsearch runs as, " 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); 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.license.XPackLicenseState;
import org.elasticsearch.tasks.Task; import org.elasticsearch.tasks.Task;
import org.elasticsearch.threadpool.ThreadPool; import org.elasticsearch.threadpool.ThreadPool;
import org.elasticsearch.transport.TcpTransport;
import org.elasticsearch.transport.Transport; import org.elasticsearch.transport.Transport;
import org.elasticsearch.transport.TransportChannel; import org.elasticsearch.transport.TransportChannel;
import org.elasticsearch.transport.TransportException; import org.elasticsearch.transport.TransportException;
@ -28,7 +29,6 @@ import org.elasticsearch.transport.TransportResponse;
import org.elasticsearch.transport.TransportResponseHandler; import org.elasticsearch.transport.TransportResponseHandler;
import org.elasticsearch.transport.TransportService; import org.elasticsearch.transport.TransportService;
import org.elasticsearch.transport.TransportService.ContextRestoreResponseHandler; import org.elasticsearch.transport.TransportService.ContextRestoreResponseHandler;
import org.elasticsearch.transport.TransportSettings;
import org.elasticsearch.xpack.XPackSettings; import org.elasticsearch.xpack.XPackSettings;
import org.elasticsearch.xpack.security.SecurityContext; import org.elasticsearch.xpack.security.SecurityContext;
import org.elasticsearch.xpack.security.authc.AuthenticationService; 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); 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)); 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.BoundTransportAddress;
import org.elasticsearch.common.transport.TransportAddress; import org.elasticsearch.common.transport.TransportAddress;
import org.elasticsearch.license.XPackLicenseState; import org.elasticsearch.license.XPackLicenseState;
import org.elasticsearch.transport.TransportSettings; import org.elasticsearch.transport.TcpTransport;
import org.elasticsearch.xpack.security.audit.AuditTrailService; import org.elasticsearch.xpack.security.audit.AuditTrailService;
import java.net.InetSocketAddress; import java.net.InetSocketAddress;
@ -118,7 +118,7 @@ public class IPFilter {
isHttpFilterEnabled = IP_FILTER_ENABLED_HTTP_SETTING.get(settings); isHttpFilterEnabled = IP_FILTER_ENABLED_HTTP_SETTING.get(settings);
isIpFilterEnabled = IP_FILTER_ENABLED_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 // 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_HTTP_SETTING, this::setHttpFiltering);
clusterSettings.addSettingsUpdateConsumer(IP_FILTER_ENABLED_SETTING, this::setTransportFiltering); 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(TRANSPORT_FILTER_DENY_SETTING, this::setTransportDenyFilter);
clusterSettings.addSettingsUpdateConsumer(HTTP_FILTER_ALLOW_SETTING, this::setHttpAllowFilter); clusterSettings.addSettingsUpdateConsumer(HTTP_FILTER_ALLOW_SETTING, this::setHttpAllowFilter);
clusterSettings.addSettingsUpdateConsumer(HTTP_FILTER_DENY_SETTING, this::setHttpDenyFilter); 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(); updateRules();
} }

View File

@ -19,7 +19,7 @@ import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.common.util.BigArrays; import org.elasticsearch.common.util.BigArrays;
import org.elasticsearch.indices.breaker.CircuitBreakerService; import org.elasticsearch.indices.breaker.CircuitBreakerService;
import org.elasticsearch.threadpool.ThreadPool; import org.elasticsearch.threadpool.ThreadPool;
import org.elasticsearch.transport.TransportSettings; import org.elasticsearch.transport.TcpTransport;
import org.elasticsearch.transport.netty4.Netty4Transport; import org.elasticsearch.transport.netty4.Netty4Transport;
import org.elasticsearch.xpack.ssl.SSLConfiguration; import org.elasticsearch.xpack.ssl.SSLConfiguration;
import org.elasticsearch.xpack.ssl.SSLService; import org.elasticsearch.xpack.ssl.SSLService;
@ -65,8 +65,8 @@ public class SecurityNetty4Transport extends Netty4Transport {
profileConfiguration.put(entry.getKey(), configuration); profileConfiguration.put(entry.getKey(), configuration);
} }
if (profileConfiguration.containsKey(TransportSettings.DEFAULT_PROFILE) == false) { if (profileConfiguration.containsKey(TcpTransport.DEFAULT_PROFILE) == false) {
profileConfiguration.put(TransportSettings.DEFAULT_PROFILE, sslConfiguration); 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 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 * The reserved {@code elastic} superuser. Has full permission/access to the cluster/indices and can
* run as any other user. * run as any other user.
@ -15,8 +18,27 @@ public class ElasticUser extends User {
public static final String NAME = "elastic"; public static final String NAME = "elastic";
private static final String ROLE_NAME = "superuser"; private static final String ROLE_NAME = "superuser";
private static final String SETUP_MODE = "_setup_mode";
public ElasticUser(boolean enabled) { 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.component.AbstractComponent;
import org.elasticsearch.common.settings.Settings; import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.env.Environment; import org.elasticsearch.env.Environment;
import org.elasticsearch.transport.TransportSettings; import org.elasticsearch.transport.TcpTransport;
import org.elasticsearch.xpack.XPackSettings; import org.elasticsearch.xpack.XPackSettings;
import org.elasticsearch.xpack.common.socket.SocketAccess; import org.elasticsearch.xpack.common.socket.SocketAccess;
import org.elasticsearch.xpack.security.Security; import org.elasticsearch.xpack.security.Security;
@ -852,7 +852,7 @@ public class SSLService extends AbstractComponent {
private static List<Settings> getTransportProfileSSLSettings(Settings settings) { private static List<Settings> getTransportProfileSSLSettings(Settings settings) {
List<Settings> sslSettings = new ArrayList<>(); 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()) { for (Entry<String, Settings> entry : profiles.entrySet()) {
Settings profileSettings = entry.getValue().getByPrefix("xpack.security.ssl."); Settings profileSettings = entry.getValue().getByPrefix("xpack.security.ssl.");
if (profileSettings.isEmpty() == false) { 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.apache.logging.log4j.Logger;
import org.elasticsearch.action.ActionRequest; import org.elasticsearch.action.ActionRequest;
import org.elasticsearch.action.ActionResponse; import org.elasticsearch.action.ActionResponse;
import org.elasticsearch.bootstrap.BootstrapCheck;
import org.elasticsearch.cluster.NamedDiff; import org.elasticsearch.cluster.NamedDiff;
import org.elasticsearch.cluster.metadata.IndexNameExpressionResolver; import org.elasticsearch.cluster.metadata.IndexNameExpressionResolver;
import org.elasticsearch.cluster.metadata.IndexTemplateMetaData; 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.regex.Regex;
import org.elasticsearch.common.settings.ClusterSettings; import org.elasticsearch.common.settings.ClusterSettings;
import org.elasticsearch.common.settings.IndexScopedSettings; import org.elasticsearch.common.settings.IndexScopedSettings;
import org.elasticsearch.common.settings.SecureSetting;
import org.elasticsearch.common.settings.Setting; import org.elasticsearch.common.settings.Setting;
import org.elasticsearch.common.settings.Settings; import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.common.settings.SettingsFilter; import org.elasticsearch.common.settings.SettingsFilter;
import org.elasticsearch.common.unit.TimeValue; import org.elasticsearch.common.unit.TimeValue;
import org.elasticsearch.common.util.concurrent.EsExecutors; import org.elasticsearch.common.util.concurrent.EsExecutors;
import org.elasticsearch.common.xcontent.NamedXContentRegistry; import org.elasticsearch.common.xcontent.NamedXContentRegistry;
import org.elasticsearch.env.Environment;
import org.elasticsearch.index.IndexModule; import org.elasticsearch.index.IndexModule;
import org.elasticsearch.license.XPackLicenseState; import org.elasticsearch.license.XPackLicenseState;
import org.elasticsearch.plugins.ActionPlugin; 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.DateTime;
import org.joda.time.DateTimeZone; import org.joda.time.DateTimeZone;
import java.io.InputStream;
import java.time.Clock; import java.time.Clock;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Arrays; 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); new Setting<>("index.xpack.watcher.template.version", "", Function.identity(), Setting.Property.IndexScope);
public static final Setting<Boolean> ENCRYPT_SENSITIVE_DATA_SETTING = public static final Setting<Boolean> ENCRYPT_SENSITIVE_DATA_SETTING =
Setting.boolSetting("xpack.watcher.encrypt_sensitive_data", false, Setting.Property.NodeScope); 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 = public static final Setting<TimeValue> MAX_STOP_TIMEOUT_SETTING =
Setting.timeSetting("xpack.watcher.stop.timeout", TimeValue.timeValueSeconds(30), Setting.Property.NodeScope); 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.execution.scroll.size", 0, Setting.Property.NodeScope));
settings.add(Setting.intSetting("xpack.watcher.watch.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(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.search.default_timeout", Setting.Property.NodeScope));
settings.add(Setting.simpleString("xpack.watcher.internal.ops.bulk.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.execution.scroll.timeout", Setting.Property.NodeScope));
settings.add(Setting.simpleString("xpack.watcher.start_immediately", Setting.Property.NodeScope)); settings.add(Setting.simpleString("xpack.watcher.start_immediately", Setting.Property.NodeScope));
// encryption settings
CryptoService.addSettings(settings);
return settings; return settings;
} }
@ -512,4 +520,8 @@ public class Watcher implements ActionPlugin {
return map; 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.NamedXContentRegistry;
import org.elasticsearch.common.xcontent.XContentFactory; import org.elasticsearch.common.xcontent.XContentFactory;
import org.elasticsearch.common.xcontent.XContentParser; import org.elasticsearch.common.xcontent.XContentParser;
import org.elasticsearch.index.query.QueryParseContext;
import org.elasticsearch.script.Script; import org.elasticsearch.script.Script;
import org.elasticsearch.script.ScriptService; import org.elasticsearch.script.ScriptService;
import org.elasticsearch.script.TemplateScript; import org.elasticsearch.script.TemplateScript;
@ -63,7 +62,7 @@ public class WatcherSearchTemplateService extends AbstractComponent {
BytesReference source = request.getSearchSource(); BytesReference source = request.getSearchSource();
if (source != null && source.length() > 0) { if (source != null && source.length() > 0) {
try (XContentParser parser = XContentFactory.xContent(source).createParser(xContentRegistry, source)) { try (XContentParser parser = XContentFactory.xContent(source).createParser(xContentRegistry, source)) {
sourceBuilder.parseXContent(new QueryParseContext(parser)); sourceBuilder.parseXContent(parser);
searchRequest.source(sourceBuilder); 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.common.secret.Secret;
import org.elasticsearch.xpack.security.crypto.CryptoService; import org.elasticsearch.xpack.security.crypto.CryptoService;
import org.elasticsearch.xpack.support.clock.HaltedClock; 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.ActionRegistry;
import org.elasticsearch.xpack.watcher.actions.ActionStatus; import org.elasticsearch.xpack.watcher.actions.ActionStatus;
import org.elasticsearch.xpack.watcher.actions.ActionWrapper; import org.elasticsearch.xpack.watcher.actions.ActionWrapper;
@ -209,7 +208,7 @@ public class Watch implements ToXContentObject {
this.triggerService = triggerService; this.triggerService = triggerService;
this.actionRegistry = actionRegistry; this.actionRegistry = actionRegistry;
this.inputRegistry = inputRegistry; this.inputRegistry = inputRegistry;
this.cryptoService = Watcher.ENCRYPT_SENSITIVE_DATA_SETTING.get(settings) ? cryptoService : null; this.cryptoService = cryptoService;
this.defaultInput = new ExecutableNoneInput(logger); this.defaultInput = new ExecutableNoneInput(logger);
this.defaultCondition = AlwaysCondition.INSTANCE; this.defaultCondition = AlwaysCondition.INSTANCE;
this.defaultActions = Collections.emptyList(); this.defaultActions = Collections.emptyList();

View File

@ -74,8 +74,8 @@ public class BulkUpdateTests extends SecurityIntegTestCase {
public void testThatBulkUpdateDoesNotLoseFieldsHttp() throws IOException { public void testThatBulkUpdateDoesNotLoseFieldsHttp() throws IOException {
final String path = "/index1/type/1"; final String path = "/index1/type/1";
final Header basicAuthHeader = new BasicHeader("Authorization", final Header basicAuthHeader = new BasicHeader("Authorization",
UsernamePasswordToken.basicAuthHeaderValue(SecuritySettingsSource.DEFAULT_USER_NAME, UsernamePasswordToken.basicAuthHeaderValue(SecuritySettingsSource.TEST_USER_NAME,
new SecureString(SecuritySettingsSource.DEFAULT_PASSWORD.toCharArray()))); new SecureString(SecuritySettingsSource.TEST_PASSWORD.toCharArray())));
StringEntity body = new StringEntity("{\"test\":\"test\"}", ContentType.APPLICATION_JSON); StringEntity body = new StringEntity("{\"test\":\"test\"}", ContentType.APPLICATION_JSON);
Response response = getRestClient().performRequest("PUT", path, Collections.emptyMap(), body, basicAuthHeader); 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.test.SecuritySettingsSource;
import org.elasticsearch.xpack.security.action.realm.ClearRealmCacheRequest; import org.elasticsearch.xpack.security.action.realm.ClearRealmCacheRequest;
import org.elasticsearch.xpack.security.action.realm.ClearRealmCacheResponse; 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.Realm;
import org.elasticsearch.xpack.security.authc.Realms; import org.elasticsearch.xpack.security.authc.Realms;
import org.elasticsearch.xpack.security.authc.support.Hasher; 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.not;
import static org.hamcrest.Matchers.notNullValue; import static org.hamcrest.Matchers.notNullValue;
import static org.hamcrest.Matchers.sameInstance; import static org.hamcrest.Matchers.sameInstance;
import static org.mockito.Mockito.mock;
public class ClearRealmsCacheTests extends SecurityIntegTestCase { public class ClearRealmsCacheTests extends SecurityIntegTestCase {
private static final String USERS_PASSWD_HASHED = new String(Hasher.BCRYPT.hash(new SecureString("passwd".toCharArray()))); 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 { static void executeHttpRequest(String path, Map<String, String> params) throws Exception {
Response response = getRestClient().performRequest("POST", path, params, Response response = getRestClient().performRequest("POST", path, params,
new BasicHeader(UsernamePasswordToken.BASIC_AUTH_HEADER, new BasicHeader(UsernamePasswordToken.BASIC_AUTH_HEADER,
UsernamePasswordToken.basicAuthHeaderValue(SecuritySettingsSource.DEFAULT_USER_NAME, UsernamePasswordToken.basicAuthHeaderValue(SecuritySettingsSource.TEST_USER_NAME,
new SecureString(SecuritySettingsSource.DEFAULT_PASSWORD.toCharArray())))); new SecureString(SecuritySettingsSource.TEST_PASSWORD.toCharArray()))));
assertNotNull(response.getEntity()); assertNotNull(response.getEntity());
assertTrue(EntityUtils.toString(response.getEntity()).contains("cluster_name")); assertTrue(EntityUtils.toString(response.getEntity()).contains("cluster_name"));
} }
@ -233,7 +235,7 @@ public class ClearRealmsCacheTests extends SecurityIntegTestCase {
for (Realm realm : realms) { for (Realm realm : realms) {
for (String username : usernames) { for (String username : usernames) {
PlainActionFuture<User> future = new PlainActionFuture<>(); PlainActionFuture<User> future = new PlainActionFuture<>();
realm.authenticate(tokens.get(username), future); realm.authenticate(tokens.get(username), future, mock(IncomingRequest.class));
User user = future.actionGet(); User user = future.actionGet();
assertThat(user, notNullValue()); assertThat(user, notNullValue());
Map<Realm, User> realmToUser = users.get(username); Map<Realm, User> realmToUser = users.get(username);
@ -250,7 +252,7 @@ public class ClearRealmsCacheTests extends SecurityIntegTestCase {
for (String username : usernames) { for (String username : usernames) {
for (Realm realm : realms) { for (Realm realm : realms) {
PlainActionFuture<User> future = new PlainActionFuture<>(); PlainActionFuture<User> future = new PlainActionFuture<>();
realm.authenticate(tokens.get(username), future); realm.authenticate(tokens.get(username), future, mock(IncomingRequest.class));
User user = future.actionGet(); User user = future.actionGet();
assertThat(user, sameInstance(users.get(username).get(realm))); assertThat(user, sameInstance(users.get(username).get(realm)));
} }
@ -263,7 +265,7 @@ public class ClearRealmsCacheTests extends SecurityIntegTestCase {
for (String username : usernames) { for (String username : usernames) {
for (Realm realm : realms) { for (Realm realm : realms) {
PlainActionFuture<User> future = new PlainActionFuture<>(); PlainActionFuture<User> future = new PlainActionFuture<>();
realm.authenticate(tokens.get(username), future); realm.authenticate(tokens.get(username), future, mock(IncomingRequest.class));
User user = future.actionGet(); User user = future.actionGet();
assertThat(user, notNullValue()); assertThat(user, notNullValue());
scenario.assertEviction(users.get(username).get(realm), user); scenario.assertEviction(users.get(username).get(realm), user);

View File

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

View File

@ -7,7 +7,6 @@ package org.elasticsearch.integration;
import org.elasticsearch.ElasticsearchSecurityException; import org.elasticsearch.ElasticsearchSecurityException;
import org.elasticsearch.action.search.SearchResponse; import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.common.settings.SecureString;
import org.elasticsearch.index.query.QueryBuilders; import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.indices.TermsLookup; import org.elasticsearch.indices.TermsLookup;
import org.elasticsearch.test.SecurityIntegTestCase; import org.elasticsearch.test.SecurityIntegTestCase;
@ -26,7 +25,7 @@ public class SecurityCachePermissionTests extends SecurityIntegTestCase {
@Override @Override
public String configUsers() { public String configUsers() {
return super.configUsers() return super.configUsers()
+ READ_ONE_IDX_USER + ":" + SecuritySettingsSource.DEFAULT_PASSWORD_HASHED + "\n"; + READ_ONE_IDX_USER + ":" + SecuritySettingsSource.TEST_PASSWORD_HASHED + "\n";
} }
@Override @Override
@ -61,7 +60,7 @@ public class SecurityCachePermissionTests extends SecurityIntegTestCase {
// Repeat with unauthorized user!!!! // Repeat with unauthorized user!!!!
try { try {
response = client().filterWithHeader(singletonMap("Authorization", basicAuthHeaderValue(READ_ONE_IDX_USER, 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( .prepareSearch("data").setTypes("a").setQuery(QueryBuilders.constantScoreQuery(
QueryBuilders.termsLookupQuery("token", new TermsLookup("tokens", "tokens", "1", "tokens")))) QueryBuilders.termsLookupQuery("token", new TermsLookup("tokens", "tokens", "1", "tokens"))))
.execute().actionGet(); .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") @TestLogging("org.elasticsearch.cluster.service:TRACE,org.elasticsearch.discovery.zen:TRACE")
public class LicensingTests extends SecurityIntegTestCase { public class LicensingTests extends SecurityIntegTestCase {
public static final String ROLES = public static final String ROLES =
SecuritySettingsSource.DEFAULT_ROLE + ":\n" + SecuritySettingsSource.TEST_ROLE + ":\n" +
" cluster: [ all ]\n" + " cluster: [ all ]\n" +
" indices:\n" + " indices:\n" +
" - names: '*'\n" + " - names: '*'\n" +
@ -204,8 +204,8 @@ public class LicensingTests extends SecurityIntegTestCase {
e = expectThrows(ResponseException.class, () -> getRestClient().performRequest("GET", "/_xpack/security/_authenticate")); e = expectThrows(ResponseException.class, () -> getRestClient().performRequest("GET", "/_xpack/security/_authenticate"));
assertThat(e.getResponse().getStatusLine().getStatusCode(), is(401)); assertThat(e.getResponse().getStatusLine().getStatusCode(), is(401));
final String basicAuthValue = UsernamePasswordToken.basicAuthHeaderValue(SecuritySettingsSource.DEFAULT_USER_NAME, final String basicAuthValue = UsernamePasswordToken.basicAuthHeaderValue(SecuritySettingsSource.TEST_USER_NAME,
new SecureString(SecuritySettingsSource.DEFAULT_PASSWORD.toCharArray())); new SecureString(SecuritySettingsSource.TEST_PASSWORD.toCharArray()));
response = getRestClient().performRequest("GET", "/", new BasicHeader("Authorization", basicAuthValue)); response = getRestClient().performRequest("GET", "/", new BasicHeader("Authorization", basicAuthValue));
assertThat(response.getStatusLine().getStatusCode(), is(200)); assertThat(response.getStatusLine().getStatusCode(), is(200));
response = getRestClient() response = getRestClient()

View File

@ -5,10 +5,28 @@
*/ */
package org.elasticsearch.test; 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.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.After;
import org.junit.Before; 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 * 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 @Before
public void ensureNativeStoresStarted() throws Exception { public void ensureNativeStoresStarted() throws Exception {
assertSecurityIndexActive(); assertSecurityIndexActive();
setupReservedPasswords();
} }
@After @After
@ -29,4 +48,41 @@ public abstract class NativeRealmIntegTestCase extends SecurityIntegTestCase {
client.prepareClearRealmCache().get(); 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 @Override
protected Settings externalClusterClientSettings() { protected Settings externalClusterClientSettings() {
return Settings.builder() return Settings.builder()
.put(Security.USER_SETTING.getKey(), SecuritySettingsSource.DEFAULT_USER_NAME + ":" .put(Security.USER_SETTING.getKey(), SecuritySettingsSource.TEST_USER_NAME + ":"
+ SecuritySettingsSource.DEFAULT_PASSWORD) + SecuritySettingsSource.TEST_PASSWORD)
.build(); .build();
} }

View File

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

View File

@ -55,7 +55,7 @@ public class SecurityTestsUtils {
public static void assertAuthorizationExceptionDefaultUsers(Throwable throwable, String action) { public static void assertAuthorizationExceptionDefaultUsers(Throwable throwable, String action) {
assertAuthorizationException(throwable, either(containsString("[" + action + "] is unauthorized for user [" 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 + "]"))); + 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.Response;
import org.elasticsearch.client.ResponseException; import org.elasticsearch.client.ResponseException;
import org.elasticsearch.client.RestClient; import org.elasticsearch.client.RestClient;
import org.elasticsearch.common.settings.SecureString;
import org.elasticsearch.common.settings.Settings; import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.common.util.concurrent.ThreadContext; import org.elasticsearch.common.util.concurrent.ThreadContext;
import org.elasticsearch.test.SecuritySettingsSource;
import org.elasticsearch.test.rest.ESRestTestCase; import org.elasticsearch.test.rest.ESRestTestCase;
import org.elasticsearch.xpack.ml.MachineLearning; import org.elasticsearch.xpack.ml.MachineLearning;
import org.junit.After; import org.junit.After;
@ -33,9 +33,9 @@ import static org.hamcrest.Matchers.equalTo;
public class DatafeedJobsRestIT extends ESRestTestCase { public class DatafeedJobsRestIT extends ESRestTestCase {
private static final String BASIC_AUTH_VALUE_ELASTIC = 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 = 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 @Override
protected Settings restClientSettings() { protected Settings restClientSettings() {
@ -50,11 +50,16 @@ public class DatafeedJobsRestIT extends ESRestTestCase {
@Before @Before
public void setUpData() throws Exception { 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 // This user has admin rights on machine learning, but (importantly for the tests) no
// rights on any of the data indexes // rights on any of the data indexes
String user = "{" String user = "{"
+ " \"password\" : \"changeme\"," + " \"password\" : \"" + password + "\","
+ " \"roles\" : [ \"machine_learning_admin\" ]" + " \"roles\" : [ \"machine_learning_admin\" ]"
+ "}"; + "}";

View File

@ -9,11 +9,11 @@ import org.apache.http.entity.ContentType;
import org.apache.http.entity.StringEntity; import org.apache.http.entity.StringEntity;
import org.elasticsearch.client.Response; import org.elasticsearch.client.Response;
import org.elasticsearch.client.ResponseException; import org.elasticsearch.client.ResponseException;
import org.elasticsearch.common.settings.SecureString;
import org.elasticsearch.common.settings.Settings; import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.common.util.concurrent.ConcurrentCollections; import org.elasticsearch.common.util.concurrent.ConcurrentCollections;
import org.elasticsearch.common.util.concurrent.ConcurrentMapLong; import org.elasticsearch.common.util.concurrent.ConcurrentMapLong;
import org.elasticsearch.common.util.concurrent.ThreadContext; import org.elasticsearch.common.util.concurrent.ThreadContext;
import org.elasticsearch.test.SecuritySettingsSource;
import org.elasticsearch.test.rest.ESRestTestCase; import org.elasticsearch.test.rest.ESRestTestCase;
import org.elasticsearch.xpack.ml.MachineLearning; import org.elasticsearch.xpack.ml.MachineLearning;
import org.elasticsearch.xpack.ml.job.persistence.AnomalyDetectorsIndex; import org.elasticsearch.xpack.ml.job.persistence.AnomalyDetectorsIndex;
@ -36,7 +36,7 @@ import static org.hamcrest.Matchers.not;
public class MlJobIT extends ESRestTestCase { 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 @Override
protected Settings restClientSettings() { protected Settings restClientSettings() {

View File

@ -20,6 +20,7 @@ import org.elasticsearch.common.xcontent.json.JsonXContent;
import org.elasticsearch.search.SearchModule; import org.elasticsearch.search.SearchModule;
import org.elasticsearch.tasks.Task; import org.elasticsearch.tasks.Task;
import org.elasticsearch.test.SecurityIntegTestCase; import org.elasticsearch.test.SecurityIntegTestCase;
import org.elasticsearch.test.SecuritySettingsSource;
import org.elasticsearch.xpack.XPackSettings; import org.elasticsearch.xpack.XPackSettings;
import org.elasticsearch.xpack.ml.MlMetadata; import org.elasticsearch.xpack.ml.MlMetadata;
import org.elasticsearch.xpack.ml.action.CloseJobAction; import org.elasticsearch.xpack.ml.action.CloseJobAction;
@ -80,7 +81,7 @@ abstract class MlNativeAutodetectIntegTestCase extends SecurityIntegTestCase {
protected Settings externalClusterClientSettings() { protected Settings externalClusterClientSettings() {
Settings.Builder builder = Settings.builder(); Settings.Builder builder = Settings.builder();
builder.put(NetworkModule.TRANSPORT_TYPE_KEY, Security.NAME4); 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); builder.put(XPackSettings.MACHINE_LEARNING_ENABLED.getKey(), true);
return builder.build(); return builder.build();
} }

View File

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

View File

@ -84,8 +84,8 @@ public class OldMonitoringIndicesBackwardsCompatibilityTests extends AbstractOld
httpExporter.put("type", "http"); httpExporter.put("type", "http");
httpExporter.put("enabled", port == null ? "false" : "true"); httpExporter.put("enabled", port == null ? "false" : "true");
httpExporter.put("host", "http://localhost:" + (port == null ? "does_not_matter" : port)); httpExporter.put("host", "http://localhost:" + (port == null ? "does_not_matter" : port));
httpExporter.put("auth.username", SecuritySettingsSource.DEFAULT_USER_NAME); httpExporter.put("auth.username", SecuritySettingsSource.TEST_USER_NAME);
httpExporter.put("auth.password", SecuritySettingsSource.DEFAULT_PASSWORD); httpExporter.put("auth.password", SecuritySettingsSource.TEST_PASSWORD);
settings.putProperties(httpExporter, k -> MonitoringSettings.EXPORTERS_SETTINGS.getKey() + "my_exporter." + k); 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.index.query.QueryBuilders;
import org.elasticsearch.plugins.Plugin; import org.elasticsearch.plugins.Plugin;
import org.elasticsearch.test.ESIntegTestCase; import org.elasticsearch.test.ESIntegTestCase;
import org.elasticsearch.test.SecuritySettingsSource;
import org.elasticsearch.test.TestCluster; import org.elasticsearch.test.TestCluster;
import org.elasticsearch.test.store.MockFSIndexStore; import org.elasticsearch.test.store.MockFSIndexStore;
import org.elasticsearch.test.transport.MockTransportService; import org.elasticsearch.test.transport.MockTransportService;
@ -157,7 +158,7 @@ public abstract class MonitoringIntegTestCase extends ESIntegTestCase {
return Settings.builder() return Settings.builder()
.put(super.transportClientSettings()) .put(super.transportClientSettings())
.put("client.transport.sniff", false) .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.TRANSPORT_TYPE_KEY, Security.NAME4)
.put(NetworkModule.HTTP_TYPE_KEY, Security.NAME4) .put(NetworkModule.HTTP_TYPE_KEY, Security.NAME4)
.put(XPackSettings.WATCHER_ENABLED.getKey(), watcherEnabled) .put(XPackSettings.WATCHER_ENABLED.getKey(), watcherEnabled)
@ -467,7 +468,7 @@ public abstract class MonitoringIntegTestCase extends ESIntegTestCase {
public static class SecuritySettings { public static class SecuritySettings {
public static final String TEST_USERNAME = "test"; 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()))); 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); static boolean auditLogsEnabled = SystemPropertyUtil.getBoolean("tests.audit_logs", true);

View File

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

View File

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

View File

@ -5,15 +5,22 @@
*/ */
package org.elasticsearch.xpack.security; 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.ElasticsearchSecurityException;
import org.elasticsearch.action.admin.cluster.health.ClusterHealthResponse; import org.elasticsearch.action.admin.cluster.health.ClusterHealthResponse;
import org.elasticsearch.client.Client; import org.elasticsearch.client.Client;
import org.elasticsearch.client.RestClient;
import org.elasticsearch.client.RestClientBuilder;
import org.elasticsearch.cluster.ClusterState; import org.elasticsearch.cluster.ClusterState;
import org.elasticsearch.cluster.ClusterStateObserver; import org.elasticsearch.cluster.ClusterStateObserver;
import org.elasticsearch.cluster.service.ClusterService; import org.elasticsearch.cluster.service.ClusterService;
import org.elasticsearch.common.UUIDs; import org.elasticsearch.common.UUIDs;
import org.elasticsearch.common.network.NetworkModule;
import org.elasticsearch.common.settings.MockSecureSettings; import org.elasticsearch.common.settings.MockSecureSettings;
import org.elasticsearch.common.settings.SecureSettings;
import org.elasticsearch.common.settings.SecureString; import org.elasticsearch.common.settings.SecureString;
import org.elasticsearch.common.settings.Settings; import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.common.unit.TimeValue; 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.action.user.PutUserResponse;
import org.elasticsearch.xpack.security.authc.support.UsernamePasswordToken; import org.elasticsearch.xpack.security.authc.support.UsernamePasswordToken;
import org.elasticsearch.xpack.security.client.SecurityClient; import org.elasticsearch.xpack.security.client.SecurityClient;
import org.elasticsearch.xpack.security.user.ElasticUser;
import org.elasticsearch.xpack.security.support.IndexLifecycleManager; import org.elasticsearch.xpack.security.support.IndexLifecycleManager;
import org.junit.After; import org.junit.After;
import org.junit.AfterClass; import org.junit.AfterClass;
import org.junit.BeforeClass; import org.junit.BeforeClass;
import java.net.InetSocketAddress;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collections; import java.util.Collections;
import java.util.HashMap; import java.util.HashMap;
@ -76,7 +86,16 @@ public class SecurityTribeIT extends NativeRealmIntegTestCase {
super.setUp(); super.setUp();
if (cluster2 == null) { if (cluster2 == null) {
SecuritySettingsSource cluster2SettingsSource = 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, cluster2 = new InternalTestCluster(randomLong(), createTempDir(), true, true, 1, 2,
UUIDs.randomBase64UUID(random()), cluster2SettingsSource, 0, false, SECOND_CLUSTER_NODE_PREFIX, getMockPlugins(), UUIDs.randomBase64UUID(random()), cluster2SettingsSource, 0, false, SECOND_CLUSTER_NODE_PREFIX, getMockPlugins(),
getClientWrapper()); getClientWrapper());
@ -85,6 +104,11 @@ public class SecurityTribeIT extends NativeRealmIntegTestCase {
} }
} }
@Override
public boolean shouldSetReservedUserPasswords() {
return false;
}
@Override @Override
public boolean useGeneratedSSLConfig() { public boolean useGeneratedSSLConfig() {
return useGeneratedSSL; return useGeneratedSSL;
@ -138,8 +162,17 @@ public class SecurityTribeIT extends NativeRealmIntegTestCase {
private void setupTribeNode(Settings settings) throws NodeValidationException, InterruptedException { private void setupTribeNode(Settings settings) throws NodeValidationException, InterruptedException {
SecuritySettingsSource cluster2SettingsSource = SecuritySettingsSource cluster2SettingsSource =
new SecuritySettingsSource(1, useGeneratedSSL, createTempDir(), Scope.TEST); new SecuritySettingsSource(1, useGeneratedSSL, createTempDir(), Scope.TEST) {
Map<String,String> asMap = new HashMap<>(cluster2SettingsSource.nodeSettings(0).getAsMap()); @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()); asMap.remove(NodeEnvironment.MAX_LOCAL_STORAGE_NODES_SETTING.getKey());
Settings.Builder tribe1Defaults = Settings.builder(); Settings.Builder tribe1Defaults = Settings.builder();
Settings.Builder tribe2Defaults = Settings.builder(); Settings.Builder tribe2Defaults = Settings.builder();
@ -216,9 +249,25 @@ public class SecurityTribeIT extends NativeRealmIntegTestCase {
} }
public void testThatTribeCanAuthenticateElasticUser() throws Exception { 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); setupTribeNode(Settings.EMPTY);
ClusterHealthResponse response = tribeClient.filterWithHeader(Collections.singletonMap("Authorization", 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(); .admin().cluster().prepareHealth().get();
assertNoTimeout(response); assertNoTimeout(response);
} }
@ -308,7 +357,7 @@ public class SecurityTribeIT extends NativeRealmIntegTestCase {
PutUserResponse response = PutUserResponse response =
securityClient(nonPreferredClient).preparePutUser(username, "password".toCharArray(), "superuser").get(); securityClient(nonPreferredClient).preparePutUser(username, "password".toCharArray(), "superuser").get();
assertTrue(response.created()); assertTrue(response.created());
shouldBeSuccessfulUsers.add(username); shouldBeSuccessfulUsers.add(username);
} }
assertTribeNodeHasAllIndices(); assertTribeNodeHasAllIndices();

View File

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

View File

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

View File

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

View File

@ -183,8 +183,8 @@ public class IndexAuditTrailTests extends SecurityIntegTestCase {
Settings.Builder builder = Settings.builder() Settings.Builder builder = Settings.builder()
.put("xpack.security.audit.index.client." + XPackSettings.SECURITY_ENABLED.getKey(), useSecurity) .put("xpack.security.audit.index.client." + XPackSettings.SECURITY_ENABLED.getKey(), useSecurity)
.put(remoteSettings(NetworkAddress.format(inet.address().getAddress()), inet.address().getPort(), cluster2Name)) .put(remoteSettings(NetworkAddress.format(inet.address().getAddress()), inet.address().getPort(), cluster2Name))
.put("xpack.security.audit.index.client.xpack.security.user", SecuritySettingsSource.DEFAULT_USER_NAME + ":" + .put("xpack.security.audit.index.client.xpack.security.user", SecuritySettingsSource.TEST_USER_NAME + ":" +
SecuritySettingsSource.DEFAULT_PASSWORD); SecuritySettingsSource.TEST_PASSWORD);
if (useGeneratedSSL == false) { if (useGeneratedSSL == false) {
cluster2SettingsSource.addClientSSLSettings(builder, "xpack.security.audit.index.client."); 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")) .put("xpack.security.audit.outputs", randomFrom("index", "index,logfile"))
.putArray("xpack.security.audit.index.client.hosts", addresses.toArray(new String[addresses.size()])) .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.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."); addClientSSLSettings(builder, "xpack.security.audit.index.client.");
return builder.build(); return builder.build();

View File

@ -5,16 +5,6 @@
*/ */
package org.elasticsearch.xpack.security.authc; 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.apache.lucene.util.SetOnce;
import org.elasticsearch.ElasticsearchException; import org.elasticsearch.ElasticsearchException;
import org.elasticsearch.ElasticsearchSecurityException; import org.elasticsearch.ElasticsearchSecurityException;
@ -24,11 +14,14 @@ import org.elasticsearch.action.get.GetRequest;
import org.elasticsearch.action.get.GetResponse; import org.elasticsearch.action.get.GetResponse;
import org.elasticsearch.action.support.PlainActionFuture; import org.elasticsearch.action.support.PlainActionFuture;
import org.elasticsearch.client.Client; import org.elasticsearch.client.Client;
import org.elasticsearch.common.SuppressForbidden;
import org.elasticsearch.common.io.stream.BytesStreamOutput; import org.elasticsearch.common.io.stream.BytesStreamOutput;
import org.elasticsearch.common.io.stream.StreamInput; import org.elasticsearch.common.io.stream.StreamInput;
import org.elasticsearch.common.settings.SecureString; import org.elasticsearch.common.settings.SecureString;
import org.elasticsearch.common.settings.Settings; import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.common.transport.TransportAddress;
import org.elasticsearch.common.util.concurrent.ThreadContext; import org.elasticsearch.common.util.concurrent.ThreadContext;
import org.elasticsearch.common.xcontent.NamedXContentRegistry;
import org.elasticsearch.env.Environment; import org.elasticsearch.env.Environment;
import org.elasticsearch.license.XPackLicenseState; import org.elasticsearch.license.XPackLicenseState;
import org.elasticsearch.rest.RestRequest; import org.elasticsearch.rest.RestRequest;
@ -53,6 +46,18 @@ import org.elasticsearch.xpack.security.user.User;
import org.junit.After; import org.junit.After;
import org.junit.Before; 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.test.SecurityTestsUtils.assertAuthenticationException;
import static org.elasticsearch.xpack.security.support.Exceptions.authenticationError; import static org.elasticsearch.xpack.security.support.Exceptions.authenticationError;
import static org.hamcrest.Matchers.arrayContaining; import static org.hamcrest.Matchers.arrayContaining;
@ -93,12 +98,16 @@ public class AuthenticationServiceTests extends ESTestCase {
private TokenService tokenService; private TokenService tokenService;
private SecurityLifecycleService lifecycleService; private SecurityLifecycleService lifecycleService;
private Client client; private Client client;
private InetSocketAddress remoteAddress;
@Before @Before
@SuppressForbidden(reason = "Allow accessing localhost")
public void init() throws Exception { public void init() throws Exception {
token = mock(AuthenticationToken.class); token = mock(AuthenticationToken.class);
message = new InternalMessage(); 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); threadContext = new ThreadContext(Settings.EMPTY);
firstRealm = mock(Realm.class); firstRealm = mock(Realm.class);
@ -206,7 +215,7 @@ public class AuthenticationServiceTests extends ESTestCase {
}, this::logAndFail)); }, this::logAndFail));
verify(auditTrail).authenticationSuccess(secondRealm.name(), user, "_action", message); verify(auditTrail).authenticationSuccess(secondRealm.name(), user, "_action", message);
verifyNoMoreInteractions(auditTrail); 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()); assertTrue(completed.get());
} }
@ -562,7 +571,7 @@ public class AuthenticationServiceTests extends ESTestCase {
when(secondRealm.token(threadContext)).thenReturn(token); when(secondRealm.token(threadContext)).thenReturn(token);
when(secondRealm.supports(token)).thenReturn(true); when(secondRealm.supports(token)).thenReturn(true);
doThrow(authenticationError("realm doesn't like authenticate")) 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 { try {
authenticateBlocking("_action", message, null); authenticateBlocking("_action", message, null);
fail("exception should bubble out"); fail("exception should bubble out");
@ -577,7 +586,7 @@ public class AuthenticationServiceTests extends ESTestCase {
when(secondRealm.token(threadContext)).thenReturn(token); when(secondRealm.token(threadContext)).thenReturn(token);
when(secondRealm.supports(token)).thenReturn(true); when(secondRealm.supports(token)).thenReturn(true);
doThrow(authenticationError("realm doesn't like authenticate")) 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 { try {
authenticateBlocking(restRequest); authenticateBlocking(restRequest);
fail("exception should bubble out"); fail("exception should bubble out");
@ -869,7 +878,7 @@ public class AuthenticationServiceTests extends ESTestCase {
ActionListener listener = (ActionListener) i.getArguments()[1]; ActionListener listener = (ActionListener) i.getArguments()[1];
listener.onResponse(user); listener.onResponse(user);
return null; 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) { private Authentication authenticateBlocking(RestRequest restRequest) {

View File

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

View File

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

View File

@ -50,8 +50,8 @@ public class TokenAuthIntegTests extends SecurityIntegTestCase {
SecurityClient securityClient = new SecurityClient(client); SecurityClient securityClient = new SecurityClient(client);
CreateTokenResponse response = securityClient.prepareCreateToken() CreateTokenResponse response = securityClient.prepareCreateToken()
.setGrantType("password") .setGrantType("password")
.setUsername(SecuritySettingsSource.DEFAULT_USER_NAME) .setUsername(SecuritySettingsSource.TEST_USER_NAME)
.setPassword(new SecureString(SecuritySettingsSource.DEFAULT_PASSWORD.toCharArray())) .setPassword(new SecureString(SecuritySettingsSource.TEST_PASSWORD.toCharArray()))
.get(); .get();
Instant created = Instant.now(); Instant created = Instant.now();
@ -90,8 +90,8 @@ public class TokenAuthIntegTests extends SecurityIntegTestCase {
public void testExpireMultipleTimes() throws Exception { public void testExpireMultipleTimes() throws Exception {
CreateTokenResponse response = securityClient().prepareCreateToken() CreateTokenResponse response = securityClient().prepareCreateToken()
.setGrantType("password") .setGrantType("password")
.setUsername(SecuritySettingsSource.DEFAULT_USER_NAME) .setUsername(SecuritySettingsSource.TEST_USER_NAME)
.setPassword(new SecureString(SecuritySettingsSource.DEFAULT_PASSWORD.toCharArray())) .setPassword(new SecureString(SecuritySettingsSource.TEST_PASSWORD.toCharArray()))
.get(); .get();
InvalidateTokenResponse invalidateResponse = securityClient().prepareInvalidateToken(response.getTokenString()).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.SecurityLifecycleService;
import org.elasticsearch.xpack.security.authc.support.CharArrays; import org.elasticsearch.xpack.security.authc.support.CharArrays;
import org.elasticsearch.xpack.security.client.SecurityClient; import org.elasticsearch.xpack.security.client.SecurityClient;
import org.junit.AfterClass;
import org.junit.BeforeClass; import org.junit.BeforeClass;
import java.nio.charset.StandardCharsets; import java.nio.charset.StandardCharsets;
@ -39,6 +40,11 @@ public class ESNativeMigrateToolTests extends NativeRealmIntegTestCase {
useSSL = randomBoolean(); useSSL = randomBoolean();
} }
@Override
public boolean shouldSetReservedUserPasswords() {
return false;
}
@Override @Override
public Settings nodeSettings(int nodeOrdinal) { public Settings nodeSettings(int nodeOrdinal) {
logger.info("--> use SSL? {}", useSSL); 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.Strings;
import org.elasticsearch.common.settings.Settings; import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.env.Environment; import org.elasticsearch.env.Environment;
import org.elasticsearch.test.SecuritySettingsSource;
import org.elasticsearch.xpack.security.authz.RoleDescriptor; import org.elasticsearch.xpack.security.authz.RoleDescriptor;
import java.io.FileNotFoundException; import java.io.FileNotFoundException;
@ -104,9 +105,12 @@ public class ESNativeRealmMigrateToolTests extends CommandTestCase {
Files.createDirectories(xpackConfDir); Files.createDirectories(xpackConfDir);
ESNativeRealmMigrateTool.MigrateUserOrRoles muor = new ESNativeRealmMigrateTool.MigrateUserOrRoles(); 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(); Settings settings = Settings.builder().put("path.home", homeDir).build();
Environment environment = new Environment(settings, confDir); Environment environment = new Environment(settings, confDir);
MockTerminal mockTerminal = new MockTerminal(); MockTerminal mockTerminal = new MockTerminal();
FileNotFoundException fnfe = expectThrows(FileNotFoundException.class, FileNotFoundException fnfe = expectThrows(FileNotFoundException.class,

View File

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

View File

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

View File

@ -111,9 +111,9 @@ public class NativeUsersStoreTests extends ESTestCase {
actionRespond(GetRequest.class, new GetResponse(result)); actionRespond(GetRequest.class, new GetResponse(result));
final NativeUsersStore.ReservedUserInfo userInfo = future.get(); final NativeUsersStore.ReservedUserInfo userInfo = future.get();
assertThat(userInfo.hasDefaultPassword, equalTo(true)); assertThat(userInfo.hasEmptyPassword, equalTo(true));
assertThat(userInfo.enabled, 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 { public void testInContainerTrueReturnsEmptyPasswordForNonElasticReservedUsers() throws Exception {
@ -142,9 +142,9 @@ public class NativeUsersStoreTests extends ESTestCase {
actionRespond(GetRequest.class, new GetResponse(result)); actionRespond(GetRequest.class, new GetResponse(result));
final NativeUsersStore.ReservedUserInfo userInfo = future.get(); final NativeUsersStore.ReservedUserInfo userInfo = future.get();
assertThat(userInfo.hasDefaultPassword, equalTo(true)); assertThat(userInfo.hasEmptyPassword, equalTo(true));
assertThat(userInfo.enabled, 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 { public void testInContainerTrueReturnsBootstrapPasswordForElastic() throws Exception {
@ -171,7 +171,7 @@ public class NativeUsersStoreTests extends ESTestCase {
actionRespond(GetRequest.class, new GetResponse(result)); actionRespond(GetRequest.class, new GetResponse(result));
final NativeUsersStore.ReservedUserInfo userInfo = future.get(); final NativeUsersStore.ReservedUserInfo userInfo = future.get();
assertThat(userInfo.hasDefaultPassword, equalTo(false)); assertThat(userInfo.hasEmptyPassword, equalTo(false));
assertThat(userInfo.enabled, equalTo(true)); assertThat(userInfo.enabled, equalTo(true));
assertThat(userInfo.passwordHash, equalTo(passwordHash)); 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.ElasticsearchSecurityException;
import org.elasticsearch.action.admin.cluster.health.ClusterHealthResponse; import org.elasticsearch.action.admin.cluster.health.ClusterHealthResponse;
import org.elasticsearch.common.settings.SecureString; 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.client.SecurityClient;
import org.elasticsearch.xpack.security.user.BeatsSystemUser;
import org.elasticsearch.xpack.security.user.ElasticUser; import org.elasticsearch.xpack.security.user.ElasticUser;
import org.elasticsearch.xpack.security.user.KibanaUser; import org.elasticsearch.xpack.security.user.KibanaUser;
import org.elasticsearch.xpack.security.action.user.ChangePasswordResponse; import org.elasticsearch.xpack.security.user.LogstashSystemUser;
import org.elasticsearch.test.NativeRealmIntegTestCase;
import java.util.Arrays; import java.util.Arrays;
@ -27,12 +29,10 @@ import static org.hamcrest.Matchers.notNullValue;
*/ */
public class ReservedRealmIntegTests extends NativeRealmIntegTestCase { public class ReservedRealmIntegTests extends NativeRealmIntegTestCase {
private static final SecureString DEFAULT_PASSWORD = new SecureString("changeme".toCharArray());
public void testAuthenticate() { 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() ClusterHealthResponse response = client()
.filterWithHeader(singletonMap("Authorization", basicAuthHeaderValue(username, DEFAULT_PASSWORD))) .filterWithHeader(singletonMap("Authorization", basicAuthHeaderValue(username, getReservedPassword())))
.admin() .admin()
.cluster() .cluster()
.prepareHealth() .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. * the reserved realm.
*/ */
public void testAuthenticateAfterEnablingUser() { public void testAuthenticateAfterEnablingUser() {
final SecurityClient c = securityClient(); 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(); c.prepareSetEnabled(username, true).get();
ClusterHealthResponse response = client() ClusterHealthResponse response = client()
.filterWithHeader(singletonMap("Authorization", basicAuthHeaderValue(username, DEFAULT_PASSWORD))) .filterWithHeader(singletonMap("Authorization", basicAuthHeaderValue(username, getReservedPassword())))
.admin() .admin()
.cluster() .cluster()
.prepareHealth() .prepareHealth()
@ -62,12 +62,12 @@ public class ReservedRealmIntegTests extends NativeRealmIntegTestCase {
} }
public void testChangingPassword() { 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(); final char[] newPassword = "supersecretvalue".toCharArray();
if (randomBoolean()) { if (randomBoolean()) {
ClusterHealthResponse response = client() ClusterHealthResponse response = client()
.filterWithHeader(singletonMap("Authorization", basicAuthHeaderValue(username, DEFAULT_PASSWORD))) .filterWithHeader(singletonMap("Authorization", basicAuthHeaderValue(username, getReservedPassword())))
.admin() .admin()
.cluster() .cluster()
.prepareHealth() .prepareHealth()
@ -81,7 +81,7 @@ public class ReservedRealmIntegTests extends NativeRealmIntegTestCase {
assertThat(response, notNullValue()); assertThat(response, notNullValue());
ElasticsearchSecurityException elasticsearchSecurityException = expectThrows(ElasticsearchSecurityException.class, () -> client() ElasticsearchSecurityException elasticsearchSecurityException = expectThrows(ElasticsearchSecurityException.class, () -> client()
.filterWithHeader(singletonMap("Authorization", basicAuthHeaderValue(username, DEFAULT_PASSWORD))) .filterWithHeader(singletonMap("Authorization", basicAuthHeaderValue(username, getReservedPassword())))
.admin() .admin()
.cluster() .cluster()
.prepareHealth() .prepareHealth()
@ -100,7 +100,7 @@ public class ReservedRealmIntegTests extends NativeRealmIntegTestCase {
public void testDisablingUser() throws Exception { public void testDisablingUser() throws Exception {
// validate the user works // validate the user works
ClusterHealthResponse response = client() ClusterHealthResponse response = client()
.filterWithHeader(singletonMap("Authorization", basicAuthHeaderValue(ElasticUser.NAME, DEFAULT_PASSWORD))) .filterWithHeader(singletonMap("Authorization", basicAuthHeaderValue(ElasticUser.NAME, getReservedPassword())))
.admin() .admin()
.cluster() .cluster()
.prepareHealth() .prepareHealth()
@ -110,7 +110,7 @@ public class ReservedRealmIntegTests extends NativeRealmIntegTestCase {
// disable user // disable user
securityClient().prepareSetEnabled(ElasticUser.NAME, false).get(); securityClient().prepareSetEnabled(ElasticUser.NAME, false).get();
ElasticsearchSecurityException elasticsearchSecurityException = expectThrows(ElasticsearchSecurityException.class, () -> client() ElasticsearchSecurityException elasticsearchSecurityException = expectThrows(ElasticsearchSecurityException.class, () -> client()
.filterWithHeader(singletonMap("Authorization", basicAuthHeaderValue(ElasticUser.NAME, DEFAULT_PASSWORD))) .filterWithHeader(singletonMap("Authorization", basicAuthHeaderValue(ElasticUser.NAME, getReservedPassword())))
.admin() .admin()
.cluster() .cluster()
.prepareHealth() .prepareHealth()
@ -120,7 +120,7 @@ public class ReservedRealmIntegTests extends NativeRealmIntegTestCase {
//enable //enable
securityClient().prepareSetEnabled(ElasticUser.NAME, true).get(); securityClient().prepareSetEnabled(ElasticUser.NAME, true).get();
response = client() response = client()
.filterWithHeader(singletonMap("Authorization", basicAuthHeaderValue(ElasticUser.NAME, DEFAULT_PASSWORD))) .filterWithHeader(singletonMap("Authorization", basicAuthHeaderValue(ElasticUser.NAME, getReservedPassword())))
.admin() .admin()
.cluster() .cluster()
.prepareHealth() .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.Version;
import org.elasticsearch.action.ActionListener; import org.elasticsearch.action.ActionListener;
import org.elasticsearch.action.support.PlainActionFuture; import org.elasticsearch.action.support.PlainActionFuture;
import org.elasticsearch.common.SuppressForbidden;
import org.elasticsearch.common.settings.SecureString; import org.elasticsearch.common.settings.SecureString;
import org.elasticsearch.common.settings.Settings; import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.common.util.concurrent.ThreadContext; import org.elasticsearch.common.util.concurrent.ThreadContext;
@ -16,6 +17,7 @@ import org.elasticsearch.env.Environment;
import org.elasticsearch.test.ESTestCase; import org.elasticsearch.test.ESTestCase;
import org.elasticsearch.xpack.XPackSettings; import org.elasticsearch.xpack.XPackSettings;
import org.elasticsearch.xpack.security.SecurityLifecycleService; 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.esnative.NativeUsersStore.ReservedUserInfo;
import org.elasticsearch.xpack.security.authc.support.Hasher; import org.elasticsearch.xpack.security.authc.support.Hasher;
import org.elasticsearch.xpack.security.authc.support.UsernamePasswordToken; 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.junit.Before;
import org.mockito.ArgumentCaptor; import org.mockito.ArgumentCaptor;
import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.net.UnknownHostException;
import java.util.Collection; import java.util.Collection;
import java.util.Collections; import java.util.Collections;
import java.util.Map; import java.util.Map;
@ -58,62 +63,38 @@ import static org.mockito.Mockito.when;
*/ */
public class ReservedRealmTests extends ESTestCase { 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(); public static final String ACCEPT_DEFAULT_PASSWORDS = ReservedRealm.ACCEPT_DEFAULT_PASSWORD_SETTING.getKey();
private NativeUsersStore usersStore; private NativeUsersStore usersStore;
private SecurityLifecycleService securityLifecycleService; private SecurityLifecycleService securityLifecycleService;
private IncomingRequest incomingRequest;
@Before @Before
public void setupMocks() throws Exception { public void setupMocks() throws Exception {
usersStore = mock(NativeUsersStore.class); usersStore = mock(NativeUsersStore.class);
securityLifecycleService = mock(SecurityLifecycleService.class); securityLifecycleService = mock(SecurityLifecycleService.class);
incomingRequest = mock(IncomingRequest.class);
when(securityLifecycleService.isSecurityIndexAvailable()).thenReturn(true); when(securityLifecycleService.isSecurityIndexAvailable()).thenReturn(true);
when(securityLifecycleService.checkSecurityMappingVersion(any())).thenReturn(true); when(securityLifecycleService.checkSecurityMappingVersion(any())).thenReturn(true);
mockGetAllReservedUserInfo(usersStore, Collections.emptyMap()); 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); when(securityLifecycleService.checkSecurityMappingVersion(any())).thenReturn(false);
final ReservedRealm reservedRealm = final ReservedRealm reservedRealm =
new ReservedRealm(mock(Environment.class), Settings.EMPTY, usersStore, new ReservedRealm(mock(Environment.class), Settings.EMPTY, usersStore,
new AnonymousUser(Settings.EMPTY), securityLifecycleService, new ThreadContext(Settings.EMPTY)); 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<>(); 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)); 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 { public void testDisableDefaultPasswordAuthentication() throws Throwable {
final User expected = randomFrom(new ElasticUser(true), new KibanaUser(true), new LogstashSystemUser(true)); 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")); 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 { public void testAuthenticationDisabled() throws Throwable {
@ -151,7 +176,7 @@ public class ReservedRealmTests extends ESTestCase {
final String principal = expected.principal(); final String principal = expected.principal();
PlainActionFuture<User> listener = new PlainActionFuture<>(); 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(); final User authenticated = listener.actionGet();
assertNull(authenticated); assertNull(authenticated);
verifyZeroInteractions(usersStore); verifyZeroInteractions(usersStore);
@ -179,9 +204,9 @@ public class ReservedRealmTests extends ESTestCase {
return null; return null;
}).when(usersStore).getReservedUserInfo(eq(principal), any(ActionListener.class)); }).when(usersStore).getReservedUserInfo(eq(principal), any(ActionListener.class));
// test default password // test empty password
final PlainActionFuture<User> listener = new PlainActionFuture<>(); 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); ElasticsearchSecurityException expected = expectThrows(ElasticsearchSecurityException.class, listener::actionGet);
assertThat(expected.getMessage(), containsString("failed to authenticate user [" + principal)); assertThat(expected.getMessage(), containsString("failed to authenticate user [" + principal));
@ -194,7 +219,7 @@ public class ReservedRealmTests extends ESTestCase {
// test new password // test new password
final PlainActionFuture<User> authListener = new PlainActionFuture<>(); 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(); final User authenticated = authListener.actionGet();
assertEquals(expectedUser, authenticated); assertEquals(expectedUser, authenticated);
assertThat(expectedUser.enabled(), is(enabled)); assertThat(expectedUser.enabled(), is(enabled));
@ -211,7 +236,7 @@ public class ReservedRealmTests extends ESTestCase {
final ReservedRealm reservedRealm = final ReservedRealm reservedRealm =
new ReservedRealm(mock(Environment.class), Settings.EMPTY, usersStore, new ReservedRealm(mock(Environment.class), Settings.EMPTY, usersStore,
new AnonymousUser(Settings.EMPTY), securityLifecycleService, new ThreadContext(Settings.EMPTY)); 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(); final String principal = expectedUser.principal();
PlainActionFuture<User> listener = new PlainActionFuture<>(); PlainActionFuture<User> listener = new PlainActionFuture<>();
@ -299,7 +324,7 @@ public class ReservedRealmTests extends ESTestCase {
new AnonymousUser(Settings.EMPTY), securityLifecycleService, new ThreadContext(Settings.EMPTY)); new AnonymousUser(Settings.EMPTY), securityLifecycleService, new ThreadContext(Settings.EMPTY));
PlainActionFuture<Collection<User>> userFuture = new PlainActionFuture<>(); PlainActionFuture<Collection<User>> userFuture = new PlainActionFuture<>();
reservedRealm.users(userFuture); 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))); 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, final ReservedRealm reservedRealm = new ReservedRealm(mock(Environment.class), Settings.EMPTY, usersStore,
new AnonymousUser(Settings.EMPTY), securityLifecycleService, new ThreadContext(Settings.EMPTY)); new AnonymousUser(Settings.EMPTY), securityLifecycleService, new ThreadContext(Settings.EMPTY));
InetSocketAddress address = new InetSocketAddress(InetAddress.getLocalHost(), 100);
// maybe cache a successful auth // maybe cache a successful auth
if (randomBoolean()) { if (randomBoolean()) {
PlainActionFuture<User> future = new PlainActionFuture<>(); 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(); User user = future.actionGet();
assertEquals(new ElasticUser(true), user); assertEquals(new ElasticUser(true, true), user);
} }
PlainActionFuture<User> future = new PlainActionFuture<>(); 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); ElasticsearchSecurityException e = expectThrows(ElasticsearchSecurityException.class, future::actionGet);
assertThat(e.getMessage(), containsString("failed to authenticate")); assertThat(e.getMessage(), containsString("failed to authenticate"));
} }

View File

@ -61,7 +61,7 @@ public class SetupPasswordToolTests extends CommandTestCase {
execute("auto", pathHomeParameter, "-b", "true"); execute("auto", pathHomeParameter, "-b", "true");
ArgumentCaptor<String> passwordCaptor = ArgumentCaptor.forClass(String.class); ArgumentCaptor<String> passwordCaptor = ArgumentCaptor.forClass(String.class);
SecureString defaultPassword = new SecureString("changeme".toCharArray()); SecureString defaultPassword = new SecureString("".toCharArray());
InOrder inOrder = Mockito.inOrder(httpClient); InOrder inOrder = Mockito.inOrder(httpClient);
String elasticUrl = "http://localhost:9200/_xpack/security/user/elastic/_password"; 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"); execute("auto", pathHomeParameter, "-u", url, "-b");
ArgumentCaptor<String> passwordCaptor = ArgumentCaptor.forClass(String.class); ArgumentCaptor<String> passwordCaptor = ArgumentCaptor.forClass(String.class);
SecureString defaultPassword = new SecureString("changeme".toCharArray()); SecureString defaultPassword = new SecureString("".toCharArray());
InOrder inOrder = Mockito.inOrder(httpClient); InOrder inOrder = Mockito.inOrder(httpClient);
String elasticUrl = url + "/_xpack/security/user/elastic/_password"; String elasticUrl = url + "/_xpack/security/user/elastic/_password";
@ -99,7 +99,7 @@ public class SetupPasswordToolTests extends CommandTestCase {
execute("interactive", pathHomeParameter); execute("interactive", pathHomeParameter);
SecureString defaultPassword = new SecureString("changeme".toCharArray()); SecureString defaultPassword = new SecureString("".toCharArray());
InOrder inOrder = Mockito.inOrder(httpClient); InOrder inOrder = Mockito.inOrder(httpClient);
String elasticUrl = "http://localhost:9200/_xpack/security/user/elastic/_password"; 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.settings.Settings;
import org.elasticsearch.common.util.concurrent.ThreadContext; import org.elasticsearch.common.util.concurrent.ThreadContext;
import org.elasticsearch.env.Environment; 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.RealmConfig;
import org.elasticsearch.xpack.security.authc.support.Hasher; import org.elasticsearch.xpack.security.authc.support.Hasher;
import org.elasticsearch.xpack.security.authc.support.UsernamePasswordToken; 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)); RealmConfig config = new RealmConfig("file-test", Settings.EMPTY, globalSettings, new Environment(globalSettings), new ThreadContext(globalSettings));
FileRealm realm = new FileRealm(config, userPasswdStore, userRolesStore); FileRealm realm = new FileRealm(config, userPasswdStore, userRolesStore);
PlainActionFuture<User> future = new PlainActionFuture<>(); 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(); User user = future.actionGet();
assertThat(user, notNullValue()); assertThat(user, notNullValue());
assertThat(user.principal(), equalTo("user1")); assertThat(user.principal(), equalTo("user1"));
@ -71,10 +72,10 @@ public class FileRealmTests extends ESTestCase {
when(userRolesStore.roles("user1")).thenReturn(new String[]{"role1", "role2"}); when(userRolesStore.roles("user1")).thenReturn(new String[]{"role1", "role2"});
FileRealm realm = new FileRealm(config, userPasswdStore, userRolesStore); FileRealm realm = new FileRealm(config, userPasswdStore, userRolesStore);
PlainActionFuture<User> future = new PlainActionFuture<>(); 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(); User user1 = future.actionGet();
future = new PlainActionFuture<>(); 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(); User user2 = future.actionGet();
assertThat(user1, sameInstance(user2)); assertThat(user1, sameInstance(user2));
} }
@ -87,32 +88,32 @@ public class FileRealmTests extends ESTestCase {
doReturn(new String[] { "role1", "role2" }).when(userRolesStore).roles("user1"); doReturn(new String[] { "role1", "role2" }).when(userRolesStore).roles("user1");
FileRealm realm = new FileRealm(config, userPasswdStore, userRolesStore); FileRealm realm = new FileRealm(config, userPasswdStore, userRolesStore);
PlainActionFuture<User> future = new PlainActionFuture<>(); 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(); User user1 = future.actionGet();
future = new PlainActionFuture<>(); 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(); User user2 = future.actionGet();
assertThat(user1, sameInstance(user2)); assertThat(user1, sameInstance(user2));
userPasswdStore.notifyRefresh(); userPasswdStore.notifyRefresh();
future = new PlainActionFuture<>(); 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(); User user3 = future.actionGet();
assertThat(user2, not(sameInstance(user3))); assertThat(user2, not(sameInstance(user3)));
future = new PlainActionFuture<>(); 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(); User user4 = future.actionGet();
assertThat(user3, sameInstance(user4)); assertThat(user3, sameInstance(user4));
userRolesStore.notifyRefresh(); userRolesStore.notifyRefresh();
future = new PlainActionFuture<>(); 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(); User user5 = future.actionGet();
assertThat(user4, not(sameInstance(user5))); assertThat(user4, not(sameInstance(user5)));
future = new PlainActionFuture<>(); 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(); User user6 = future.actionGet();
assertThat(user5, sameInstance(user6)); 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.SecureString;
import org.elasticsearch.common.settings.Settings; import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.env.Environment; import org.elasticsearch.env.Environment;
import org.elasticsearch.test.SecuritySettingsSource;
import org.elasticsearch.xpack.XPackSettings; import org.elasticsearch.xpack.XPackSettings;
import org.elasticsearch.xpack.security.authc.support.Hasher; import org.elasticsearch.xpack.security.authc.support.Hasher;
import org.elasticsearch.xpack.security.authz.store.ReservedRolesStore; import org.elasticsearch.xpack.security.authz.store.ReservedRolesStore;
@ -64,10 +65,11 @@ public class UsersToolTests extends CommandTestCase {
IOUtils.rm(homeDir); IOUtils.rm(homeDir);
confDir = homeDir.resolve("config").resolve(XPackPlugin.NAME); confDir = homeDir.resolve("config").resolve(XPackPlugin.NAME);
Files.createDirectories(confDir); Files.createDirectories(confDir);
String defaultPassword = SecuritySettingsSource.TEST_PASSWORD;
Files.write(confDir.resolve("users"), Arrays.asList( Files.write(confDir.resolve("users"), Arrays.asList(
"existing_user:" + new String(Hasher.BCRYPT.hash(new SecureString("changeme".toCharArray()))), "existing_user:" + new String(Hasher.BCRYPT.hash(SecuritySettingsSource.TEST_PASSWORD_SECURE_STRING)),
"existing_user2:" + new String(Hasher.BCRYPT.hash(new SecureString("changeme2".toCharArray()))), "existing_user2:" + new String(Hasher.BCRYPT.hash(new SecureString((defaultPassword + "2").toCharArray()))),
"existing_user3:" + new String(Hasher.BCRYPT.hash(new SecureString("changeme3".toCharArray()))) "existing_user3:" + new String(Hasher.BCRYPT.hash(new SecureString((defaultPassword + "3").toCharArray())))
), StandardCharsets.UTF_8); ), StandardCharsets.UTF_8);
Files.write(confDir.resolve("users_roles"), Arrays.asList( Files.write(confDir.resolve("users_roles"), Arrays.asList(
"test_admin:existing_user,existing_user2", "test_admin:existing_user,existing_user2",
@ -268,20 +270,20 @@ public class UsersToolTests extends CommandTestCase {
} }
public void testUseraddNoPassword() throws Exception { public void testUseraddNoPassword() throws Exception {
terminal.addSecretInput("changeme"); terminal.addSecretInput(SecuritySettingsSource.TEST_PASSWORD);
terminal.addSecretInput("changeme"); terminal.addSecretInput(SecuritySettingsSource.TEST_PASSWORD);
execute("useradd", pathHomeParameter, fileTypeParameter, "username"); execute("useradd", pathHomeParameter, fileTypeParameter, "username");
assertUser("username", "changeme"); assertUser("username", SecuritySettingsSource.TEST_PASSWORD);
} }
public void testUseraddPasswordOption() throws Exception { public void testUseraddPasswordOption() throws Exception {
execute("useradd", pathHomeParameter, fileTypeParameter, "username", "-p", "changeme"); execute("useradd", pathHomeParameter, fileTypeParameter, "username", "-p", SecuritySettingsSource.TEST_PASSWORD);
assertUser("username", "changeme"); assertUser("username", SecuritySettingsSource.TEST_PASSWORD);
} }
public void testUseraddUserExists() throws Exception { public void testUseraddUserExists() throws Exception {
UserException e = expectThrows(UserException.class, () -> { 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(ExitCodes.CODE_ERROR, e.exitCode);
assertEquals("User [existing_user] already exists", e.getMessage()); assertEquals("User [existing_user] already exists", e.getMessage());
@ -290,7 +292,7 @@ public class UsersToolTests extends CommandTestCase {
public void testUseraddReservedUser() throws Exception { public void testUseraddReservedUser() throws Exception {
final String name = randomFrom(ElasticUser.NAME, KibanaUser.NAME); final String name = randomFrom(ElasticUser.NAME, KibanaUser.NAME);
UserException e = expectThrows(UserException.class, () -> { 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(ExitCodes.DATA_ERROR, e.exitCode);
assertEquals("Invalid username [" + name + "]... Username [" + name + "] is reserved and may not be used.", e.getMessage()); 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 { public void testUseraddNoRoles() throws Exception {
Files.delete(confDir.resolve("users_roles")); Files.delete(confDir.resolve("users_roles"));
Files.createFile(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); List<String> lines = Files.readAllLines(confDir.resolve("users_roles"), StandardCharsets.UTF_8);
assertTrue(lines.toString(), lines.isEmpty()); assertTrue(lines.toString(), lines.isEmpty());
} }
@ -319,7 +321,7 @@ public class UsersToolTests extends CommandTestCase {
public void testPasswdUnknownUser() throws Exception { public void testPasswdUnknownUser() throws Exception {
UserException e = expectThrows(UserException.class, () -> { 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); assertEquals(ExitCodes.NO_USER, e.exitCode);
assertTrue(e.getMessage(), e.getMessage().contains("User [unknown] doesn't exist")); 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 { 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"); execute("roles", pathHomeParameter, fileTypeParameter, "existing_user", "-r", "test_admin");
assertRole("test_admin", "username"); assertRole("test_admin", "username");
} }
@ -407,7 +410,8 @@ public class UsersToolTests extends CommandTestCase {
} }
public void testListUnknownRoles() throws Exception { 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"); String output = execute("list", pathHomeParameter, fileTypeParameter, "username");
assertTrue(output, output.contains("username")); assertTrue(output, output.contains("username"));
assertTrue(output, output.contains("r2*,r3*,test_r1")); 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.settings.Settings;
import org.elasticsearch.common.util.concurrent.ThreadContext; import org.elasticsearch.common.util.concurrent.ThreadContext;
import org.elasticsearch.env.Environment; 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.DownLevelADAuthenticator;
import org.elasticsearch.xpack.security.authc.ldap.ActiveDirectorySessionFactory.UpnADAuthenticator; import org.elasticsearch.xpack.security.authc.ldap.ActiveDirectorySessionFactory.UpnADAuthenticator;
import org.elasticsearch.xpack.security.user.User; 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.hamcrest.Matchers.notNullValue;
import static org.mockito.Matchers.any; import static org.mockito.Matchers.any;
import static org.mockito.Matchers.eq; import static org.mockito.Matchers.eq;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.spy; import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.times; import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify; 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); LdapRealm realm = new LdapRealm(LdapRealm.AD_TYPE, config, sessionFactory, roleMapper, threadPool);
PlainActionFuture<User> future = new PlainActionFuture<>(); 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(); User user = future.actionGet();
assertThat(user, is(notNullValue())); assertThat(user, is(notNullValue()));
assertThat(user.roles(), arrayContaining(containsString("Avengers"))); 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 // Thor does not have a UPN of form CN=Thor@ad.test.elasticsearch.com
PlainActionFuture<User> future = new PlainActionFuture<>(); 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(); User user = future.actionGet();
assertThat(user, is(notNullValue())); assertThat(user, is(notNullValue()));
assertThat(user.roles(), arrayContaining(containsString("Avengers"))); assertThat(user.roles(), arrayContaining(containsString("Avengers")));
@ -178,7 +180,7 @@ public class ActiveDirectoryRealmTests extends ESTestCase {
int count = randomIntBetween(2, 10); int count = randomIntBetween(2, 10);
for (int i = 0; i < count; i++) { for (int i = 0; i < count; i++) {
PlainActionFuture<User> future = new PlainActionFuture<>(); 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(); future.actionGet();
} }
@ -196,7 +198,7 @@ public class ActiveDirectoryRealmTests extends ESTestCase {
int count = randomIntBetween(2, 10); int count = randomIntBetween(2, 10);
for (int i = 0; i < count; i++) { for (int i = 0; i < count; i++) {
PlainActionFuture<User> future = new PlainActionFuture<>(); 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(); future.actionGet();
} }
@ -214,7 +216,7 @@ public class ActiveDirectoryRealmTests extends ESTestCase {
int count = randomIntBetween(2, 10); int count = randomIntBetween(2, 10);
for (int i = 0; i < count; i++) { for (int i = 0; i < count; i++) {
PlainActionFuture<User> future = new PlainActionFuture<>(); 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(); future.actionGet();
} }
@ -226,7 +228,7 @@ public class ActiveDirectoryRealmTests extends ESTestCase {
for (int i = 0; i < count; i++) { for (int i = 0; i < count; i++) {
PlainActionFuture<User> future = new PlainActionFuture<>(); 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(); future.actionGet();
} }
@ -243,7 +245,7 @@ public class ActiveDirectoryRealmTests extends ESTestCase {
LdapRealm realm = new LdapRealm(LdapRealm.AD_TYPE, config, sessionFactory, roleMapper, threadPool); LdapRealm realm = new LdapRealm(LdapRealm.AD_TYPE, config, sessionFactory, roleMapper, threadPool);
PlainActionFuture<User> future = new PlainActionFuture<>(); 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(); User user = future.actionGet();
assertThat(user, is(notNullValue())); assertThat(user, is(notNullValue()));
assertThat(user.roles(), arrayContaining(equalTo("group_role"))); 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); LdapRealm realm = new LdapRealm(LdapRealm.AD_TYPE, config, sessionFactory, roleMapper, threadPool);
PlainActionFuture<User> future = new PlainActionFuture<>(); 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(); User user = future.actionGet();
assertThat(user, is(notNullValue())); assertThat(user, is(notNullValue()));
assertThat(user.roles(), arrayContainingInAnyOrder(equalTo("group_role"), equalTo("user_role"))); 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