Merge branch 'master' into feature/sql
Original commit: elastic/x-pack-elasticsearch@51fc29da6a
This commit is contained in:
commit
50a46d0ed2
|
@ -113,7 +113,7 @@ Closure waitWithAuth = { NodeInfo node, AntBuilder ant ->
|
|||
try {
|
||||
httpURLConnection = (HttpURLConnection) new URL("http://${node.httpUri()}/_cluster/health").openConnection();
|
||||
httpURLConnection.setRequestProperty("Authorization", "Basic " +
|
||||
Base64.getEncoder().encodeToString("test_admin:changeme".getBytes(StandardCharsets.UTF_8)));
|
||||
Base64.getEncoder().encodeToString("test_admin:x-pack-test-password".getBytes(StandardCharsets.UTF_8)));
|
||||
httpURLConnection.setRequestMethod("GET");
|
||||
httpURLConnection.setConnectTimeout(1000);
|
||||
httpURLConnection.setReadTimeout(30000);
|
||||
|
@ -145,7 +145,7 @@ Closure waitWithAuth = { NodeInfo node, AntBuilder ant ->
|
|||
integTestCluster {
|
||||
plugin ':x-pack-elasticsearch:plugin'
|
||||
setupCommand 'setupTestAdmin',
|
||||
'bin/x-pack/users', 'useradd', 'test_admin', '-p', 'changeme', '-r', 'superuser'
|
||||
'bin/x-pack/users', 'useradd', 'test_admin', '-p', 'x-pack-test-password', '-r', 'superuser'
|
||||
waitCondition = waitWithAuth
|
||||
}
|
||||
|
||||
|
|
|
@ -6,7 +6,6 @@
|
|||
:es-repo-dir: {docdir}/../../../../elasticsearch/docs
|
||||
:es-test-dir: {docdir}/../../../../elasticsearch/docs/src/test
|
||||
:plugins-examples-dir: {docdir}/../../../../elasticsearch/plugins/examples
|
||||
:docs-dir: {docdir}/../../../../docs
|
||||
|
||||
include::{es-repo-dir}/Versions.asciidoc[]
|
||||
|
||||
|
|
|
@ -72,8 +72,8 @@ make it easier to control which users have authority to view and manage the jobs
|
|||
{dfeeds}, and results.
|
||||
|
||||
By default, you can perform all of the steps in this tutorial by using the
|
||||
built-in `elastic` super user. The default password for the `elastic` user is
|
||||
`changeme`. For information about how to change that password, see
|
||||
built-in `elastic` super user. However, the password must be set before the user
|
||||
can do anything. For information about how to set that password, see
|
||||
<<security-getting-started>>.
|
||||
|
||||
If you are performing these steps in a production environment, take extra care
|
||||
|
@ -191,7 +191,7 @@ mapping for the data set:
|
|||
[source,shell]
|
||||
----------------------------------
|
||||
|
||||
curl -u elastic:changeme -X PUT -H 'Content-Type: application/json'
|
||||
curl -u elastic:x-pack-test-password -X PUT -H 'Content-Type: application/json'
|
||||
http://localhost:9200/server-metrics -d '{
|
||||
"settings":{
|
||||
"number_of_shards":1,
|
||||
|
@ -227,7 +227,7 @@ http://localhost:9200/server-metrics -d '{
|
|||
}'
|
||||
----------------------------------
|
||||
|
||||
NOTE: If you run this command, you must replace `changeme` with your
|
||||
NOTE: If you run this command, you must replace `x-pack-test-password` with your
|
||||
actual password.
|
||||
|
||||
////
|
||||
|
@ -247,16 +247,16 @@ example, which loads the four JSON files:
|
|||
[source,shell]
|
||||
----------------------------------
|
||||
|
||||
curl -u elastic:changeme -X POST -H "Content-Type: application/json"
|
||||
curl -u elastic:x-pack-test-password -X POST -H "Content-Type: application/json"
|
||||
http://localhost:9200/server-metrics/_bulk --data-binary "@server-metrics_1.json"
|
||||
|
||||
curl -u elastic:changeme -X POST -H "Content-Type: application/json"
|
||||
curl -u elastic:x-pack-test-password -X POST -H "Content-Type: application/json"
|
||||
http://localhost:9200/server-metrics/_bulk --data-binary "@server-metrics_2.json"
|
||||
|
||||
curl -u elastic:changeme -X POST -H "Content-Type: application/json"
|
||||
curl -u elastic:x-pack-test-password -X POST -H "Content-Type: application/json"
|
||||
http://localhost:9200/server-metrics/_bulk --data-binary "@server-metrics_3.json"
|
||||
|
||||
curl -u elastic:changeme -X POST -H "Content-Type: application/json"
|
||||
curl -u elastic:x-pack-test-password -X POST -H "Content-Type: application/json"
|
||||
http://localhost:9200/server-metrics/_bulk --data-binary "@server-metrics_4.json"
|
||||
----------------------------------
|
||||
|
||||
|
@ -271,7 +271,7 @@ You can verify that the data was loaded successfully with the following command:
|
|||
[source,shell]
|
||||
----------------------------------
|
||||
|
||||
curl 'http://localhost:9200/_cat/indices?v' -u elastic:changeme
|
||||
curl 'http://localhost:9200/_cat/indices?v' -u elastic:x-pack-test-password
|
||||
----------------------------------
|
||||
|
||||
You should see output similar to the following:
|
||||
|
|
|
@ -13,7 +13,7 @@ To change the password of the logged in user, submit a POST request to the
|
|||
--------------------------------------------------
|
||||
POST _xpack/security/user/elastic/_password
|
||||
{
|
||||
"password": "changeme"
|
||||
"password": "x-pack-test-password"
|
||||
}
|
||||
--------------------------------------------------
|
||||
// CONSOLE
|
||||
|
|
|
@ -16,8 +16,8 @@ endpoint.
|
|||
POST /_xpack/security/oauth2/token
|
||||
{
|
||||
"grant_type" : "password",
|
||||
"username" : "elastic",
|
||||
"password" : "changeme"
|
||||
"username" : "test_admin",
|
||||
"password" : "x-pack-test-password"
|
||||
}
|
||||
--------------------------------------------------
|
||||
// CONSOLE
|
||||
|
|
|
@ -15,9 +15,11 @@ see <<managing-native-users, Managing Native Users>>.
|
|||
=== Built-in Users
|
||||
|
||||
{security} provides built-in user credentials to help you get up and running.
|
||||
These users have a fixed set of privileges and the default password `changeme`.
|
||||
Please read <<reset-built-in-user-passwords,Reset Built-in User Passwords>> and
|
||||
<<disabling-default-password, Disable Default Password Functionality>> below.
|
||||
These users have a fixed set of privileges and cannot be authenticated until their
|
||||
passwords have been set. The exception is the `elastic` user which can be authenticated
|
||||
from a localhost rest request with an empty password. Until a password is set, the elastic
|
||||
user is only authorized to perform change password requests.
|
||||
Please read <<reset-built-in-user-passwords,Reset Built-in User Passwords>> below.
|
||||
|
||||
.{security} Built-in Users
|
||||
|========
|
||||
|
@ -48,8 +50,7 @@ be disabled individually, using the
|
|||
==== Reset Built-in User Passwords
|
||||
[IMPORTANT]
|
||||
=============================================================================
|
||||
You must reset the default passwords for all built-in users, and then
|
||||
<<disabling-default-password, disable default password support>>.
|
||||
You must set the passwords for all built-in users.
|
||||
You can update passwords from the *Management > Users* UI in Kibana or with the
|
||||
{ref}/security-api-users.html#security-api-reset-user-password[Reset Password API]:
|
||||
|
||||
|
@ -117,14 +118,8 @@ PUT _xpack/security/user/logstash_system/_enable
|
|||
==== Disable Default Password Functionality
|
||||
[IMPORTANT]
|
||||
=============================================================================
|
||||
The default password of `changeme` is provided as a convenience that allows you to quickly
|
||||
setup your Elasticsearch stack. It should not be used when running in production.
|
||||
|
||||
Once you have changed the password for the built-in users, you must disable default password support
|
||||
by setting `xpack.security.authc.accept_default_password` to `false`.
|
||||
|
||||
A {ref}/bootstrap-checks.html[bootstrap check] will prevent your cluster from operating in production
|
||||
mode until you make this configuration change.
|
||||
This setting is deprecated. The elastic user no longer has a default password. The password must
|
||||
be set before the user can be used.
|
||||
|
||||
=============================================================================
|
||||
|
||||
|
|
|
@ -61,7 +61,7 @@ xpack:
|
|||
order: 0
|
||||
url: "ldaps://ldap.example.com:636"
|
||||
bind_dn: "cn=ldapuser, ou=users, o=services, dc=example, dc=com"
|
||||
bind_password: changeme
|
||||
bind_password: x-pack-test-password
|
||||
user_search:
|
||||
base_dn: "dc=example,dc=com"
|
||||
attribute: cn
|
||||
|
|
|
@ -21,7 +21,7 @@ Run the migrate tool after you install the X-Pack plugin. For example:
|
|||
|
||||
[source, sh]
|
||||
----------------------------------------------------------------------
|
||||
$ bin/x-pack/migrate native -U http://localhost:9200 -u elastic -p changeme
|
||||
$ bin/x-pack/migrate native -U http://localhost:9200 -u elastic -p x-pack-test-password
|
||||
-n lee,foo -r role1,role2,role3,role4,foo
|
||||
starting migration of users and roles...
|
||||
importing users from [/home/es/config/shield/users]...
|
||||
|
@ -69,5 +69,5 @@ to specify a different configuration directory, the command would look like:
|
|||
|
||||
[source, sh]
|
||||
----------------------------------------------------------------------
|
||||
$ bin/x-pack/migrate native -U http://localhost:9200 -u elastic -p changeme --path.conf /etc/elasticsearch
|
||||
$ bin/x-pack/migrate native -U http://localhost:9200 -u elastic -p x-pack-test-password --path.conf /etc/elasticsearch
|
||||
----------------------------------------------------------------------
|
||||
|
|
|
@ -80,7 +80,7 @@ xpack:
|
|||
type: pki
|
||||
truststore:
|
||||
path: "/path/to/pki_truststore.jks"
|
||||
password: "changeme"
|
||||
password: "x-pack-test-password"
|
||||
------------------------------------------------------------
|
||||
|
||||
. Restart Elasticsearch.
|
||||
|
|
|
@ -36,7 +36,8 @@ curl -XPUT -u elastic 'localhost:9200/_xpack/security/user/logstash_system/_pass
|
|||
----------------------------------------------------------
|
||||
// NOTCONSOLE
|
||||
|
||||
NOTE: The default password for the `elastic` user is `changeme`.
|
||||
NOTE: By default, the `elastic` user does not have a password set. Until its password is set, the `elastic` user will only be
|
||||
allowed to submit change password rest requests from localhost.
|
||||
|
||||
--
|
||||
|
||||
|
@ -72,23 +73,6 @@ curl -XPOST -u elastic 'localhost:9200/_xpack/security/user/johndoe' -H "Content
|
|||
// NOTCONSOLE
|
||||
--
|
||||
|
||||
[[enable-message-authentication]]
|
||||
. Enable message authentication to verify that messages are not tampered with or corrupted in transit:
|
||||
.. Run the `syskeygen` tool from `ES_HOME` without any options:
|
||||
+
|
||||
[source, shell]
|
||||
----------------
|
||||
bin/x-pack/syskeygen
|
||||
----------------
|
||||
+
|
||||
This creates a system key file in `CONFIG_DIR/x-pack/system_key`.
|
||||
|
||||
.. Copy the generated system key to the rest of the nodes in the cluster.
|
||||
+
|
||||
IMPORTANT: The system key is a symmetric key, so the same key must be on every
|
||||
node in the cluster.
|
||||
|
||||
|
||||
[[enable-auditing]]
|
||||
. Enable Auditing to keep track of attempted and successful interactions with
|
||||
your Elasticsearch cluster:
|
||||
|
|
|
@ -52,11 +52,8 @@ A critical part of security is keeping confidential data confidential.
|
|||
Elasticsearch has built-in protections against accidental data loss and
|
||||
corruption. However, there's nothing to stop deliberate tampering or data
|
||||
interception. {security} preserves the integrity of your data by
|
||||
<<ssl-tls, encrypting communications>> to and from nodes and
|
||||
<<enable-message-authentication, authenticating messages>> to verify that they
|
||||
have not been tampered with or corrupted in transit during node-to-node
|
||||
communication. For even greater protection, you can increase the
|
||||
<<ciphers, encryption strength>> and
|
||||
<<ssl-tls, encrypting communications>> to and from nodes.
|
||||
For even greater protection, you can increase the <<ciphers, encryption strength>> and
|
||||
<<separating-node-client-traffic, separate client traffic from node-to-node communications>>.
|
||||
|
||||
|
||||
|
|
|
@ -20,10 +20,6 @@ The {security} uses the following files:
|
|||
* `CONFIG_DIR/x-pack/log4j2.properties` contains audit information (read more
|
||||
<<logging-file, here>>).
|
||||
|
||||
* `CONFIG_DIR/x-pack/system_key` holds a cluster secret key that's used to
|
||||
authenticate messages during node to node communication. For more information,
|
||||
see <<enable-message-authentication, Enabling Message Authentication>>.
|
||||
|
||||
[[security-files-location]]
|
||||
|
||||
IMPORTANT: Any files that {security} uses must be stored in the Elasticsearch
|
||||
|
|
|
@ -102,7 +102,7 @@ March 15, 2016
|
|||
|
||||
.Bug Fixes
|
||||
* Enable <<field-and-document-access-control,document and field level security>> by default.
|
||||
* Fix issues with <<enable-message-authentication,message authentication>> on certain JDKs that do not support cloning message
|
||||
* Fix issues with message authentication on certain JDKs that do not support cloning message
|
||||
authentication codes.
|
||||
* Built in <<setting-up-authentication, realms>> no longer throw an exception if the `Authorization` header does not contain a basic
|
||||
authentication token.
|
||||
|
@ -209,7 +209,7 @@ the correct user to index the audit events.
|
|||
July 21, 2015
|
||||
|
||||
.Bug Fixes
|
||||
* Fixes <<enable-message-authentication,message authentication>> serialization to work with Shield 1.2.1 and earlier.
|
||||
* Fixes message authentication serialization to work with Shield 1.2.1 and earlier.
|
||||
** NOTE: if you are upgrading from Shield 1.3.0 or Shield 1.2.2 a {ref-17}/setup-upgrade.html#restart-upgrade[cluster restart upgrade]
|
||||
will be necessary. When upgrading from other versions of Shield, follow the normal upgrade procedure.
|
||||
|
||||
|
@ -245,7 +245,7 @@ June 24, 2015
|
|||
July 21, 2015
|
||||
|
||||
.Bug Fixes
|
||||
* Fixes <<enable-message-authentication,message authentication>> serialization to work with Shield 1.2.1 and earlier.
|
||||
* Fixes message authentication serialization to work with Shield 1.2.1 and earlier.
|
||||
** NOTE: if you are upgrading from Shield 1.2.2 a {ref-17}/setup-upgrade.html#restart-upgrade[cluster restart upgrade]
|
||||
will be necessary. When upgrading from other versions of Shield, follow the normal upgrade procedure.
|
||||
|
||||
|
|
|
@ -58,11 +58,11 @@ for the client traffic by adding the following to `elasticsearch.yml`:
|
|||
--------------------------------------------------
|
||||
transport.profiles.client.xpack.security.ssl.truststore:
|
||||
path: /path/to/another/truststore
|
||||
password: changeme
|
||||
password: x-pack-test-password
|
||||
|
||||
transport.profiles.client.xpack.security.ssl.keystore:
|
||||
path: /path/to/another/keystore
|
||||
password: changeme
|
||||
password: x-pack-test-password
|
||||
--------------------------------------------------
|
||||
|
||||
To change the default behavior that requires certificates for transport clients,
|
||||
|
|
|
@ -57,7 +57,7 @@ users from the **Management / Users** UI in Kibana or through the
|
|||
---------------------------------------------------------------
|
||||
POST /_xpack/security/user/packetbeat_internal
|
||||
{
|
||||
"password" : "changeme",
|
||||
"password" : "x-pack-test-password",
|
||||
"roles" : [ "packetbeat_writer"],
|
||||
"full_name" : "Internal Packetbeat User"
|
||||
}
|
||||
|
@ -87,7 +87,7 @@ output.elasticsearch:
|
|||
hosts: ["localhost:9200"]
|
||||
index: "packetbeat"
|
||||
username: "packetbeat_internal"
|
||||
password: "changeme"
|
||||
password: "x-pack-test-password"
|
||||
--------------------------------------------------
|
||||
|
||||
.. To use PKI authentication, configure the `certificate` and
|
||||
|
@ -144,7 +144,7 @@ the `packetbeat_reader` role:
|
|||
---------------------------------------------------------------
|
||||
POST /_xpack/security/user/packetbeat_user
|
||||
{
|
||||
"password" : "changeme",
|
||||
"password" : "x-pack-test-password",
|
||||
"roles" : [ "packetbeat_reader"],
|
||||
"full_name" : "Packetbeat User"
|
||||
}
|
||||
|
|
|
@ -137,7 +137,7 @@ import org.elasticsearch.xpack.client.PreBuiltXPackTransportClient;
|
|||
|
||||
TransportClient client = new PreBuiltXPackTransportClient(Settings.builder()
|
||||
.put("cluster.name", "myClusterName")
|
||||
.put("xpack.security.user", "transport_client_user:changeme")
|
||||
.put("xpack.security.user", "transport_client_user:x-pack-test-password")
|
||||
...
|
||||
.build())
|
||||
.addTransportAddress(new InetSocketTransportAddress("localhost", 9300))
|
||||
|
@ -169,14 +169,14 @@ import static org.elasticsearch.xpack.security.authc.support.UsernamePasswordTok
|
|||
|
||||
TransportClient client = new PreBuiltXPackTransportClient(Settings.builder()
|
||||
.put("cluster.name", "myClusterName")
|
||||
.put("xpack.security.user", "transport_client_user:changeme")
|
||||
.put("xpack.security.user", "transport_client_user:x-pack-test-password")
|
||||
...
|
||||
.build())
|
||||
.build()
|
||||
.addTransportAddress(new InetSocketTransportAddress(InetAddress.getByName("localhost"), 9300))
|
||||
.addTransportAddress(new InetSocketTransportAddress(InetAddress.getByName("localhost"), 9301))
|
||||
|
||||
String token = basicAuthHeaderValue("test_user", new SecureString("changeme".toCharArray()));
|
||||
String token = basicAuthHeaderValue("test_user", new SecureString("x-pack-test-password".toCharArray()));
|
||||
|
||||
client.filterWithHeader(Collections.singletonMap("Authorization", token))
|
||||
.prepareSearch().get();
|
||||
|
@ -198,7 +198,7 @@ import org.elasticsearch.xpack.client.PreBuiltXPackTransportClient;
|
|||
|
||||
TransportClient client = new PreBuiltXPackTransportClient(Settings.builder()
|
||||
.put("cluster.name", "myClusterName")
|
||||
.put("xpack.security.user", "transport_client_user:changeme")
|
||||
.put("xpack.security.user", "transport_client_user:x-pack-test-password")
|
||||
.put("xpack.ssl.key", "/path/to/client.key")
|
||||
.put("xpack.ssl.certificate", "/path/to/client.crt")
|
||||
.put("xpack.ssl.certificate_authorities", "/path/to/ca.crt")
|
||||
|
@ -217,7 +217,7 @@ import org.elasticsearch.xpack.client.PreBuiltXPackTransportClient;
|
|||
|
||||
TransportClient client = new PreBuiltXPackTransportClient(Settings.builder()
|
||||
.put("cluster.name", "myClusterName")
|
||||
.put("xpack.security.user", "transport_client_user:changeme")
|
||||
.put("xpack.security.user", "transport_client_user:x-pack-test-password")
|
||||
.put("xpack.ssl.key", "/path/to/client.key")
|
||||
.put("xpack.ssl.certificate", "/path/to/client.crt")
|
||||
.put("xpack.ssl.certificate_authorities", "/path/to/ca.crt")
|
||||
|
@ -246,7 +246,7 @@ import org.elasticsearch.xpack.client.PreBuiltXPackTransportClient;
|
|||
|
||||
TransportClient client = new PreBuiltXPackTransportClient(Settings.builder()
|
||||
.put("cluster.name", "myClusterName")
|
||||
.put("xpack.security.user", "test_user:changeme")
|
||||
.put("xpack.security.user", "test_user:x-pack-test-password")
|
||||
.put("xpack.ssl.certificate_authorities", "/path/to/ca.crt")
|
||||
.put("xpack.security.transport.ssl.enabled", "true")
|
||||
...
|
||||
|
|
|
@ -27,8 +27,8 @@ To use Kibana with {security}:
|
|||
requests as this user to access the cluster monitoring APIs and the `.kibana` index.
|
||||
The server does _not_ need access to user indices.
|
||||
+
|
||||
By default, the `kibana` user password is set to `changeme`. Change this password
|
||||
through the reset password API:
|
||||
By default, the `kibana` does not have a password. The user will not be enabled until
|
||||
a password is set. Set the password through the reset password API:
|
||||
+
|
||||
[source,shell]
|
||||
--------------------------------------------------------------------------------
|
||||
|
|
|
@ -61,7 +61,7 @@ the `user` API:
|
|||
---------------------------------------------------------------
|
||||
POST _xpack/security/user/logstash_internal
|
||||
{
|
||||
"password" : "changeme",
|
||||
"password" : "x-pack-test-password",
|
||||
"roles" : [ "logstash_writer"],
|
||||
"full_name" : "Internal Logstash User"
|
||||
}
|
||||
|
@ -76,18 +76,18 @@ plugins in your Logstash `.conf` file. For example:
|
|||
input {
|
||||
...
|
||||
user => logstash_internal
|
||||
password => changeme
|
||||
password => x-pack-test-password
|
||||
}
|
||||
filter {
|
||||
...
|
||||
user => logstash_internal
|
||||
password => changeme
|
||||
password => x-pack-test-password
|
||||
}
|
||||
output {
|
||||
elasticsearch {
|
||||
...
|
||||
user => logstash_internal
|
||||
password => changeme
|
||||
password => x-pack-test-password
|
||||
}
|
||||
--------------------------------------------------
|
||||
|
||||
|
@ -126,7 +126,7 @@ the `user` API:
|
|||
---------------------------------------------------------------
|
||||
POST _xpack/security/user/logstash_user
|
||||
{
|
||||
"password" : "changeme",
|
||||
"password" : "x-pack-test-password",
|
||||
"roles" : [ "logstash_reader"],
|
||||
"full_name" : "Kibana User"
|
||||
}
|
||||
|
@ -187,8 +187,8 @@ This user has the minimum permissions necessary for the monitoring function, and
|
|||
_should not_ be used for any other purpose - it is specifically _not intended_ for
|
||||
use within a Logstash pipeline.
|
||||
|
||||
By default, the `logstash_system` user password is set to `changeme`.
|
||||
Change this password through the reset password API:
|
||||
By default, the `logstash_system` does not have a password. The user will not be enabled until
|
||||
a password is set. Set the password through the reset password API:
|
||||
|
||||
[source,js]
|
||||
---------------------------------------------------------------------
|
||||
|
|
|
@ -152,7 +152,7 @@ for the agent user:
|
|||
--------------------------------------------------
|
||||
xpack.monitoring.elasticsearch.url: ["http://es-mon-1:9200", "http://es-mon2:9200"]
|
||||
xpack.monitoring.elasticsearch.username: "remote_monitor"
|
||||
xpack.monitoring.elasticsearch.password: "changeme"
|
||||
xpack.monitoring.elasticsearch.password: "x-pack-test-password"
|
||||
--------------------------------------------------
|
||||
|
||||
.. If SSL/TLS is enabled on the monitoring cluster:
|
||||
|
@ -176,6 +176,6 @@ Alternatively, you can configure trusted certificates using a truststore
|
|||
[source,yaml]
|
||||
--------------------------------------------------
|
||||
xpack.monitoring.elasticsearch.ssl.truststore.path: /path/to/file
|
||||
xpack.monitoring.elasticsearch.ssl.truststore.password: changeme
|
||||
xpack.monitoring.elasticsearch.ssl.truststore.password: x-pack-test-password
|
||||
--------------------------------------------------
|
||||
--
|
|
@ -24,7 +24,7 @@ the following request creates a `reporter` user that has the
|
|||
---------------------------------------------------------------
|
||||
POST /_xpack/security/user/reporter
|
||||
{
|
||||
"password" : "changeme",
|
||||
"password" : "x-pack-test-password",
|
||||
"roles" : ["kibana_user", "reporting_user"],
|
||||
"full_name" : "Reporting User"
|
||||
}
|
||||
|
|
|
@ -15,14 +15,6 @@ To use a tribe node with secured clusters:
|
|||
|
||||
. Install {xpack} on the tribe node and every node in each connected cluster.
|
||||
|
||||
. Enable <<enable-message-authentication, message authentication>> globally.
|
||||
Generate a system key on one node and copy it to the tribe node and every other
|
||||
node in each of the connected clusters.
|
||||
+
|
||||
IMPORTANT: For message authentication to work properly across multiple clusters,
|
||||
the tribe node and all of the connected clusters must share the same
|
||||
system key. {security} reads the system key from `CONFIG_DIR/x-pack/system_key`.
|
||||
|
||||
. Enable encryption globally. To encrypt communications, you must enable
|
||||
<<ssl-tls,enable SSL/TLS>> on every node.
|
||||
+
|
||||
|
|
|
@ -21,8 +21,6 @@ Configure in both `elasticsearch.yml` and `kibana.yml`.
|
|||
==== Default Password Security Settings
|
||||
`xpack.security.authc.accept_default_password`::
|
||||
In `elasticsearch.yml`, set this to `false` to disable support for the default "changeme" password.
|
||||
For more information, see {xpack-ref}/setting-up-authentication.html#disabling-default-password[
|
||||
Disable Default Password Functionality].
|
||||
|
||||
[float]
|
||||
[[anonymous-access-settings]]
|
||||
|
|
|
@ -88,7 +88,7 @@ PUT _xpack/watcher/watch/cluster_health_watch
|
|||
"auth": {
|
||||
"basic": {
|
||||
"username": "elastic",
|
||||
"password": "changeme"
|
||||
"password": "x-pack-test-password"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -33,7 +33,7 @@ output { <2>
|
|||
elasticsearch {
|
||||
hosts => "http://localhost:9200"
|
||||
user => "elastic"
|
||||
password => "changeme"
|
||||
password => "x-pack-test-password"
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -26,7 +26,7 @@ import static java.util.Collections.singletonMap;
|
|||
import static org.elasticsearch.xpack.security.authc.support.UsernamePasswordToken.basicAuthHeaderValue;
|
||||
|
||||
public class XDocsClientYamlTestSuiteIT extends ESClientYamlSuiteTestCase {
|
||||
private static final String USER_TOKEN = basicAuthHeaderValue("test_admin", new SecureString("changeme".toCharArray()));
|
||||
private static final String USER_TOKEN = basicAuthHeaderValue("test_admin", new SecureString("x-pack-test-password".toCharArray()));
|
||||
|
||||
public XDocsClientYamlTestSuiteIT(@Name("yaml") ClientYamlTestCandidate testCandidate) {
|
||||
super(testCandidate);
|
||||
|
|
|
@ -0,0 +1 @@
|
|||
/bin/
|
|
@ -98,7 +98,7 @@ if [ -e "$CONF_DIR" ]; then
|
|||
fi
|
||||
|
||||
cd "$ES_HOME" > /dev/null
|
||||
"$JAVA" $ES_JAVA_OPTS -Des.path.home="$ES_HOME" -cp "$ES_CLASSPATH" org.elasticsearch.xpack.security.crypto.tool.SystemKeyTool $properties "${args[@]}"
|
||||
"$JAVA" $ES_JAVA_OPTS -Des.path.home="$ES_HOME" -cp "$ES_CLASSPATH" org.elasticsearch.common.settings.EncKeyTool $properties "${args[@]}"
|
||||
status=$?
|
||||
cd - > /dev/null
|
||||
exit $status
|
||||
|
|
|
@ -5,5 +5,5 @@ rem or more contributor license agreements. Licensed under the Elastic License;
|
|||
rem you may not use this file except in compliance with the Elastic License.
|
||||
|
||||
PUSHD "%~dp0"
|
||||
CALL "%~dp0.in.bat" org.elasticsearch.xpack.security.crypto.tool.SystemKeyTool %*
|
||||
CALL "%~dp0.in.bat" org.elasticsearch.common.settings.EncKeyTool %*
|
||||
POPD
|
|
@ -210,13 +210,50 @@ integTestCluster {
|
|||
|
||||
waitCondition = { NodeInfo node, AntBuilder ant ->
|
||||
File tmpFile = new File(node.cwd, 'wait.success')
|
||||
|
||||
for (int i = 0; i < 10; i++) {
|
||||
HttpURLConnection httpURLConnection = null;
|
||||
try {
|
||||
httpURLConnection = (HttpURLConnection) new URL("http://${node.httpUri()}/_xpack/security/user/elastic/_password")
|
||||
.openConnection();
|
||||
httpURLConnection.setRequestProperty("Authorization", "Basic " +
|
||||
Base64.getEncoder().encodeToString("elastic:".getBytes(StandardCharsets.UTF_8)));
|
||||
httpURLConnection.setRequestMethod("PUT");
|
||||
httpURLConnection.setDoOutput(true);
|
||||
httpURLConnection.setRequestProperty("Content-Type", "application/json; charset=UTF-8");
|
||||
|
||||
httpURLConnection.connect();
|
||||
OutputStream out = httpURLConnection.getOutputStream();
|
||||
out.write("{\"password\": \"x-pack-test-password\"}".getBytes(StandardCharsets.UTF_8));
|
||||
out.close()
|
||||
|
||||
if (httpURLConnection.getResponseCode() == 200) {
|
||||
break
|
||||
}
|
||||
} catch (Exception e) {
|
||||
httpURLConnection.disconnect()
|
||||
if (i == 9) {
|
||||
logger.error("final attempt to set elastic password", e)
|
||||
} else {
|
||||
logger.debug("failed to set elastic password", e)
|
||||
}
|
||||
} finally {
|
||||
if (httpURLConnection != null) {
|
||||
httpURLConnection.disconnect();
|
||||
}
|
||||
}
|
||||
|
||||
// did not start, so wait a bit before trying again
|
||||
Thread.sleep(500L);
|
||||
}
|
||||
|
||||
for (int i = 0; i < 10; i++) {
|
||||
// we use custom wait logic here as the elastic user is not available immediately and ant.get will fail when a 401 is returned
|
||||
HttpURLConnection httpURLConnection = null;
|
||||
try {
|
||||
httpURLConnection = (HttpURLConnection) new URL("http://${node.httpUri()}/_cluster/health?wait_for_nodes=${numNodes}&wait_for_status=yellow").openConnection();
|
||||
httpURLConnection.setRequestProperty("Authorization", "Basic " +
|
||||
Base64.getEncoder().encodeToString("elastic:changeme".getBytes(StandardCharsets.UTF_8)));
|
||||
Base64.getEncoder().encodeToString("elastic:x-pack-test-password".getBytes(StandardCharsets.UTF_8)));
|
||||
httpURLConnection.setRequestMethod("GET");
|
||||
httpURLConnection.connect();
|
||||
if (httpURLConnection.getResponseCode() == 200) {
|
||||
|
|
|
@ -97,6 +97,7 @@ import org.elasticsearch.xpack.security.Security;
|
|||
import org.elasticsearch.xpack.security.SecurityFeatureSet;
|
||||
import org.elasticsearch.xpack.security.authc.AuthenticationService;
|
||||
import org.elasticsearch.xpack.security.authc.support.UsernamePasswordToken;
|
||||
import org.elasticsearch.xpack.security.crypto.CryptoService;
|
||||
import org.elasticsearch.xpack.sql.plugin.SqlPlugin;
|
||||
import org.elasticsearch.xpack.ssl.SSLConfigurationReloader;
|
||||
import org.elasticsearch.xpack.ssl.SSLService;
|
||||
|
@ -122,9 +123,12 @@ import java.util.Set;
|
|||
import java.util.function.Supplier;
|
||||
import java.util.function.UnaryOperator;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import javax.security.auth.DestroyFailedException;
|
||||
|
||||
import static org.elasticsearch.xpack.watcher.Watcher.ENCRYPT_SENSITIVE_DATA_SETTING;
|
||||
|
||||
public class XPackPlugin extends Plugin implements ScriptPlugin, ActionPlugin, IngestPlugin, NetworkPlugin {
|
||||
|
||||
public static final String NAME = "x-pack";
|
||||
|
@ -203,6 +207,7 @@ public class XPackPlugin extends Plugin implements ScriptPlugin, ActionPlugin, I
|
|||
protected Graph graph;
|
||||
protected MachineLearning machineLearning;
|
||||
protected Logstash logstash;
|
||||
protected CryptoService cryptoService;
|
||||
protected Deprecation deprecation;
|
||||
protected Upgrade upgrade;
|
||||
protected SqlPlugin sql;
|
||||
|
@ -232,6 +237,7 @@ public class XPackPlugin extends Plugin implements ScriptPlugin, ActionPlugin, I
|
|||
} else {
|
||||
this.extensionsService = null;
|
||||
}
|
||||
cryptoService = ENCRYPT_SENSITIVE_DATA_SETTING.get(settings) ? new CryptoService(settings) : null;
|
||||
}
|
||||
|
||||
// For tests only
|
||||
|
@ -286,7 +292,7 @@ public class XPackPlugin extends Plugin implements ScriptPlugin, ActionPlugin, I
|
|||
|
||||
// watcher http stuff
|
||||
Map<String, HttpAuthFactory> httpAuthFactories = new HashMap<>();
|
||||
httpAuthFactories.put(BasicAuth.TYPE, new BasicAuthFactory(security.getCryptoService()));
|
||||
httpAuthFactories.put(BasicAuth.TYPE, new BasicAuthFactory(cryptoService));
|
||||
// TODO: add more auth types, or remove this indirection
|
||||
HttpAuthRegistry httpAuthRegistry = new HttpAuthRegistry(httpAuthFactories);
|
||||
HttpRequestTemplate.Parser httpTemplateParser = new HttpRequestTemplate.Parser(httpAuthRegistry);
|
||||
|
@ -299,7 +305,7 @@ public class XPackPlugin extends Plugin implements ScriptPlugin, ActionPlugin, I
|
|||
components.addAll(notificationComponents);
|
||||
|
||||
components.addAll(watcher.createComponents(getClock(), scriptService, internalClient, licenseState,
|
||||
httpClient, httpTemplateParser, threadPool, clusterService, security.getCryptoService(), xContentRegistry, components));
|
||||
httpClient, httpTemplateParser, threadPool, clusterService, cryptoService, xContentRegistry, components));
|
||||
|
||||
|
||||
components.addAll(machineLearning.createComponents(internalClient, clusterService, threadPool, xContentRegistry));
|
||||
|
@ -321,7 +327,7 @@ public class XPackPlugin extends Plugin implements ScriptPlugin, ActionPlugin, I
|
|||
HttpRequestTemplate.Parser httpTemplateParser, ScriptService scriptService,
|
||||
HttpAuthRegistry httpAuthRegistry) {
|
||||
List<Object> components = new ArrayList<>();
|
||||
components.add(new EmailService(settings, security.getCryptoService(), clusterSettings));
|
||||
components.add(new EmailService(settings, cryptoService, clusterSettings));
|
||||
components.add(new HipChatService(settings, httpClient, clusterSettings));
|
||||
components.add(new JiraService(settings, httpClient, clusterSettings));
|
||||
components.add(new SlackService(settings, httpClient, clusterSettings));
|
||||
|
@ -582,7 +588,10 @@ public class XPackPlugin extends Plugin implements ScriptPlugin, ActionPlugin, I
|
|||
|
||||
@Override
|
||||
public List<BootstrapCheck> getBootstrapChecks() {
|
||||
return security.getBootstrapChecks();
|
||||
return Collections.unmodifiableList(
|
||||
Stream.of(security.getBootstrapChecks(), watcher.getBootstrapChecks())
|
||||
.flatMap(Collection::stream)
|
||||
.collect(Collectors.toList()));
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -12,7 +12,6 @@ import org.elasticsearch.common.Strings;
|
|||
import org.elasticsearch.common.settings.Settings;
|
||||
import org.elasticsearch.common.unit.TimeValue;
|
||||
import org.elasticsearch.common.xcontent.XContentParser;
|
||||
import org.elasticsearch.index.query.QueryParseContext;
|
||||
import org.elasticsearch.rest.RestController;
|
||||
import org.elasticsearch.rest.RestRequest;
|
||||
import org.elasticsearch.rest.action.RestToXContentListener;
|
||||
|
@ -28,10 +27,10 @@ import java.util.HashMap;
|
|||
import java.util.HashSet;
|
||||
import java.util.Map;
|
||||
|
||||
import static org.elasticsearch.index.query.AbstractQueryBuilder.parseInnerQueryBuilder;
|
||||
import static org.elasticsearch.rest.RestRequest.Method.GET;
|
||||
import static org.elasticsearch.rest.RestRequest.Method.POST;
|
||||
import static org.elasticsearch.xpack.graph.action.GraphExploreAction.INSTANCE;
|
||||
|
||||
/**
|
||||
* @see GraphExploreRequest
|
||||
*/
|
||||
|
@ -89,7 +88,6 @@ public class RestGraphAction extends XPackRestHandler {
|
|||
Hop currentHop = graphRequest.createNextHop(null);
|
||||
|
||||
try (XContentParser parser = request.contentOrSourceParamParser()) {
|
||||
QueryParseContext context = new QueryParseContext(parser);
|
||||
|
||||
XContentParser.Token token = parser.nextToken();
|
||||
|
||||
|
@ -97,15 +95,14 @@ public class RestGraphAction extends XPackRestHandler {
|
|||
throw new ElasticsearchParseException("failed to parse search source. source must be an object, but found [{}] instead",
|
||||
token.name());
|
||||
}
|
||||
parseHop(parser, context, currentHop, graphRequest);
|
||||
parseHop(parser, currentHop, graphRequest);
|
||||
}
|
||||
|
||||
graphRequest.types(Strings.splitStringByCommaToArray(request.param("type")));
|
||||
return channel -> client.es().execute(INSTANCE, graphRequest, new RestToXContentListener<>(channel));
|
||||
}
|
||||
|
||||
private void parseHop(XContentParser parser, QueryParseContext context, Hop currentHop,
|
||||
GraphExploreRequest graphRequest) throws IOException {
|
||||
private void parseHop(XContentParser parser, Hop currentHop, GraphExploreRequest graphRequest) throws IOException {
|
||||
String fieldName = null;
|
||||
XContentParser.Token token;
|
||||
|
||||
|
@ -121,15 +118,15 @@ public class RestGraphAction extends XPackRestHandler {
|
|||
}
|
||||
} else if (token == XContentParser.Token.START_OBJECT) {
|
||||
if (QUERY_FIELD.match(fieldName)) {
|
||||
currentHop.guidingQuery(context.parseInnerQueryBuilder());
|
||||
currentHop.guidingQuery(parseInnerQueryBuilder(parser));
|
||||
} else if (CONNECTIONS_FIELD.match(fieldName)) {
|
||||
parseHop(parser, context, graphRequest.createNextHop(null), graphRequest);
|
||||
parseHop(parser, graphRequest.createNextHop(null), graphRequest);
|
||||
} else if (CONTROLS_FIELD.match(fieldName)) {
|
||||
if (currentHop.getParentHop() != null) {
|
||||
throw new ElasticsearchParseException(
|
||||
"Controls are a global setting that can only be set in the root " + fieldName, token.name());
|
||||
}
|
||||
parseControls(parser, context, graphRequest);
|
||||
parseControls(parser, graphRequest);
|
||||
} else {
|
||||
throw new ElasticsearchParseException("Illegal object property in graph definition " + fieldName, token.name());
|
||||
|
||||
|
@ -221,7 +218,7 @@ public class RestGraphAction extends XPackRestHandler {
|
|||
"Graph vertices definition cannot contain both "+ INCLUDE_FIELD.getPreferredName()+
|
||||
" and "+EXCLUDE_FIELD.getPreferredName()+" clauses", token.name());
|
||||
}
|
||||
excludes = new HashSet<String>();
|
||||
excludes = new HashSet<>();
|
||||
while ((token = parser.nextToken()) != XContentParser.Token.END_ARRAY) {
|
||||
excludes.add(parser.text());
|
||||
}
|
||||
|
@ -274,7 +271,7 @@ public class RestGraphAction extends XPackRestHandler {
|
|||
}
|
||||
|
||||
|
||||
private void parseControls(XContentParser parser, QueryParseContext context, GraphExploreRequest graphRequest) throws IOException {
|
||||
private void parseControls(XContentParser parser, GraphExploreRequest graphRequest) throws IOException {
|
||||
XContentParser.Token token;
|
||||
|
||||
String fieldName = null;
|
||||
|
|
|
@ -18,9 +18,9 @@ import org.elasticsearch.common.xcontent.ObjectParser;
|
|||
import org.elasticsearch.common.xcontent.ToXContentObject;
|
||||
import org.elasticsearch.common.xcontent.XContentBuilder;
|
||||
import org.elasticsearch.common.xcontent.XContentParser;
|
||||
import org.elasticsearch.index.query.AbstractQueryBuilder;
|
||||
import org.elasticsearch.index.query.QueryBuilder;
|
||||
import org.elasticsearch.index.query.QueryBuilders;
|
||||
import org.elasticsearch.index.query.QueryParseContext;
|
||||
import org.elasticsearch.search.aggregations.AggregationBuilder;
|
||||
import org.elasticsearch.search.aggregations.AggregatorFactories;
|
||||
import org.elasticsearch.search.aggregations.bucket.histogram.DateHistogramAggregationBuilder;
|
||||
|
@ -87,14 +87,14 @@ public class DatafeedConfig extends AbstractDiffable<DatafeedConfig> implements
|
|||
PARSER.declareString((builder, val) ->
|
||||
builder.setFrequency(TimeValue.parseTimeValue(val, FREQUENCY.getPreferredName())), FREQUENCY);
|
||||
PARSER.declareObject(Builder::setQuery,
|
||||
(p, c) -> new QueryParseContext(p).parseInnerQueryBuilder(), QUERY);
|
||||
PARSER.declareObject(Builder::setAggregations, (p, c) -> AggregatorFactories.parseAggregators(new QueryParseContext(p)),
|
||||
(p, c) -> AbstractQueryBuilder.parseInnerQueryBuilder(p), QUERY);
|
||||
PARSER.declareObject(Builder::setAggregations, (p, c) -> AggregatorFactories.parseAggregators(p),
|
||||
AGGREGATIONS);
|
||||
PARSER.declareObject(Builder::setAggregations,(p, c) -> AggregatorFactories.parseAggregators(new QueryParseContext(p)), AGGS);
|
||||
PARSER.declareObject(Builder::setAggregations,(p, c) -> AggregatorFactories.parseAggregators(p), AGGS);
|
||||
PARSER.declareObject(Builder::setScriptFields, (p, c) -> {
|
||||
List<SearchSourceBuilder.ScriptField> parsedScriptFields = new ArrayList<>();
|
||||
while (p.nextToken() != XContentParser.Token.END_OBJECT) {
|
||||
parsedScriptFields.add(new SearchSourceBuilder.ScriptField(new QueryParseContext(p)));
|
||||
parsedScriptFields.add(new SearchSourceBuilder.ScriptField(p));
|
||||
}
|
||||
parsedScriptFields.sort(Comparator.comparing(SearchSourceBuilder.ScriptField::fieldName));
|
||||
return parsedScriptFields;
|
||||
|
|
|
@ -16,8 +16,8 @@ import org.elasticsearch.common.xcontent.ObjectParser;
|
|||
import org.elasticsearch.common.xcontent.ToXContentObject;
|
||||
import org.elasticsearch.common.xcontent.XContentBuilder;
|
||||
import org.elasticsearch.common.xcontent.XContentParser;
|
||||
import org.elasticsearch.index.query.AbstractQueryBuilder;
|
||||
import org.elasticsearch.index.query.QueryBuilder;
|
||||
import org.elasticsearch.index.query.QueryParseContext;
|
||||
import org.elasticsearch.search.aggregations.AggregatorFactories;
|
||||
import org.elasticsearch.search.builder.SearchSourceBuilder;
|
||||
import org.elasticsearch.xpack.ml.job.config.Job;
|
||||
|
@ -49,15 +49,15 @@ public class DatafeedUpdate implements Writeable, ToXContentObject {
|
|||
PARSER.declareString((builder, val) -> builder.setFrequency(
|
||||
TimeValue.parseTimeValue(val, DatafeedConfig.FREQUENCY.getPreferredName())), DatafeedConfig.FREQUENCY);
|
||||
PARSER.declareObject(Builder::setQuery,
|
||||
(p, c) -> new QueryParseContext(p).parseInnerQueryBuilder(), DatafeedConfig.QUERY);
|
||||
PARSER.declareObject(Builder::setAggregations, (p, c) -> AggregatorFactories.parseAggregators(new QueryParseContext(p)),
|
||||
(p, c) -> AbstractQueryBuilder.parseInnerQueryBuilder(p), DatafeedConfig.QUERY);
|
||||
PARSER.declareObject(Builder::setAggregations, (p, c) -> AggregatorFactories.parseAggregators(p),
|
||||
DatafeedConfig.AGGREGATIONS);
|
||||
PARSER.declareObject(Builder::setAggregations,(p, c) -> AggregatorFactories.parseAggregators(new QueryParseContext(p)),
|
||||
PARSER.declareObject(Builder::setAggregations,(p, c) -> AggregatorFactories.parseAggregators(p),
|
||||
DatafeedConfig.AGGS);
|
||||
PARSER.declareObject(Builder::setScriptFields, (p, c) -> {
|
||||
List<SearchSourceBuilder.ScriptField> parsedScriptFields = new ArrayList<>();
|
||||
while (p.nextToken() != XContentParser.Token.END_OBJECT) {
|
||||
parsedScriptFields.add(new SearchSourceBuilder.ScriptField(new QueryParseContext(p)));
|
||||
parsedScriptFields.add(new SearchSourceBuilder.ScriptField(p));
|
||||
}
|
||||
parsedScriptFields.sort(Comparator.comparing(SearchSourceBuilder.ScriptField::fieldName));
|
||||
return parsedScriptFields;
|
||||
|
|
|
@ -31,6 +31,16 @@ import java.util.Collections;
|
|||
*/
|
||||
public class NodeStatsCollector extends Collector {
|
||||
|
||||
private static final CommonStatsFlags FLAGS =
|
||||
new CommonStatsFlags(CommonStatsFlags.Flag.Docs,
|
||||
CommonStatsFlags.Flag.FieldData,
|
||||
CommonStatsFlags.Flag.Store,
|
||||
CommonStatsFlags.Flag.Indexing,
|
||||
CommonStatsFlags.Flag.QueryCache,
|
||||
CommonStatsFlags.Flag.RequestCache,
|
||||
CommonStatsFlags.Flag.Search,
|
||||
CommonStatsFlags.Flag.Segments);
|
||||
|
||||
private final Client client;
|
||||
|
||||
public NodeStatsCollector(Settings settings, ClusterService clusterService,
|
||||
|
@ -43,7 +53,7 @@ public class NodeStatsCollector extends Collector {
|
|||
@Override
|
||||
protected Collection<MonitoringDoc> doCollect() throws Exception {
|
||||
NodesStatsRequest request = new NodesStatsRequest("_local");
|
||||
request.indices(CommonStatsFlags.ALL);
|
||||
request.indices(FLAGS);
|
||||
request.os(true);
|
||||
request.jvm(true);
|
||||
request.process(true);
|
||||
|
@ -67,4 +77,5 @@ public class NodeStatsCollector extends Collector {
|
|||
|
||||
return Collections.singletonList(nodeStatsDoc);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -200,7 +200,6 @@ public class Security implements ActionPlugin, IngestPlugin, NetworkPlugin {
|
|||
private final boolean enabled;
|
||||
private final boolean transportClientMode;
|
||||
private final XPackLicenseState licenseState;
|
||||
private final CryptoService cryptoService;
|
||||
private final SSLService sslService;
|
||||
/* what a PITA that we need an extra indirection to initialize this. Yet, once we got rid of guice we can thing about how
|
||||
* to fix this or make it simpler. Today we need several service that are created in createComponents but we need to register
|
||||
|
@ -220,18 +219,11 @@ public class Security implements ActionPlugin, IngestPlugin, NetworkPlugin {
|
|||
this.enabled = XPackSettings.SECURITY_ENABLED.get(settings);
|
||||
if (enabled && transportClientMode == false) {
|
||||
validateAutoCreateIndex(settings);
|
||||
cryptoService = new CryptoService(settings, env);
|
||||
} else {
|
||||
cryptoService = null;
|
||||
}
|
||||
this.licenseState = licenseState;
|
||||
this.sslService = sslService;
|
||||
}
|
||||
|
||||
public CryptoService getCryptoService() {
|
||||
return cryptoService;
|
||||
}
|
||||
|
||||
public Collection<Module> nodeModules() {
|
||||
List<Module> modules = new ArrayList<>();
|
||||
if (enabled == false || transportClientMode) {
|
||||
|
@ -254,7 +246,6 @@ public class Security implements ActionPlugin, IngestPlugin, NetworkPlugin {
|
|||
|
||||
if (enabled == false) {
|
||||
modules.add(b -> {
|
||||
b.bind(CryptoService.class).toProvider(Providers.of(null));
|
||||
b.bind(Realms.class).toProvider(Providers.of(null)); // for SecurityFeatureSet
|
||||
b.bind(CompositeRolesStore.class).toProvider(Providers.of(null)); // for SecurityFeatureSet
|
||||
b.bind(NativeRoleMappingStore.class).toProvider(Providers.of(null)); // for SecurityFeatureSet
|
||||
|
@ -268,7 +259,6 @@ public class Security implements ActionPlugin, IngestPlugin, NetworkPlugin {
|
|||
// which might not be the case during Plugin class instantiation. Once nodeModules are pulled
|
||||
// everything should have been loaded
|
||||
modules.add(b -> {
|
||||
b.bind(CryptoService.class).toInstance(cryptoService);
|
||||
if (XPackSettings.AUDIT_ENABLED.get(settings)) {
|
||||
b.bind(AuditTrail.class).to(AuditTrailService.class); // interface used by some actions...
|
||||
}
|
||||
|
@ -474,9 +464,6 @@ public class Security implements ActionPlugin, IngestPlugin, NetworkPlugin {
|
|||
settingsList.add(TokenService.DELETE_INTERVAL);
|
||||
settingsList.add(TokenService.DELETE_TIMEOUT);
|
||||
|
||||
// encryption settings
|
||||
CryptoService.addSettings(settingsList);
|
||||
|
||||
// hide settings
|
||||
settingsList.add(Setting.listSetting(setting("hide_settings"), Collections.emptyList(), Function.identity(),
|
||||
Property.NodeScope, Property.Filtered));
|
||||
|
|
|
@ -16,6 +16,7 @@ import org.elasticsearch.common.settings.SecureString;
|
|||
import org.elasticsearch.common.settings.Setting;
|
||||
import org.elasticsearch.common.settings.Setting.Property;
|
||||
import org.elasticsearch.common.settings.Settings;
|
||||
import org.elasticsearch.common.transport.TransportAddress;
|
||||
import org.elasticsearch.common.util.concurrent.ThreadContext;
|
||||
import org.elasticsearch.node.Node;
|
||||
import org.elasticsearch.rest.RestRequest;
|
||||
|
@ -29,6 +30,7 @@ import org.elasticsearch.xpack.security.authc.support.UsernamePasswordToken;
|
|||
import org.elasticsearch.xpack.security.user.AnonymousUser;
|
||||
import org.elasticsearch.xpack.security.user.User;
|
||||
|
||||
import java.net.InetSocketAddress;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.function.BiConsumer;
|
||||
|
@ -132,8 +134,8 @@ public class AuthenticationService extends AbstractComponent {
|
|||
|
||||
private final AuditableRequest request;
|
||||
private final User fallbackUser;
|
||||
private final ActionListener<Authentication> listener;
|
||||
|
||||
private final ActionListener<Authentication> listener;
|
||||
private RealmRef authenticatedBy = null;
|
||||
private RealmRef lookedupBy = null;
|
||||
private AuthenticationToken authenticationToken = null;
|
||||
|
@ -279,7 +281,7 @@ public class AuthenticationService extends AbstractComponent {
|
|||
authenticationToken.principal(), realm.name(), ex);
|
||||
logger.debug("Authentication failed due to exception", ex);
|
||||
userListener.onFailure(ex);
|
||||
}));
|
||||
}), request);
|
||||
} else {
|
||||
userListener.onResponse(null);
|
||||
}
|
||||
|
@ -436,16 +438,21 @@ public class AuthenticationService extends AbstractComponent {
|
|||
}
|
||||
}
|
||||
|
||||
abstract static class AuditableRequest {
|
||||
abstract static class AuditableRequest implements IncomingRequest {
|
||||
|
||||
final AuditTrail auditTrail;
|
||||
final AuthenticationFailureHandler failureHandler;
|
||||
final ThreadContext threadContext;
|
||||
private final InetSocketAddress remoteAddress;
|
||||
private final RequestType requestType;
|
||||
|
||||
AuditableRequest(AuditTrail auditTrail, AuthenticationFailureHandler failureHandler, ThreadContext threadContext) {
|
||||
AuditableRequest(AuditTrail auditTrail, AuthenticationFailureHandler failureHandler, ThreadContext threadContext,
|
||||
RequestType requestType, InetSocketAddress remoteAddress) {
|
||||
this.auditTrail = auditTrail;
|
||||
this.failureHandler = failureHandler;
|
||||
this.threadContext = threadContext;
|
||||
this.remoteAddress = remoteAddress;
|
||||
this.requestType = requestType;
|
||||
}
|
||||
|
||||
abstract void realmAuthenticationFailed(AuthenticationToken token, String realm);
|
||||
|
@ -461,6 +468,14 @@ public class AuthenticationService extends AbstractComponent {
|
|||
abstract ElasticsearchSecurityException runAsDenied(User user, AuthenticationToken token);
|
||||
|
||||
abstract void authenticationSuccess(String realm, User user);
|
||||
|
||||
public InetSocketAddress getRemoteAddress() {
|
||||
return remoteAddress;
|
||||
}
|
||||
|
||||
public RequestType getType() {
|
||||
return requestType;
|
||||
}
|
||||
}
|
||||
|
||||
static class AuditableTransportRequest extends AuditableRequest {
|
||||
|
@ -470,7 +485,7 @@ public class AuthenticationService extends AbstractComponent {
|
|||
|
||||
AuditableTransportRequest(AuditTrail auditTrail, AuthenticationFailureHandler failureHandler, ThreadContext threadContext,
|
||||
String action, TransportMessage message) {
|
||||
super(auditTrail, failureHandler, threadContext);
|
||||
super(auditTrail, failureHandler, threadContext, getType(message), getRemoteAddress(message));
|
||||
this.action = action;
|
||||
this.message = message;
|
||||
}
|
||||
|
@ -523,15 +538,25 @@ public class AuthenticationService extends AbstractComponent {
|
|||
public String toString() {
|
||||
return "transport request action [" + action + "]";
|
||||
}
|
||||
|
||||
private static RequestType getType(TransportMessage message) {
|
||||
return message.remoteAddress() == null ? RequestType.LOCAL_NODE : RequestType.REMOTE_NODE;
|
||||
}
|
||||
|
||||
private static InetSocketAddress getRemoteAddress(TransportMessage message) {
|
||||
TransportAddress transportAddress = message.remoteAddress();
|
||||
return transportAddress == null ? null : transportAddress.address();
|
||||
}
|
||||
}
|
||||
|
||||
static class AuditableRestRequest extends AuditableRequest {
|
||||
|
||||
private final RestRequest request;
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
AuditableRestRequest(AuditTrail auditTrail, AuthenticationFailureHandler failureHandler, ThreadContext threadContext,
|
||||
RestRequest request) {
|
||||
super(auditTrail, failureHandler, threadContext);
|
||||
super(auditTrail, failureHandler, threadContext, RequestType.REST, (InetSocketAddress) request.getRemoteAddress());
|
||||
this.request = request;
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
||||
}
|
||||
}
|
|
@ -81,10 +81,12 @@ public abstract class Realm implements Comparable<Realm> {
|
|||
* {@link ActionListener#onResponse} with the User associated with the given token. An unsuccessful authentication calls
|
||||
* with {@code null} on the argument.
|
||||
*
|
||||
* The remote address should be null if the request initiated from the local node.
|
||||
* @param token The authentication token
|
||||
* @param listener The listener to pass the authentication result to
|
||||
* @param incomingRequest the request that is being authenticated
|
||||
*/
|
||||
public abstract void authenticate(AuthenticationToken token, ActionListener<User> listener);
|
||||
public abstract void authenticate(AuthenticationToken token, ActionListener<User> listener, IncomingRequest incomingRequest);
|
||||
|
||||
/**
|
||||
* Looks up the user identified the String identifier. A successful lookup will call the {@link ActionListener#onResponse}
|
||||
|
|
|
@ -7,12 +7,12 @@ package org.elasticsearch.xpack.security.authc.esnative;
|
|||
|
||||
import org.elasticsearch.action.ActionListener;
|
||||
import org.elasticsearch.common.settings.Setting;
|
||||
import org.elasticsearch.xpack.security.authc.IncomingRequest;
|
||||
import org.elasticsearch.xpack.security.authc.RealmConfig;
|
||||
import org.elasticsearch.xpack.security.authc.support.CachingUsernamePasswordRealm;
|
||||
import org.elasticsearch.xpack.security.authc.support.UsernamePasswordToken;
|
||||
import org.elasticsearch.xpack.security.user.User;
|
||||
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
|
@ -35,7 +35,7 @@ public class NativeRealm extends CachingUsernamePasswordRealm {
|
|||
}
|
||||
|
||||
@Override
|
||||
protected void doAuthenticate(UsernamePasswordToken token, ActionListener<User> listener) {
|
||||
protected void doAuthenticate(UsernamePasswordToken token, ActionListener<User> listener, IncomingRequest incomingRequest) {
|
||||
userStore.verifyPassword(token.principal(), token.credentials(), listener);
|
||||
}
|
||||
|
||||
|
|
|
@ -210,7 +210,7 @@ public class NativeRealmMigrator implements IndexLifecycleManager.IndexDataMigra
|
|||
}
|
||||
|
||||
try (SecureString secureString = new SecureString(passwordHash.toCharArray())) {
|
||||
return Hasher.BCRYPT.verify(ReservedRealm.DEFAULT_PASSWORD_TEXT, secureString.getChars());
|
||||
return Hasher.BCRYPT.verify(ReservedRealm.EMPTY_PASSWORD_TEXT, secureString.getChars());
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -548,7 +548,7 @@ public class NativeUsersStore extends AbstractComponent {
|
|||
} else if (password.isEmpty() && containerSettings.inContainer() && username.equals(ElasticUser.NAME)) {
|
||||
listener.onResponse(new ReservedUserInfo(containerSettings.getPasswordHash(), enabled, false));
|
||||
} else if (password.isEmpty()) {
|
||||
listener.onResponse(new ReservedUserInfo(ReservedRealm.DEFAULT_PASSWORD_HASH, enabled, true));
|
||||
listener.onResponse(new ReservedUserInfo(ReservedRealm.EMPTY_PASSWORD_HASH, enabled, true));
|
||||
} else {
|
||||
listener.onResponse(new ReservedUserInfo(password.toCharArray(), enabled, false));
|
||||
}
|
||||
|
@ -607,7 +607,7 @@ public class NativeUsersStore extends AbstractComponent {
|
|||
char[] passwordHash = containerSettings.getPasswordHash();
|
||||
userInfos.put(searchHit.getId(), new ReservedUserInfo(passwordHash, enabled, false));
|
||||
} else if (password.isEmpty()) {
|
||||
userInfos.put(username, new ReservedUserInfo(ReservedRealm.DEFAULT_PASSWORD_HASH, enabled, true));
|
||||
userInfos.put(username, new ReservedUserInfo(ReservedRealm.EMPTY_PASSWORD_HASH, enabled, true));
|
||||
} else {
|
||||
userInfos.put(username, new ReservedUserInfo(password.toCharArray(), enabled, false));
|
||||
}
|
||||
|
@ -694,12 +694,12 @@ public class NativeUsersStore extends AbstractComponent {
|
|||
|
||||
public final char[] passwordHash;
|
||||
public final boolean enabled;
|
||||
public final boolean hasDefaultPassword;
|
||||
public final boolean hasEmptyPassword;
|
||||
|
||||
ReservedUserInfo(char[] passwordHash, boolean enabled, boolean hasDefaultPassword) {
|
||||
ReservedUserInfo(char[] passwordHash, boolean enabled, boolean hasEmptyPassword) {
|
||||
this.passwordHash = passwordHash;
|
||||
this.enabled = enabled;
|
||||
this.hasDefaultPassword = hasDefaultPassword;
|
||||
this.hasEmptyPassword = hasEmptyPassword;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -17,6 +17,7 @@ import org.elasticsearch.env.Environment;
|
|||
import org.elasticsearch.xpack.XPackSettings;
|
||||
import org.elasticsearch.xpack.security.Security;
|
||||
import org.elasticsearch.xpack.security.SecurityLifecycleService;
|
||||
import org.elasticsearch.xpack.security.authc.IncomingRequest;
|
||||
import org.elasticsearch.xpack.security.authc.RealmConfig;
|
||||
import org.elasticsearch.xpack.security.authc.esnative.NativeUsersStore.ReservedUserInfo;
|
||||
import org.elasticsearch.xpack.security.authc.support.CachingUsernamePasswordRealm;
|
||||
|
@ -30,6 +31,9 @@ import org.elasticsearch.xpack.security.user.KibanaUser;
|
|||
import org.elasticsearch.xpack.security.user.LogstashSystemUser;
|
||||
import org.elasticsearch.xpack.security.user.User;
|
||||
|
||||
import java.net.InetAddress;
|
||||
import java.net.NetworkInterface;
|
||||
import java.net.SocketException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
|
@ -44,20 +48,20 @@ public class ReservedRealm extends CachingUsernamePasswordRealm {
|
|||
|
||||
public static final String TYPE = "reserved";
|
||||
|
||||
public static final SecureString DEFAULT_PASSWORD_TEXT = new SecureString("changeme".toCharArray());
|
||||
static final char[] DEFAULT_PASSWORD_HASH = Hasher.BCRYPT.hash(DEFAULT_PASSWORD_TEXT);
|
||||
public static final SecureString EMPTY_PASSWORD_TEXT = new SecureString("".toCharArray());
|
||||
static final char[] EMPTY_PASSWORD_HASH = Hasher.BCRYPT.hash(EMPTY_PASSWORD_TEXT);
|
||||
|
||||
private static final ReservedUserInfo DEFAULT_USER_INFO = new ReservedUserInfo(DEFAULT_PASSWORD_HASH, true, true);
|
||||
private static final ReservedUserInfo DISABLED_USER_INFO = new ReservedUserInfo(DEFAULT_PASSWORD_HASH, false, true);
|
||||
private static final ReservedUserInfo DEFAULT_USER_INFO = new ReservedUserInfo(EMPTY_PASSWORD_HASH, true, true);
|
||||
private static final ReservedUserInfo DISABLED_USER_INFO = new ReservedUserInfo(EMPTY_PASSWORD_HASH, false, true);
|
||||
|
||||
public static final Setting<Boolean> ACCEPT_DEFAULT_PASSWORD_SETTING = Setting.boolSetting(
|
||||
Security.setting("authc.accept_default_password"), true, Setting.Property.NodeScope, Setting.Property.Filtered);
|
||||
Security.setting("authc.accept_default_password"), true, Setting.Property.NodeScope, Setting.Property.Filtered,
|
||||
Setting.Property.Deprecated);
|
||||
|
||||
private final NativeUsersStore nativeUsersStore;
|
||||
private final AnonymousUser anonymousUser;
|
||||
private final boolean realmEnabled;
|
||||
private final boolean anonymousEnabled;
|
||||
private final boolean defaultPasswordEnabled;
|
||||
private final SecurityLifecycleService securityLifecycleService;
|
||||
|
||||
public ReservedRealm(Environment env, Settings settings, NativeUsersStore nativeUsersStore, AnonymousUser anonymousUser,
|
||||
|
@ -67,12 +71,28 @@ public class ReservedRealm extends CachingUsernamePasswordRealm {
|
|||
this.realmEnabled = XPackSettings.RESERVED_REALM_ENABLED_SETTING.get(settings);
|
||||
this.anonymousUser = anonymousUser;
|
||||
this.anonymousEnabled = AnonymousUser.isAnonymousEnabled(settings);
|
||||
this.defaultPasswordEnabled = ACCEPT_DEFAULT_PASSWORD_SETTING.get(settings);
|
||||
this.securityLifecycleService = securityLifecycleService;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void doAuthenticate(UsernamePasswordToken token, ActionListener<User> listener) {
|
||||
protected void doAuthenticate(UsernamePasswordToken token, ActionListener<User> listener, IncomingRequest incomingRequest) {
|
||||
if (incomingRequest.getType() != IncomingRequest.RequestType.REST) {
|
||||
doAuthenticate(token, listener, false);
|
||||
} else {
|
||||
InetAddress address = incomingRequest.getRemoteAddress().getAddress();
|
||||
|
||||
try {
|
||||
// This checks if the address is the loopback address or if it is bound to one of this machine's
|
||||
// network interfaces. This is because we want to allow requests that originate from this machine.
|
||||
final boolean isLocalMachine = address.isLoopbackAddress() || NetworkInterface.getByInetAddress(address) != null;
|
||||
doAuthenticate(token, listener, isLocalMachine);
|
||||
} catch (SocketException e) {
|
||||
listener.onFailure(Exceptions.authenticationError("failed to authenticate user [{}]", e, token.principal()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void doAuthenticate(UsernamePasswordToken token, ActionListener<User> listener, boolean acceptEmptyPassword) {
|
||||
if (realmEnabled == false) {
|
||||
listener.onResponse(null);
|
||||
} else if (isReserved(token.principal(), config.globalSettings()) == false) {
|
||||
|
@ -82,7 +102,10 @@ public class ReservedRealm extends CachingUsernamePasswordRealm {
|
|||
Runnable action;
|
||||
if (userInfo != null) {
|
||||
try {
|
||||
if (verifyPassword(userInfo, token)) {
|
||||
if (userInfo.hasEmptyPassword && isSetupMode(token.principal(), acceptEmptyPassword) == false) {
|
||||
action = () -> listener.onFailure(Exceptions.authenticationError("failed to authenticate user [{}]",
|
||||
token.principal()));
|
||||
} else if (verifyPassword(userInfo, token)) {
|
||||
final User user = getUser(token.principal(), userInfo);
|
||||
action = () -> listener.onResponse(user);
|
||||
} else {
|
||||
|
@ -90,7 +113,7 @@ public class ReservedRealm extends CachingUsernamePasswordRealm {
|
|||
token.principal()));
|
||||
}
|
||||
} finally {
|
||||
if (userInfo.passwordHash != DEFAULT_PASSWORD_HASH) {
|
||||
if (userInfo.passwordHash != EMPTY_PASSWORD_HASH) {
|
||||
Arrays.fill(userInfo.passwordHash, (char) 0);
|
||||
}
|
||||
}
|
||||
|
@ -104,11 +127,12 @@ public class ReservedRealm extends CachingUsernamePasswordRealm {
|
|||
}
|
||||
}
|
||||
|
||||
private boolean isSetupMode(String userName, boolean acceptEmptyPassword) {
|
||||
return ElasticUser.NAME.equals(userName) && acceptEmptyPassword;
|
||||
}
|
||||
|
||||
private boolean verifyPassword(ReservedUserInfo userInfo, UsernamePasswordToken token) {
|
||||
if (Hasher.BCRYPT.verify(token.credentials(), userInfo.passwordHash)) {
|
||||
if (userInfo.hasDefaultPassword && this.defaultPasswordEnabled == false) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
|
@ -154,7 +178,7 @@ public class ReservedRealm extends CachingUsernamePasswordRealm {
|
|||
assert username != null;
|
||||
switch (username) {
|
||||
case ElasticUser.NAME:
|
||||
return new ElasticUser(userInfo.enabled);
|
||||
return new ElasticUser(userInfo.enabled, userInfo.hasEmptyPassword);
|
||||
case KibanaUser.NAME:
|
||||
return new KibanaUser(userInfo.enabled);
|
||||
case LogstashSystemUser.NAME:
|
||||
|
@ -178,7 +202,8 @@ public class ReservedRealm extends CachingUsernamePasswordRealm {
|
|||
List<User> users = new ArrayList<>(4);
|
||||
|
||||
ReservedUserInfo userInfo = reservedUserInfos.get(ElasticUser.NAME);
|
||||
users.add(new ElasticUser(userInfo == null || userInfo.enabled));
|
||||
users.add(new ElasticUser(userInfo == null || userInfo.enabled,
|
||||
userInfo == null || userInfo.hasEmptyPassword));
|
||||
|
||||
userInfo = reservedUserInfos.get(KibanaUser.NAME);
|
||||
users.add(new KibanaUser(userInfo == null || userInfo.enabled));
|
||||
|
|
|
@ -157,7 +157,7 @@ public class SetupPasswordTool extends MultiCommand {
|
|||
private OptionSpec<String> noPromptOption;
|
||||
|
||||
private String elasticUser = ElasticUser.NAME;
|
||||
private SecureString elasticUserPassword = ReservedRealm.DEFAULT_PASSWORD_TEXT;
|
||||
private SecureString elasticUserPassword = ReservedRealm.EMPTY_PASSWORD_TEXT;
|
||||
private String url;
|
||||
|
||||
SetupCommand(String description) {
|
||||
|
|
|
@ -11,6 +11,7 @@ import java.util.Set;
|
|||
import org.elasticsearch.action.ActionListener;
|
||||
import org.elasticsearch.common.settings.Setting;
|
||||
import org.elasticsearch.watcher.ResourceWatcherService;
|
||||
import org.elasticsearch.xpack.security.authc.IncomingRequest;
|
||||
import org.elasticsearch.xpack.security.authc.RealmConfig;
|
||||
import org.elasticsearch.xpack.security.authc.support.CachingUsernamePasswordRealm;
|
||||
import org.elasticsearch.xpack.security.authc.support.UsernamePasswordToken;
|
||||
|
@ -37,7 +38,7 @@ public class FileRealm extends CachingUsernamePasswordRealm {
|
|||
}
|
||||
|
||||
@Override
|
||||
protected void doAuthenticate(UsernamePasswordToken token, ActionListener<User> listener) {
|
||||
protected void doAuthenticate(UsernamePasswordToken token, ActionListener<User> listener, IncomingRequest incomingRequest) {
|
||||
if (userPasswdStore.verifyPassword(token.principal(), token.credentials())) {
|
||||
String[] roles = userRolesStore.roles(token.principal());
|
||||
listener.onResponse(new User(token.principal(), roles));
|
||||
|
|
|
@ -19,7 +19,6 @@ import org.apache.lucene.util.IOUtils;
|
|||
import org.elasticsearch.ElasticsearchTimeoutException;
|
||||
import org.elasticsearch.action.ActionListener;
|
||||
import org.elasticsearch.action.support.ContextPreservingActionListener;
|
||||
import org.elasticsearch.common.Strings;
|
||||
import org.elasticsearch.common.collect.MapBuilder;
|
||||
import org.elasticsearch.common.settings.Setting;
|
||||
import org.elasticsearch.common.settings.Setting.Property;
|
||||
|
@ -29,6 +28,7 @@ import org.elasticsearch.common.util.concurrent.ThreadContext;
|
|||
import org.elasticsearch.threadpool.ThreadPool;
|
||||
import org.elasticsearch.threadpool.ThreadPool.Names;
|
||||
import org.elasticsearch.watcher.ResourceWatcherService;
|
||||
import org.elasticsearch.xpack.security.authc.IncomingRequest;
|
||||
import org.elasticsearch.xpack.security.authc.RealmConfig;
|
||||
import org.elasticsearch.xpack.security.authc.RealmSettings;
|
||||
import org.elasticsearch.xpack.security.authc.ldap.support.LdapLoadBalancing;
|
||||
|
@ -142,7 +142,7 @@ public final class LdapRealm extends CachingUsernamePasswordRealm {
|
|||
* This user will then be passed to the listener
|
||||
*/
|
||||
@Override
|
||||
protected void doAuthenticate(UsernamePasswordToken token, ActionListener<User> listener) {
|
||||
protected void doAuthenticate(UsernamePasswordToken token, ActionListener<User> listener, IncomingRequest incomingRequest) {
|
||||
// we submit to the threadpool because authentication using LDAP will execute blocking I/O for a bind request and we don't want
|
||||
// network threads stuck waiting for a socket to connect. After the bind, then all interaction with LDAP should be async
|
||||
final CancellableLdapRunnable cancellableLdapRunnable = new CancellableLdapRunnable(listener,
|
||||
|
|
|
@ -17,6 +17,7 @@ import org.elasticsearch.common.settings.Settings;
|
|||
import org.elasticsearch.common.util.concurrent.ThreadContext;
|
||||
import org.elasticsearch.env.Environment;
|
||||
import org.elasticsearch.watcher.ResourceWatcherService;
|
||||
import org.elasticsearch.xpack.security.authc.IncomingRequest;
|
||||
import org.elasticsearch.xpack.security.authc.support.UserRoleMapper;
|
||||
import org.elasticsearch.xpack.security.authc.support.mapper.CompositeRoleMapper;
|
||||
import org.elasticsearch.xpack.security.authc.support.mapper.NativeRoleMappingStore;
|
||||
|
@ -40,9 +41,6 @@ import java.util.Set;
|
|||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
import static org.elasticsearch.xpack.XPackSettings.HTTP_SSL_ENABLED;
|
||||
import static org.elasticsearch.xpack.security.Security.setting;
|
||||
|
||||
public class PkiRealm extends Realm {
|
||||
|
||||
public static final String PKI_CERT_HEADER_NAME = "__SECURITY_CLIENT_CERTIFICATE";
|
||||
|
@ -84,7 +82,7 @@ public class PkiRealm extends Realm {
|
|||
}
|
||||
|
||||
@Override
|
||||
public void authenticate(AuthenticationToken authToken, ActionListener<User> listener) {
|
||||
public void authenticate(AuthenticationToken authToken, ActionListener<User> listener, IncomingRequest incomingRequest) {
|
||||
X509AuthenticationToken token = (X509AuthenticationToken)authToken;
|
||||
if (isCertificateChainTrusted(trustManager, token, logger) == false) {
|
||||
listener.onResponse(null);
|
||||
|
|
|
@ -12,6 +12,7 @@ import org.elasticsearch.common.settings.SecureString;
|
|||
import org.elasticsearch.common.settings.Setting;
|
||||
import org.elasticsearch.common.unit.TimeValue;
|
||||
import org.elasticsearch.xpack.security.authc.AuthenticationToken;
|
||||
import org.elasticsearch.xpack.security.authc.IncomingRequest;
|
||||
import org.elasticsearch.xpack.security.authc.RealmConfig;
|
||||
import org.elasticsearch.xpack.security.user.User;
|
||||
|
||||
|
@ -67,17 +68,18 @@ public abstract class CachingUsernamePasswordRealm extends UsernamePasswordRealm
|
|||
* If the user exists in the cache (keyed by the principle name), then the password is validated
|
||||
* against a hash also stored in the cache. Otherwise the subclass authenticates the user via
|
||||
* doAuthenticate
|
||||
*
|
||||
* @param authToken The authentication token
|
||||
* @param listener to be called at completion
|
||||
* @param incomingRequest the request that is being authenticated
|
||||
*/
|
||||
@Override
|
||||
public final void authenticate(AuthenticationToken authToken, ActionListener<User> listener) {
|
||||
UsernamePasswordToken token = (UsernamePasswordToken)authToken;
|
||||
public final void authenticate(AuthenticationToken authToken, ActionListener<User> listener, IncomingRequest incomingRequest) {
|
||||
UsernamePasswordToken token = (UsernamePasswordToken) authToken;
|
||||
try {
|
||||
if (cache == null) {
|
||||
doAuthenticate(token, listener);
|
||||
doAuthenticate(token, listener, incomingRequest);
|
||||
} else {
|
||||
authenticateWithCache(token, listener);
|
||||
authenticateWithCache(token, listener, incomingRequest);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
// each realm should handle exceptions, if we get one here it should be considered fatal
|
||||
|
@ -85,7 +87,7 @@ public abstract class CachingUsernamePasswordRealm extends UsernamePasswordRealm
|
|||
}
|
||||
}
|
||||
|
||||
private void authenticateWithCache(UsernamePasswordToken token, ActionListener<User> listener) {
|
||||
private void authenticateWithCache(UsernamePasswordToken token, ActionListener<User> listener, IncomingRequest incomingRequest) {
|
||||
UserWithHash userWithHash = cache.get(token.principal());
|
||||
if (userWithHash == null) {
|
||||
if (logger.isDebugEnabled()) {
|
||||
|
@ -97,7 +99,7 @@ public abstract class CachingUsernamePasswordRealm extends UsernamePasswordRealm
|
|||
logger.debug("realm [{}] authenticated user [{}], with roles [{}]", name(), token.principal(), user.roles());
|
||||
}
|
||||
listener.onResponse(user);
|
||||
}, listener::onFailure));
|
||||
}, listener::onFailure), incomingRequest);
|
||||
} else if (userWithHash.hasHash()) {
|
||||
if (userWithHash.verify(token.credentials())) {
|
||||
if (userWithHash.user.enabled()) {
|
||||
|
@ -114,7 +116,7 @@ public abstract class CachingUsernamePasswordRealm extends UsernamePasswordRealm
|
|||
user.enabled(), user.roles());
|
||||
}
|
||||
listener.onResponse(user);
|
||||
}, listener::onFailure));
|
||||
}, listener::onFailure), incomingRequest);
|
||||
}
|
||||
} else {
|
||||
cache.invalidate(token.principal());
|
||||
|
@ -124,7 +126,7 @@ public abstract class CachingUsernamePasswordRealm extends UsernamePasswordRealm
|
|||
name(), token.principal(), user.roles());
|
||||
}
|
||||
listener.onResponse(user);
|
||||
}, listener::onFailure));
|
||||
}, listener::onFailure), incomingRequest);
|
||||
}
|
||||
} else {
|
||||
cache.invalidate(token.principal());
|
||||
|
@ -134,12 +136,12 @@ public abstract class CachingUsernamePasswordRealm extends UsernamePasswordRealm
|
|||
"realm [{}] authenticated user [{}] with roles [{}]", name(), token.principal(), user.roles());
|
||||
}
|
||||
listener.onResponse(user);
|
||||
}, listener::onFailure));
|
||||
}, listener::onFailure), incomingRequest);
|
||||
}
|
||||
}
|
||||
|
||||
private void doAuthenticateAndCache(UsernamePasswordToken token, ActionListener<User> listener) {
|
||||
doAuthenticate(token, ActionListener.wrap((user) -> {
|
||||
private void doAuthenticateAndCache(UsernamePasswordToken token, ActionListener<User> listener, IncomingRequest incomingRequest) {
|
||||
ActionListener<User> wrapped = ActionListener.wrap((user) -> {
|
||||
if (user == null) {
|
||||
listener.onResponse(null);
|
||||
} else {
|
||||
|
@ -148,7 +150,9 @@ public abstract class CachingUsernamePasswordRealm extends UsernamePasswordRealm
|
|||
cache.put(token.principal(), userWithHash);
|
||||
listener.onResponse(user);
|
||||
}
|
||||
}, listener::onFailure));
|
||||
}, listener::onFailure);
|
||||
|
||||
doAuthenticate(token, wrapped, incomingRequest);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -158,7 +162,7 @@ public abstract class CachingUsernamePasswordRealm extends UsernamePasswordRealm
|
|||
return stats;
|
||||
}
|
||||
|
||||
protected abstract void doAuthenticate(UsernamePasswordToken token, ActionListener<User> listener);
|
||||
protected abstract void doAuthenticate(UsernamePasswordToken token, ActionListener<User> listener, IncomingRequest incomingRequest);
|
||||
|
||||
@Override
|
||||
public final void lookupUser(String username, ActionListener<User> listener) {
|
||||
|
|
|
@ -9,6 +9,7 @@ import org.elasticsearch.ElasticsearchSecurityException;
|
|||
import org.elasticsearch.action.ActionListener;
|
||||
import org.elasticsearch.action.CompositeIndicesRequest;
|
||||
import org.elasticsearch.action.IndicesRequest;
|
||||
import org.elasticsearch.action.admin.cluster.health.ClusterHealthAction;
|
||||
import org.elasticsearch.action.admin.indices.alias.Alias;
|
||||
import org.elasticsearch.action.admin.indices.alias.IndicesAliasesRequest;
|
||||
import org.elasticsearch.action.admin.indices.create.CreateIndexRequest;
|
||||
|
@ -54,6 +55,7 @@ import org.elasticsearch.xpack.security.authz.store.CompositeRolesStore;
|
|||
import org.elasticsearch.xpack.security.authz.store.ReservedRolesStore;
|
||||
import org.elasticsearch.xpack.security.support.Automatons;
|
||||
import org.elasticsearch.xpack.security.user.AnonymousUser;
|
||||
import org.elasticsearch.xpack.security.user.ElasticUser;
|
||||
import org.elasticsearch.xpack.security.user.SystemUser;
|
||||
import org.elasticsearch.xpack.security.user.User;
|
||||
import org.elasticsearch.xpack.security.user.XPackUser;
|
||||
|
@ -150,6 +152,12 @@ public class AuthorizationService extends AbstractComponent {
|
|||
throw denial(authentication, action, request);
|
||||
}
|
||||
|
||||
// If the user is the elastic user in setup mode, then only change password requests can be authorized
|
||||
if (ElasticUser.isElasticUserInSetupMode(authentication.getUser())
|
||||
&& ChangePasswordAction.NAME.equals(action) == false) {
|
||||
throw denial(authentication, action, request);
|
||||
}
|
||||
|
||||
// get the roles of the authenticated user, which may be different than the effective
|
||||
Role permission = userRole;
|
||||
|
||||
|
|
|
@ -134,7 +134,7 @@ public class SecurityIndexSearcherWrapper extends IndexSearcherWrapper {
|
|||
String templateResult = evaluateTemplate(bytesReference.utf8ToString());
|
||||
try (XContentParser parser = XContentFactory.xContent(templateResult)
|
||||
.createParser(queryShardContext.getXContentRegistry(), templateResult)) {
|
||||
QueryBuilder queryBuilder = queryShardContext.newParseContext(parser).parseInnerQueryBuilder();
|
||||
QueryBuilder queryBuilder = queryShardContext.parseInnerQueryBuilder(parser);
|
||||
verifyRoleQuery(queryBuilder);
|
||||
failIfQueryUsesClient(scriptService, queryBuilder, queryShardContext);
|
||||
ParsedQuery parsedQuery = queryShardContext.toFilter(queryBuilder);
|
||||
|
|
|
@ -12,10 +12,8 @@ import javax.crypto.KeyGenerator;
|
|||
import javax.crypto.SecretKey;
|
||||
import javax.crypto.spec.IvParameterSpec;
|
||||
import javax.crypto.spec.SecretKeySpec;
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.IOException;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.io.InputStream;
|
||||
import java.security.MessageDigest;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
import java.security.SecureRandom;
|
||||
|
@ -25,12 +23,12 @@ import java.util.List;
|
|||
|
||||
import org.elasticsearch.ElasticsearchException;
|
||||
import org.elasticsearch.common.component.AbstractComponent;
|
||||
import org.elasticsearch.common.io.Streams;
|
||||
import org.elasticsearch.common.settings.Setting;
|
||||
import org.elasticsearch.common.settings.Setting.Property;
|
||||
import org.elasticsearch.common.settings.Settings;
|
||||
import org.elasticsearch.env.Environment;
|
||||
import org.elasticsearch.xpack.XPackPlugin;
|
||||
import org.elasticsearch.xpack.security.authc.support.CharArrays;
|
||||
import org.elasticsearch.xpack.watcher.Watcher;
|
||||
|
||||
import static org.elasticsearch.xpack.security.Security.setting;
|
||||
|
||||
|
@ -42,14 +40,19 @@ public class CryptoService extends AbstractComponent {
|
|||
public static final String KEY_ALGO = "HmacSHA512";
|
||||
public static final int KEY_SIZE = 1024;
|
||||
|
||||
static final String FILE_NAME = "system_key";
|
||||
static final String DEFAULT_ENCRYPTION_ALGORITHM = "AES/CTR/NoPadding";
|
||||
static final String DEFAULT_KEY_ALGORITH = "AES";
|
||||
static final String ENCRYPTED_TEXT_PREFIX = "::es_encrypted::";
|
||||
static final int DEFAULT_KEY_LENGTH = 128;
|
||||
|
||||
private static final Setting<Boolean> SYSTEM_KEY_REQUIRED_SETTING =
|
||||
Setting.boolSetting(setting("system_key.required"), false, Property.NodeScope);
|
||||
// the encryption used in this class was picked when Java 7 was still the min. supported
|
||||
// version. The use of counter mode was chosen to simplify the need to deal with padding
|
||||
// and for its speed. 128 bit key length is chosen due to the JCE policy that ships by
|
||||
// default with the Oracle JDK.
|
||||
// TODO: with better support in Java 8, we should consider moving to use AES GCM as it
|
||||
// also provides authentication of the encrypted data, which is something that we are
|
||||
// missing here.
|
||||
private static final String DEFAULT_ENCRYPTION_ALGORITHM = "AES/CTR/NoPadding";
|
||||
private static final String DEFAULT_KEY_ALGORITH = "AES";
|
||||
private static final int DEFAULT_KEY_LENGTH = 128;
|
||||
|
||||
private static final Setting<String> ENCRYPTION_ALGO_SETTING =
|
||||
new Setting<>(setting("encryption.algorithm"), s -> DEFAULT_ENCRYPTION_ALGORITHM, s -> s, Property.NodeScope);
|
||||
private static final Setting<Integer> ENCRYPTION_KEY_LENGTH_SETTING =
|
||||
|
@ -65,7 +68,7 @@ public class CryptoService extends AbstractComponent {
|
|||
*/
|
||||
private final SecretKey encryptionKey;
|
||||
|
||||
public CryptoService(Settings settings, Environment env) throws IOException {
|
||||
public CryptoService(Settings settings) throws IOException {
|
||||
super(settings);
|
||||
this.encryptionAlgorithm = ENCRYPTION_ALGO_SETTING.get(settings);
|
||||
final int keyLength = ENCRYPTION_KEY_LENGTH_SETTING.get(settings);
|
||||
|
@ -76,17 +79,13 @@ public class CryptoService extends AbstractComponent {
|
|||
throw new IllegalArgumentException("invalid key length [" + keyLength + "]. value must be a multiple of 8");
|
||||
}
|
||||
|
||||
Path keyFile = resolveSystemKey(env);
|
||||
SecretKey systemKey = readSystemKey(keyFile, SYSTEM_KEY_REQUIRED_SETTING.get(settings));
|
||||
|
||||
SecretKey systemKey = readSystemKey(Watcher.ENCRYPTION_KEY_SETTING.get(settings));
|
||||
try {
|
||||
encryptionKey = encryptionKey(systemKey, keyLength, keyAlgorithm);
|
||||
} catch (NoSuchAlgorithmException nsae) {
|
||||
throw new ElasticsearchException("failed to start crypto service. could not load encryption key", nsae);
|
||||
}
|
||||
if (systemKey != null) {
|
||||
logger.info("system key [{}] has been loaded", keyFile.toAbsolutePath());
|
||||
}
|
||||
assert encryptionKey != null : "the encryption key should never be null";
|
||||
}
|
||||
|
||||
public static byte[] generateKey() {
|
||||
|
@ -103,21 +102,14 @@ public class CryptoService extends AbstractComponent {
|
|||
}
|
||||
}
|
||||
|
||||
public static Path resolveSystemKey(Environment env) {
|
||||
return XPackPlugin.resolveConfigFile(env, FILE_NAME);
|
||||
}
|
||||
|
||||
private static SecretKey readSystemKey(Path file, boolean required) throws IOException {
|
||||
if (Files.exists(file)) {
|
||||
byte[] bytes = Files.readAllBytes(file);
|
||||
return new SecretKeySpec(bytes, KEY_ALGO);
|
||||
private static SecretKey readSystemKey(InputStream in) throws IOException {
|
||||
final int keySizeBytes = KEY_SIZE / 8;
|
||||
final byte[] keyBytes = new byte[keySizeBytes];
|
||||
final int read = Streams.readFully(in, keyBytes);
|
||||
if (read != keySizeBytes) {
|
||||
throw new IllegalArgumentException("key size did not match expected value; was the key generated with syskeygen?");
|
||||
}
|
||||
|
||||
if (required) {
|
||||
throw new FileNotFoundException("[" + file + "] must be present with a valid key");
|
||||
}
|
||||
|
||||
return null;
|
||||
return new SecretKeySpec(keyBytes, KEY_ALGO);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -126,15 +118,8 @@ public class CryptoService extends AbstractComponent {
|
|||
* @return character array representing the encrypted data
|
||||
*/
|
||||
public char[] encrypt(char[] chars) {
|
||||
SecretKey key = this.encryptionKey;
|
||||
if (key == null) {
|
||||
logger.warn("encrypt called without a key, returning plain text. run syskeygen and copy same key to all nodes to enable " +
|
||||
"encryption");
|
||||
return chars;
|
||||
}
|
||||
|
||||
byte[] charBytes = CharArrays.toUtf8Bytes(chars);
|
||||
String base64 = Base64.getEncoder().encodeToString(encryptInternal(charBytes, key));
|
||||
String base64 = Base64.getEncoder().encodeToString(encryptInternal(charBytes, encryptionKey));
|
||||
return ENCRYPTED_TEXT_PREFIX.concat(base64).toCharArray();
|
||||
}
|
||||
|
||||
|
@ -144,10 +129,6 @@ public class CryptoService extends AbstractComponent {
|
|||
* @return plaintext chars
|
||||
*/
|
||||
public char[] decrypt(char[] chars) {
|
||||
if (encryptionKey == null) {
|
||||
return chars;
|
||||
}
|
||||
|
||||
if (!isEncrypted(chars)) {
|
||||
// Not encrypted
|
||||
return chars;
|
||||
|
@ -170,18 +151,10 @@ public class CryptoService extends AbstractComponent {
|
|||
* @param chars the chars to check if they are encrypted
|
||||
* @return true is data is encrypted
|
||||
*/
|
||||
public boolean isEncrypted(char[] chars) {
|
||||
protected boolean isEncrypted(char[] chars) {
|
||||
return CharArrays.charsBeginsWith(ENCRYPTED_TEXT_PREFIX, chars);
|
||||
}
|
||||
|
||||
/**
|
||||
* Flag for callers to determine if values will actually be encrypted or returned plaintext
|
||||
* @return true if values will be encrypted
|
||||
*/
|
||||
public boolean isEncryptionEnabled() {
|
||||
return this.encryptionKey != null;
|
||||
}
|
||||
|
||||
private byte[] encryptInternal(byte[] bytes, SecretKey key) {
|
||||
byte[] iv = new byte[ivLength];
|
||||
secureRandom.nextBytes(iv);
|
||||
|
@ -217,7 +190,7 @@ public class CryptoService extends AbstractComponent {
|
|||
}
|
||||
|
||||
|
||||
static Cipher cipher(int mode, String encryptionAlgorithm, SecretKey key, byte[] initializationVector) {
|
||||
private static Cipher cipher(int mode, String encryptionAlgorithm, SecretKey key, byte[] initializationVector) {
|
||||
try {
|
||||
Cipher cipher = Cipher.getInstance(encryptionAlgorithm);
|
||||
cipher.init(mode, key, new IvParameterSpec(initializationVector));
|
||||
|
@ -227,11 +200,7 @@ public class CryptoService extends AbstractComponent {
|
|||
}
|
||||
}
|
||||
|
||||
static SecretKey encryptionKey(SecretKey systemKey, int keyLength, String algorithm) throws NoSuchAlgorithmException {
|
||||
if (systemKey == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
private static SecretKey encryptionKey(SecretKey systemKey, int keyLength, String algorithm) throws NoSuchAlgorithmException {
|
||||
byte[] bytes = systemKey.getEncoded();
|
||||
if ((bytes.length * 8) < keyLength) {
|
||||
throw new IllegalArgumentException("at least " + keyLength + " bits should be provided as key data");
|
||||
|
@ -253,6 +222,5 @@ public class CryptoService extends AbstractComponent {
|
|||
settings.add(ENCRYPTION_KEY_LENGTH_SETTING);
|
||||
settings.add(ENCRYPTION_KEY_ALGO_SETTING);
|
||||
settings.add(ENCRYPTION_ALGO_SETTING);
|
||||
settings.add(SYSTEM_KEY_REQUIRED_SETTING);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -15,6 +15,7 @@ import org.elasticsearch.common.SuppressForbidden;
|
|||
import org.elasticsearch.common.io.PathUtils;
|
||||
import org.elasticsearch.common.util.set.Sets;
|
||||
import org.elasticsearch.env.Environment;
|
||||
import org.elasticsearch.xpack.XPackPlugin;
|
||||
import org.elasticsearch.xpack.security.crypto.CryptoService;
|
||||
|
||||
import java.nio.file.Files;
|
||||
|
@ -61,7 +62,7 @@ public class SystemKeyTool extends EnvironmentAwareCommand {
|
|||
}
|
||||
keyPath = parsePath(args.get(0));
|
||||
} else {
|
||||
keyPath = CryptoService.resolveSystemKey(env);
|
||||
keyPath = env.configFile().resolve(XPackPlugin.NAME).resolve("system_key");
|
||||
}
|
||||
|
||||
// write the key
|
||||
|
@ -75,7 +76,7 @@ public class SystemKeyTool extends EnvironmentAwareCommand {
|
|||
if (view != null) {
|
||||
view.setPermissions(PERMISSION_OWNER_READ_WRITE);
|
||||
terminal.println("Ensure the generated key can be read by the user that Elasticsearch runs as, "
|
||||
+ "permissions are set to owner read/write only");
|
||||
+ "permissions are set to owner read/write only");
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -84,4 +85,4 @@ public class SystemKeyTool extends EnvironmentAwareCommand {
|
|||
return PathUtils.get(path);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
|
@ -17,6 +17,7 @@ import org.elasticsearch.common.util.concurrent.ThreadContext;
|
|||
import org.elasticsearch.license.XPackLicenseState;
|
||||
import org.elasticsearch.tasks.Task;
|
||||
import org.elasticsearch.threadpool.ThreadPool;
|
||||
import org.elasticsearch.transport.TcpTransport;
|
||||
import org.elasticsearch.transport.Transport;
|
||||
import org.elasticsearch.transport.TransportChannel;
|
||||
import org.elasticsearch.transport.TransportException;
|
||||
|
@ -28,7 +29,6 @@ import org.elasticsearch.transport.TransportResponse;
|
|||
import org.elasticsearch.transport.TransportResponseHandler;
|
||||
import org.elasticsearch.transport.TransportService;
|
||||
import org.elasticsearch.transport.TransportService.ContextRestoreResponseHandler;
|
||||
import org.elasticsearch.transport.TransportSettings;
|
||||
import org.elasticsearch.xpack.XPackSettings;
|
||||
import org.elasticsearch.xpack.security.SecurityContext;
|
||||
import org.elasticsearch.xpack.security.authc.AuthenticationService;
|
||||
|
@ -168,9 +168,9 @@ public class SecurityServerTransportInterceptor extends AbstractComponent implem
|
|||
}
|
||||
}
|
||||
|
||||
if (!profileFilters.containsKey(TransportSettings.DEFAULT_PROFILE)) {
|
||||
if (!profileFilters.containsKey(TcpTransport.DEFAULT_PROFILE)) {
|
||||
final boolean extractClientCert = sslService.isSSLClientAuthEnabled(transportSSLSettings);
|
||||
profileFilters.put(TransportSettings.DEFAULT_PROFILE, new ServerTransportFilter.NodeProfile(authcService, authzService,
|
||||
profileFilters.put(TcpTransport.DEFAULT_PROFILE, new ServerTransportFilter.NodeProfile(authcService, authzService,
|
||||
threadPool.getThreadContext(), extractClientCert, destructiveOperations, reservedRealmEnabled, securityContext));
|
||||
}
|
||||
|
||||
|
|
|
@ -18,7 +18,7 @@ import org.elasticsearch.common.settings.Settings;
|
|||
import org.elasticsearch.common.transport.BoundTransportAddress;
|
||||
import org.elasticsearch.common.transport.TransportAddress;
|
||||
import org.elasticsearch.license.XPackLicenseState;
|
||||
import org.elasticsearch.transport.TransportSettings;
|
||||
import org.elasticsearch.transport.TcpTransport;
|
||||
import org.elasticsearch.xpack.security.audit.AuditTrailService;
|
||||
|
||||
import java.net.InetSocketAddress;
|
||||
|
@ -118,7 +118,7 @@ public class IPFilter {
|
|||
isHttpFilterEnabled = IP_FILTER_ENABLED_HTTP_SETTING.get(settings);
|
||||
isIpFilterEnabled = IP_FILTER_ENABLED_SETTING.get(settings);
|
||||
|
||||
this.transportGroups = TransportSettings.TRANSPORT_PROFILES_SETTING.get(settings).getAsGroups(); // this is pretty crazy that we
|
||||
this.transportGroups = TcpTransport.TRANSPORT_PROFILES_SETTING.get(settings).getAsGroups(); // this is pretty crazy that we
|
||||
// allow this to be updateable!!! - we have to fix this very soon
|
||||
clusterSettings.addSettingsUpdateConsumer(IP_FILTER_ENABLED_HTTP_SETTING, this::setHttpFiltering);
|
||||
clusterSettings.addSettingsUpdateConsumer(IP_FILTER_ENABLED_SETTING, this::setTransportFiltering);
|
||||
|
@ -126,7 +126,7 @@ public class IPFilter {
|
|||
clusterSettings.addSettingsUpdateConsumer(TRANSPORT_FILTER_DENY_SETTING, this::setTransportDenyFilter);
|
||||
clusterSettings.addSettingsUpdateConsumer(HTTP_FILTER_ALLOW_SETTING, this::setHttpAllowFilter);
|
||||
clusterSettings.addSettingsUpdateConsumer(HTTP_FILTER_DENY_SETTING, this::setHttpDenyFilter);
|
||||
clusterSettings.addSettingsUpdateConsumer(TransportSettings.TRANSPORT_PROFILES_SETTING, this::setTransportProfiles);
|
||||
clusterSettings.addSettingsUpdateConsumer(TcpTransport.TRANSPORT_PROFILES_SETTING, this::setTransportProfiles);
|
||||
updateRules();
|
||||
}
|
||||
|
||||
|
|
|
@ -19,7 +19,7 @@ import org.elasticsearch.common.settings.Settings;
|
|||
import org.elasticsearch.common.util.BigArrays;
|
||||
import org.elasticsearch.indices.breaker.CircuitBreakerService;
|
||||
import org.elasticsearch.threadpool.ThreadPool;
|
||||
import org.elasticsearch.transport.TransportSettings;
|
||||
import org.elasticsearch.transport.TcpTransport;
|
||||
import org.elasticsearch.transport.netty4.Netty4Transport;
|
||||
import org.elasticsearch.xpack.ssl.SSLConfiguration;
|
||||
import org.elasticsearch.xpack.ssl.SSLService;
|
||||
|
@ -65,8 +65,8 @@ public class SecurityNetty4Transport extends Netty4Transport {
|
|||
profileConfiguration.put(entry.getKey(), configuration);
|
||||
}
|
||||
|
||||
if (profileConfiguration.containsKey(TransportSettings.DEFAULT_PROFILE) == false) {
|
||||
profileConfiguration.put(TransportSettings.DEFAULT_PROFILE, sslConfiguration);
|
||||
if (profileConfiguration.containsKey(TcpTransport.DEFAULT_PROFILE) == false) {
|
||||
profileConfiguration.put(TcpTransport.DEFAULT_PROFILE, sslConfiguration);
|
||||
|
||||
}
|
||||
|
||||
|
|
|
@ -7,6 +7,9 @@ package org.elasticsearch.xpack.security.user;
|
|||
|
||||
import org.elasticsearch.xpack.security.support.MetadataUtils;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* The reserved {@code elastic} superuser. Has full permission/access to the cluster/indices and can
|
||||
* run as any other user.
|
||||
|
@ -15,8 +18,27 @@ public class ElasticUser extends User {
|
|||
|
||||
public static final String NAME = "elastic";
|
||||
private static final String ROLE_NAME = "superuser";
|
||||
private static final String SETUP_MODE = "_setup_mode";
|
||||
|
||||
public ElasticUser(boolean enabled) {
|
||||
super(NAME, new String[] { ROLE_NAME }, null, null, MetadataUtils.DEFAULT_RESERVED_METADATA, enabled);
|
||||
this(enabled, false);
|
||||
}
|
||||
|
||||
public ElasticUser(boolean enabled, boolean setupMode) {
|
||||
super(NAME, new String[] { ROLE_NAME }, null, null, metadata(setupMode), enabled);
|
||||
}
|
||||
|
||||
public static boolean isElasticUserInSetupMode(User user) {
|
||||
return NAME.equals(user.principal()) && Boolean.TRUE.equals(user.metadata().get(SETUP_MODE));
|
||||
}
|
||||
|
||||
private static Map<String, Object> metadata(boolean setupMode) {
|
||||
if (setupMode == false) {
|
||||
return MetadataUtils.DEFAULT_RESERVED_METADATA;
|
||||
} else {
|
||||
HashMap<String, Object> metadata = new HashMap<>(MetadataUtils.DEFAULT_RESERVED_METADATA);
|
||||
metadata.put(SETUP_MODE, true);
|
||||
return metadata;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -16,7 +16,7 @@ import org.elasticsearch.common.Strings;
|
|||
import org.elasticsearch.common.component.AbstractComponent;
|
||||
import org.elasticsearch.common.settings.Settings;
|
||||
import org.elasticsearch.env.Environment;
|
||||
import org.elasticsearch.transport.TransportSettings;
|
||||
import org.elasticsearch.transport.TcpTransport;
|
||||
import org.elasticsearch.xpack.XPackSettings;
|
||||
import org.elasticsearch.xpack.common.socket.SocketAccess;
|
||||
import org.elasticsearch.xpack.security.Security;
|
||||
|
@ -852,7 +852,7 @@ public class SSLService extends AbstractComponent {
|
|||
|
||||
private static List<Settings> getTransportProfileSSLSettings(Settings settings) {
|
||||
List<Settings> sslSettings = new ArrayList<>();
|
||||
Map<String, Settings> profiles = TransportSettings.TRANSPORT_PROFILES_SETTING.get(settings).getAsGroups(true);
|
||||
Map<String, Settings> profiles = TcpTransport.TRANSPORT_PROFILES_SETTING.get(settings).getAsGroups(true);
|
||||
for (Entry<String, Settings> entry : profiles.entrySet()) {
|
||||
Settings profileSettings = entry.getValue().getByPrefix("xpack.security.ssl.");
|
||||
if (profileSettings.isEmpty() == false) {
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -8,6 +8,7 @@ package org.elasticsearch.xpack.watcher;
|
|||
import org.apache.logging.log4j.Logger;
|
||||
import org.elasticsearch.action.ActionRequest;
|
||||
import org.elasticsearch.action.ActionResponse;
|
||||
import org.elasticsearch.bootstrap.BootstrapCheck;
|
||||
import org.elasticsearch.cluster.NamedDiff;
|
||||
import org.elasticsearch.cluster.metadata.IndexNameExpressionResolver;
|
||||
import org.elasticsearch.cluster.metadata.IndexTemplateMetaData;
|
||||
|
@ -25,12 +26,14 @@ import org.elasticsearch.common.logging.Loggers;
|
|||
import org.elasticsearch.common.regex.Regex;
|
||||
import org.elasticsearch.common.settings.ClusterSettings;
|
||||
import org.elasticsearch.common.settings.IndexScopedSettings;
|
||||
import org.elasticsearch.common.settings.SecureSetting;
|
||||
import org.elasticsearch.common.settings.Setting;
|
||||
import org.elasticsearch.common.settings.Settings;
|
||||
import org.elasticsearch.common.settings.SettingsFilter;
|
||||
import org.elasticsearch.common.unit.TimeValue;
|
||||
import org.elasticsearch.common.util.concurrent.EsExecutors;
|
||||
import org.elasticsearch.common.xcontent.NamedXContentRegistry;
|
||||
import org.elasticsearch.env.Environment;
|
||||
import org.elasticsearch.index.IndexModule;
|
||||
import org.elasticsearch.license.XPackLicenseState;
|
||||
import org.elasticsearch.plugins.ActionPlugin;
|
||||
|
@ -153,6 +156,7 @@ import org.elasticsearch.xpack.watcher.watch.Watch;
|
|||
import org.joda.time.DateTime;
|
||||
import org.joda.time.DateTimeZone;
|
||||
|
||||
import java.io.InputStream;
|
||||
import java.time.Clock;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
|
@ -177,6 +181,7 @@ public class Watcher implements ActionPlugin {
|
|||
new Setting<>("index.xpack.watcher.template.version", "", Function.identity(), Setting.Property.IndexScope);
|
||||
public static final Setting<Boolean> ENCRYPT_SENSITIVE_DATA_SETTING =
|
||||
Setting.boolSetting("xpack.watcher.encrypt_sensitive_data", false, Setting.Property.NodeScope);
|
||||
public static final Setting<InputStream> ENCRYPTION_KEY_SETTING = SecureSetting.secureFile("xpack.watcher.encryption_key", null);
|
||||
public static final Setting<TimeValue> MAX_STOP_TIMEOUT_SETTING =
|
||||
Setting.timeSetting("xpack.watcher.stop.timeout", TimeValue.timeValueSeconds(30), Setting.Property.NodeScope);
|
||||
|
||||
|
@ -367,6 +372,7 @@ public class Watcher implements ActionPlugin {
|
|||
settings.add(Setting.intSetting("xpack.watcher.execution.scroll.size", 0, Setting.Property.NodeScope));
|
||||
settings.add(Setting.intSetting("xpack.watcher.watch.scroll.size", 0, Setting.Property.NodeScope));
|
||||
settings.add(ENCRYPT_SENSITIVE_DATA_SETTING);
|
||||
settings.add(ENCRYPTION_KEY_SETTING);
|
||||
|
||||
settings.add(Setting.simpleString("xpack.watcher.internal.ops.search.default_timeout", Setting.Property.NodeScope));
|
||||
settings.add(Setting.simpleString("xpack.watcher.internal.ops.bulk.default_timeout", Setting.Property.NodeScope));
|
||||
|
@ -379,6 +385,8 @@ public class Watcher implements ActionPlugin {
|
|||
settings.add(Setting.simpleString("xpack.watcher.execution.scroll.timeout", Setting.Property.NodeScope));
|
||||
settings.add(Setting.simpleString("xpack.watcher.start_immediately", Setting.Property.NodeScope));
|
||||
|
||||
// encryption settings
|
||||
CryptoService.addSettings(settings);
|
||||
return settings;
|
||||
}
|
||||
|
||||
|
@ -512,4 +520,8 @@ public class Watcher implements ActionPlugin {
|
|||
return map;
|
||||
};
|
||||
}
|
||||
|
||||
public List<BootstrapCheck> getBootstrapChecks() {
|
||||
return Collections.singletonList(new EncryptSensitiveDataBootstrapCheck(settings, new Environment(settings)));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -12,7 +12,6 @@ import org.elasticsearch.common.settings.Settings;
|
|||
import org.elasticsearch.common.xcontent.NamedXContentRegistry;
|
||||
import org.elasticsearch.common.xcontent.XContentFactory;
|
||||
import org.elasticsearch.common.xcontent.XContentParser;
|
||||
import org.elasticsearch.index.query.QueryParseContext;
|
||||
import org.elasticsearch.script.Script;
|
||||
import org.elasticsearch.script.ScriptService;
|
||||
import org.elasticsearch.script.TemplateScript;
|
||||
|
@ -63,7 +62,7 @@ public class WatcherSearchTemplateService extends AbstractComponent {
|
|||
BytesReference source = request.getSearchSource();
|
||||
if (source != null && source.length() > 0) {
|
||||
try (XContentParser parser = XContentFactory.xContent(source).createParser(xContentRegistry, source)) {
|
||||
sourceBuilder.parseXContent(new QueryParseContext(parser));
|
||||
sourceBuilder.parseXContent(parser);
|
||||
searchRequest.source(sourceBuilder);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -22,7 +22,6 @@ import org.elasticsearch.common.xcontent.XContentType;
|
|||
import org.elasticsearch.xpack.common.secret.Secret;
|
||||
import org.elasticsearch.xpack.security.crypto.CryptoService;
|
||||
import org.elasticsearch.xpack.support.clock.HaltedClock;
|
||||
import org.elasticsearch.xpack.watcher.Watcher;
|
||||
import org.elasticsearch.xpack.watcher.actions.ActionRegistry;
|
||||
import org.elasticsearch.xpack.watcher.actions.ActionStatus;
|
||||
import org.elasticsearch.xpack.watcher.actions.ActionWrapper;
|
||||
|
@ -209,7 +208,7 @@ public class Watch implements ToXContentObject {
|
|||
this.triggerService = triggerService;
|
||||
this.actionRegistry = actionRegistry;
|
||||
this.inputRegistry = inputRegistry;
|
||||
this.cryptoService = Watcher.ENCRYPT_SENSITIVE_DATA_SETTING.get(settings) ? cryptoService : null;
|
||||
this.cryptoService = cryptoService;
|
||||
this.defaultInput = new ExecutableNoneInput(logger);
|
||||
this.defaultCondition = AlwaysCondition.INSTANCE;
|
||||
this.defaultActions = Collections.emptyList();
|
||||
|
|
|
@ -74,8 +74,8 @@ public class BulkUpdateTests extends SecurityIntegTestCase {
|
|||
public void testThatBulkUpdateDoesNotLoseFieldsHttp() throws IOException {
|
||||
final String path = "/index1/type/1";
|
||||
final Header basicAuthHeader = new BasicHeader("Authorization",
|
||||
UsernamePasswordToken.basicAuthHeaderValue(SecuritySettingsSource.DEFAULT_USER_NAME,
|
||||
new SecureString(SecuritySettingsSource.DEFAULT_PASSWORD.toCharArray())));
|
||||
UsernamePasswordToken.basicAuthHeaderValue(SecuritySettingsSource.TEST_USER_NAME,
|
||||
new SecureString(SecuritySettingsSource.TEST_PASSWORD.toCharArray())));
|
||||
|
||||
StringEntity body = new StringEntity("{\"test\":\"test\"}", ContentType.APPLICATION_JSON);
|
||||
Response response = getRestClient().performRequest("PUT", path, Collections.emptyMap(), body, basicAuthHeader);
|
||||
|
|
|
@ -18,6 +18,7 @@ import org.elasticsearch.test.SecurityIntegTestCase;
|
|||
import org.elasticsearch.test.SecuritySettingsSource;
|
||||
import org.elasticsearch.xpack.security.action.realm.ClearRealmCacheRequest;
|
||||
import org.elasticsearch.xpack.security.action.realm.ClearRealmCacheResponse;
|
||||
import org.elasticsearch.xpack.security.authc.IncomingRequest;
|
||||
import org.elasticsearch.xpack.security.authc.Realm;
|
||||
import org.elasticsearch.xpack.security.authc.Realms;
|
||||
import org.elasticsearch.xpack.security.authc.support.Hasher;
|
||||
|
@ -40,6 +41,7 @@ import static org.hamcrest.Matchers.equalTo;
|
|||
import static org.hamcrest.Matchers.not;
|
||||
import static org.hamcrest.Matchers.notNullValue;
|
||||
import static org.hamcrest.Matchers.sameInstance;
|
||||
import static org.mockito.Mockito.mock;
|
||||
|
||||
public class ClearRealmsCacheTests extends SecurityIntegTestCase {
|
||||
private static final String USERS_PASSWD_HASHED = new String(Hasher.BCRYPT.hash(new SecureString("passwd".toCharArray())));
|
||||
|
@ -164,8 +166,8 @@ public class ClearRealmsCacheTests extends SecurityIntegTestCase {
|
|||
static void executeHttpRequest(String path, Map<String, String> params) throws Exception {
|
||||
Response response = getRestClient().performRequest("POST", path, params,
|
||||
new BasicHeader(UsernamePasswordToken.BASIC_AUTH_HEADER,
|
||||
UsernamePasswordToken.basicAuthHeaderValue(SecuritySettingsSource.DEFAULT_USER_NAME,
|
||||
new SecureString(SecuritySettingsSource.DEFAULT_PASSWORD.toCharArray()))));
|
||||
UsernamePasswordToken.basicAuthHeaderValue(SecuritySettingsSource.TEST_USER_NAME,
|
||||
new SecureString(SecuritySettingsSource.TEST_PASSWORD.toCharArray()))));
|
||||
assertNotNull(response.getEntity());
|
||||
assertTrue(EntityUtils.toString(response.getEntity()).contains("cluster_name"));
|
||||
}
|
||||
|
@ -233,7 +235,7 @@ public class ClearRealmsCacheTests extends SecurityIntegTestCase {
|
|||
for (Realm realm : realms) {
|
||||
for (String username : usernames) {
|
||||
PlainActionFuture<User> future = new PlainActionFuture<>();
|
||||
realm.authenticate(tokens.get(username), future);
|
||||
realm.authenticate(tokens.get(username), future, mock(IncomingRequest.class));
|
||||
User user = future.actionGet();
|
||||
assertThat(user, notNullValue());
|
||||
Map<Realm, User> realmToUser = users.get(username);
|
||||
|
@ -250,7 +252,7 @@ public class ClearRealmsCacheTests extends SecurityIntegTestCase {
|
|||
for (String username : usernames) {
|
||||
for (Realm realm : realms) {
|
||||
PlainActionFuture<User> future = new PlainActionFuture<>();
|
||||
realm.authenticate(tokens.get(username), future);
|
||||
realm.authenticate(tokens.get(username), future, mock(IncomingRequest.class));
|
||||
User user = future.actionGet();
|
||||
assertThat(user, sameInstance(users.get(username).get(realm)));
|
||||
}
|
||||
|
@ -263,7 +265,7 @@ public class ClearRealmsCacheTests extends SecurityIntegTestCase {
|
|||
for (String username : usernames) {
|
||||
for (Realm realm : realms) {
|
||||
PlainActionFuture<User> future = new PlainActionFuture<>();
|
||||
realm.authenticate(tokens.get(username), future);
|
||||
realm.authenticate(tokens.get(username), future, mock(IncomingRequest.class));
|
||||
User user = future.actionGet();
|
||||
assertThat(user, notNullValue());
|
||||
scenario.assertEviction(users.get(username).get(realm), user);
|
||||
|
|
|
@ -33,7 +33,7 @@ public class MultipleIndicesPermissionsTests extends SecurityIntegTestCase {
|
|||
|
||||
@Override
|
||||
protected String configRoles() {
|
||||
return SecuritySettingsSource.DEFAULT_ROLE + ":\n" +
|
||||
return SecuritySettingsSource.TEST_ROLE + ":\n" +
|
||||
" cluster: [ all ]\n" +
|
||||
" indices:\n" +
|
||||
" - names: '*'\n" +
|
||||
|
|
|
@ -7,7 +7,6 @@ package org.elasticsearch.integration;
|
|||
|
||||
import org.elasticsearch.ElasticsearchSecurityException;
|
||||
import org.elasticsearch.action.search.SearchResponse;
|
||||
import org.elasticsearch.common.settings.SecureString;
|
||||
import org.elasticsearch.index.query.QueryBuilders;
|
||||
import org.elasticsearch.indices.TermsLookup;
|
||||
import org.elasticsearch.test.SecurityIntegTestCase;
|
||||
|
@ -26,7 +25,7 @@ public class SecurityCachePermissionTests extends SecurityIntegTestCase {
|
|||
@Override
|
||||
public String configUsers() {
|
||||
return super.configUsers()
|
||||
+ READ_ONE_IDX_USER + ":" + SecuritySettingsSource.DEFAULT_PASSWORD_HASHED + "\n";
|
||||
+ READ_ONE_IDX_USER + ":" + SecuritySettingsSource.TEST_PASSWORD_HASHED + "\n";
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -61,7 +60,7 @@ public class SecurityCachePermissionTests extends SecurityIntegTestCase {
|
|||
// Repeat with unauthorized user!!!!
|
||||
try {
|
||||
response = client().filterWithHeader(singletonMap("Authorization", basicAuthHeaderValue(READ_ONE_IDX_USER,
|
||||
new SecureString("changeme".toCharArray()))))
|
||||
SecuritySettingsSource.TEST_PASSWORD_SECURE_STRING)))
|
||||
.prepareSearch("data").setTypes("a").setQuery(QueryBuilders.constantScoreQuery(
|
||||
QueryBuilders.termsLookupQuery("token", new TermsLookup("tokens", "tokens", "1", "tokens"))))
|
||||
.execute().actionGet();
|
||||
|
|
|
@ -78,7 +78,7 @@ import static org.hamcrest.Matchers.notNullValue;
|
|||
@TestLogging("org.elasticsearch.cluster.service:TRACE,org.elasticsearch.discovery.zen:TRACE")
|
||||
public class LicensingTests extends SecurityIntegTestCase {
|
||||
public static final String ROLES =
|
||||
SecuritySettingsSource.DEFAULT_ROLE + ":\n" +
|
||||
SecuritySettingsSource.TEST_ROLE + ":\n" +
|
||||
" cluster: [ all ]\n" +
|
||||
" indices:\n" +
|
||||
" - names: '*'\n" +
|
||||
|
@ -204,8 +204,8 @@ public class LicensingTests extends SecurityIntegTestCase {
|
|||
e = expectThrows(ResponseException.class, () -> getRestClient().performRequest("GET", "/_xpack/security/_authenticate"));
|
||||
assertThat(e.getResponse().getStatusLine().getStatusCode(), is(401));
|
||||
|
||||
final String basicAuthValue = UsernamePasswordToken.basicAuthHeaderValue(SecuritySettingsSource.DEFAULT_USER_NAME,
|
||||
new SecureString(SecuritySettingsSource.DEFAULT_PASSWORD.toCharArray()));
|
||||
final String basicAuthValue = UsernamePasswordToken.basicAuthHeaderValue(SecuritySettingsSource.TEST_USER_NAME,
|
||||
new SecureString(SecuritySettingsSource.TEST_PASSWORD.toCharArray()));
|
||||
response = getRestClient().performRequest("GET", "/", new BasicHeader("Authorization", basicAuthValue));
|
||||
assertThat(response.getStatusLine().getStatusCode(), is(200));
|
||||
response = getRestClient()
|
||||
|
|
|
@ -5,10 +5,28 @@
|
|||
*/
|
||||
package org.elasticsearch.test;
|
||||
|
||||
|
||||
import org.apache.http.HttpEntity;
|
||||
import org.apache.http.entity.ContentType;
|
||||
import org.apache.http.message.BasicHeader;
|
||||
import org.apache.http.nio.entity.NStringEntity;
|
||||
import org.elasticsearch.client.Response;
|
||||
import org.elasticsearch.common.network.NetworkModule;
|
||||
import org.elasticsearch.common.settings.SecureString;
|
||||
import org.elasticsearch.common.settings.Settings;
|
||||
import org.elasticsearch.xpack.security.authc.support.UsernamePasswordToken;
|
||||
import org.elasticsearch.xpack.security.client.SecurityClient;
|
||||
import org.elasticsearch.xpack.security.user.BeatsSystemUser;
|
||||
import org.elasticsearch.xpack.security.user.ElasticUser;
|
||||
import org.elasticsearch.xpack.security.user.KibanaUser;
|
||||
import org.elasticsearch.xpack.security.user.LogstashSystemUser;
|
||||
import org.junit.After;
|
||||
import org.junit.Before;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
|
||||
/**
|
||||
* Test case with method to handle the starting and stopping the stores for native users and roles
|
||||
*/
|
||||
|
@ -17,6 +35,7 @@ public abstract class NativeRealmIntegTestCase extends SecurityIntegTestCase {
|
|||
@Before
|
||||
public void ensureNativeStoresStarted() throws Exception {
|
||||
assertSecurityIndexActive();
|
||||
setupReservedPasswords();
|
||||
}
|
||||
|
||||
@After
|
||||
|
@ -29,4 +48,41 @@ public abstract class NativeRealmIntegTestCase extends SecurityIntegTestCase {
|
|||
client.prepareClearRealmCache().get();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Settings nodeSettings(int nodeOrdinal) {
|
||||
return Settings.builder()
|
||||
.put(super.nodeSettings(nodeOrdinal))
|
||||
.put(NetworkModule.HTTP_ENABLED.getKey(), true)
|
||||
.build();
|
||||
}
|
||||
|
||||
private SecureString reservedPassword = SecuritySettingsSource.TEST_PASSWORD_SECURE_STRING;
|
||||
|
||||
protected SecureString getReservedPassword() {
|
||||
return reservedPassword;
|
||||
}
|
||||
|
||||
protected boolean shouldSetReservedUserPasswords() {
|
||||
return true;
|
||||
}
|
||||
|
||||
public void setupReservedPasswords() throws IOException {
|
||||
if (shouldSetReservedUserPasswords() == false) {
|
||||
return;
|
||||
}
|
||||
logger.info("setting up reserved passwords for test");
|
||||
SecureString defaultPassword = new SecureString("".toCharArray());
|
||||
|
||||
for (String username : Arrays.asList(ElasticUser.NAME, KibanaUser.NAME, BeatsSystemUser.NAME, LogstashSystemUser.NAME)) {
|
||||
SecureString authPassword = username.equals(ElasticUser.NAME) ? defaultPassword : reservedPassword;
|
||||
String payload = "{\"password\": \"" + new String(reservedPassword.getChars()) + "\"}";
|
||||
HttpEntity entity = new NStringEntity(payload, ContentType.APPLICATION_JSON);
|
||||
BasicHeader authHeader = new BasicHeader(UsernamePasswordToken.BASIC_AUTH_HEADER,
|
||||
UsernamePasswordToken.basicAuthHeaderValue(ElasticUser.NAME, authPassword));
|
||||
String route = "/_xpack/security/user/" + username + "/_password";
|
||||
Response response = getRestClient().performRequest("PUT", route, Collections.emptyMap(), entity, authHeader);
|
||||
}
|
||||
logger.info("setting up reserved passwords finished");
|
||||
}
|
||||
}
|
||||
|
|
|
@ -244,8 +244,8 @@ public abstract class SecurityIntegTestCase extends ESIntegTestCase {
|
|||
@Override
|
||||
protected Settings externalClusterClientSettings() {
|
||||
return Settings.builder()
|
||||
.put(Security.USER_SETTING.getKey(), SecuritySettingsSource.DEFAULT_USER_NAME + ":"
|
||||
+ SecuritySettingsSource.DEFAULT_PASSWORD)
|
||||
.put(Security.USER_SETTING.getKey(), SecuritySettingsSource.TEST_USER_NAME + ":"
|
||||
+ SecuritySettingsSource.TEST_PASSWORD)
|
||||
.build();
|
||||
}
|
||||
|
||||
|
|
|
@ -52,25 +52,25 @@ public class SecuritySettingsSource extends ClusterDiscoveryConfiguration.Unicas
|
|||
|
||||
public static final Settings DEFAULT_SETTINGS = Settings.EMPTY;
|
||||
|
||||
public static final String DEFAULT_USER_NAME = "test_user";
|
||||
public static final String DEFAULT_PASSWORD = "changeme";
|
||||
public static final SecureString DEFAULT_PASSWORD_SECURE_STRING = new SecureString("changeme".toCharArray());
|
||||
public static final String DEFAULT_PASSWORD_HASHED = new String(Hasher.BCRYPT.hash(new SecureString(DEFAULT_PASSWORD.toCharArray())));
|
||||
public static final String DEFAULT_ROLE = "user";
|
||||
public static final String TEST_USER_NAME = "test_user";
|
||||
public static final String TEST_PASSWORD = "x-pack-test-password";
|
||||
public static final SecureString TEST_PASSWORD_SECURE_STRING = new SecureString("x-pack-test-password".toCharArray());
|
||||
public static final String TEST_PASSWORD_HASHED = new String(Hasher.BCRYPT.hash(new SecureString(TEST_PASSWORD.toCharArray())));
|
||||
public static final String TEST_ROLE = "user";
|
||||
|
||||
public static final String DEFAULT_TRANSPORT_CLIENT_ROLE = "transport_client";
|
||||
public static final String DEFAULT_TRANSPORT_CLIENT_USER_NAME = "test_trans_client_user";
|
||||
|
||||
public static final String CONFIG_STANDARD_USER =
|
||||
DEFAULT_USER_NAME + ":" + DEFAULT_PASSWORD_HASHED + "\n" +
|
||||
DEFAULT_TRANSPORT_CLIENT_USER_NAME + ":" + DEFAULT_PASSWORD_HASHED + "\n";
|
||||
TEST_USER_NAME + ":" + TEST_PASSWORD_HASHED + "\n" +
|
||||
DEFAULT_TRANSPORT_CLIENT_USER_NAME + ":" + TEST_PASSWORD_HASHED + "\n";
|
||||
|
||||
public static final String CONFIG_STANDARD_USER_ROLES =
|
||||
DEFAULT_ROLE + ":" + DEFAULT_USER_NAME + "," + DEFAULT_TRANSPORT_CLIENT_USER_NAME + "\n" +
|
||||
TEST_ROLE + ":" + TEST_USER_NAME + "," + DEFAULT_TRANSPORT_CLIENT_USER_NAME + "\n" +
|
||||
DEFAULT_TRANSPORT_CLIENT_ROLE + ":" + DEFAULT_TRANSPORT_CLIENT_USER_NAME+ "\n";
|
||||
|
||||
public static final String CONFIG_ROLE_ALLOW_ALL =
|
||||
DEFAULT_ROLE + ":\n" +
|
||||
TEST_ROLE + ":\n" +
|
||||
" cluster: [ ALL ]\n" +
|
||||
" indices:\n" +
|
||||
" - names: '*'\n" +
|
||||
|
@ -174,11 +174,11 @@ public class SecuritySettingsSource extends ClusterDiscoveryConfiguration.Unicas
|
|||
}
|
||||
|
||||
protected String nodeClientUsername() {
|
||||
return DEFAULT_USER_NAME;
|
||||
return TEST_USER_NAME;
|
||||
}
|
||||
|
||||
protected SecureString nodeClientPassword() {
|
||||
return new SecureString(DEFAULT_PASSWORD.toCharArray());
|
||||
return new SecureString(TEST_PASSWORD.toCharArray());
|
||||
}
|
||||
|
||||
protected String transportClientUsername() {
|
||||
|
@ -186,7 +186,7 @@ public class SecuritySettingsSource extends ClusterDiscoveryConfiguration.Unicas
|
|||
}
|
||||
|
||||
protected SecureString transportClientPassword() {
|
||||
return new SecureString(DEFAULT_PASSWORD.toCharArray());
|
||||
return new SecureString(TEST_PASSWORD.toCharArray());
|
||||
}
|
||||
|
||||
protected Class<? extends XPackPlugin> xpackPluginClass() {
|
||||
|
|
|
@ -55,7 +55,7 @@ public class SecurityTestsUtils {
|
|||
|
||||
public static void assertAuthorizationExceptionDefaultUsers(Throwable throwable, String action) {
|
||||
assertAuthorizationException(throwable, either(containsString("[" + action + "] is unauthorized for user ["
|
||||
+ SecuritySettingsSource.DEFAULT_USER_NAME + "]")).or(containsString("[" + action + "] is unauthorized for user ["
|
||||
+ SecuritySettingsSource.TEST_USER_NAME + "]")).or(containsString("[" + action + "] is unauthorized for user ["
|
||||
+ SecuritySettingsSource.DEFAULT_TRANSPORT_CLIENT_USER_NAME + "]")));
|
||||
}
|
||||
|
||||
|
|
|
@ -11,9 +11,9 @@ import org.apache.http.message.BasicHeader;
|
|||
import org.elasticsearch.client.Response;
|
||||
import org.elasticsearch.client.ResponseException;
|
||||
import org.elasticsearch.client.RestClient;
|
||||
import org.elasticsearch.common.settings.SecureString;
|
||||
import org.elasticsearch.common.settings.Settings;
|
||||
import org.elasticsearch.common.util.concurrent.ThreadContext;
|
||||
import org.elasticsearch.test.SecuritySettingsSource;
|
||||
import org.elasticsearch.test.rest.ESRestTestCase;
|
||||
import org.elasticsearch.xpack.ml.MachineLearning;
|
||||
import org.junit.After;
|
||||
|
@ -33,9 +33,9 @@ import static org.hamcrest.Matchers.equalTo;
|
|||
public class DatafeedJobsRestIT extends ESRestTestCase {
|
||||
|
||||
private static final String BASIC_AUTH_VALUE_ELASTIC =
|
||||
basicAuthHeaderValue("elastic", new SecureString("changeme".toCharArray()));
|
||||
basicAuthHeaderValue("elastic", SecuritySettingsSource.TEST_PASSWORD_SECURE_STRING);
|
||||
private static final String BASIC_AUTH_VALUE_ML_ADMIN =
|
||||
basicAuthHeaderValue("ml_admin", new SecureString("changeme".toCharArray()));
|
||||
basicAuthHeaderValue("ml_admin", SecuritySettingsSource.TEST_PASSWORD_SECURE_STRING);
|
||||
|
||||
@Override
|
||||
protected Settings restClientSettings() {
|
||||
|
@ -50,11 +50,16 @@ public class DatafeedJobsRestIT extends ESRestTestCase {
|
|||
|
||||
@Before
|
||||
public void setUpData() throws Exception {
|
||||
String password = new String(SecuritySettingsSource.TEST_PASSWORD_SECURE_STRING.getChars());
|
||||
String elasticUserPayload = "{\"password\" : \"" + password + "\"}";
|
||||
|
||||
client().performRequest("put", "_xpack/security/user/elastic/_password", Collections.emptyMap(),
|
||||
new StringEntity(elasticUserPayload, ContentType.APPLICATION_JSON));
|
||||
|
||||
// This user has admin rights on machine learning, but (importantly for the tests) no
|
||||
// rights on any of the data indexes
|
||||
String user = "{"
|
||||
+ " \"password\" : \"changeme\","
|
||||
+ " \"password\" : \"" + password + "\","
|
||||
+ " \"roles\" : [ \"machine_learning_admin\" ]"
|
||||
+ "}";
|
||||
|
||||
|
|
|
@ -9,11 +9,11 @@ import org.apache.http.entity.ContentType;
|
|||
import org.apache.http.entity.StringEntity;
|
||||
import org.elasticsearch.client.Response;
|
||||
import org.elasticsearch.client.ResponseException;
|
||||
import org.elasticsearch.common.settings.SecureString;
|
||||
import org.elasticsearch.common.settings.Settings;
|
||||
import org.elasticsearch.common.util.concurrent.ConcurrentCollections;
|
||||
import org.elasticsearch.common.util.concurrent.ConcurrentMapLong;
|
||||
import org.elasticsearch.common.util.concurrent.ThreadContext;
|
||||
import org.elasticsearch.test.SecuritySettingsSource;
|
||||
import org.elasticsearch.test.rest.ESRestTestCase;
|
||||
import org.elasticsearch.xpack.ml.MachineLearning;
|
||||
import org.elasticsearch.xpack.ml.job.persistence.AnomalyDetectorsIndex;
|
||||
|
@ -36,7 +36,7 @@ import static org.hamcrest.Matchers.not;
|
|||
|
||||
public class MlJobIT extends ESRestTestCase {
|
||||
|
||||
private static final String BASIC_AUTH_VALUE = basicAuthHeaderValue("elastic", new SecureString("changeme".toCharArray()));
|
||||
private static final String BASIC_AUTH_VALUE = basicAuthHeaderValue("elastic", SecuritySettingsSource.TEST_PASSWORD_SECURE_STRING);
|
||||
|
||||
@Override
|
||||
protected Settings restClientSettings() {
|
||||
|
|
|
@ -20,6 +20,7 @@ import org.elasticsearch.common.xcontent.json.JsonXContent;
|
|||
import org.elasticsearch.search.SearchModule;
|
||||
import org.elasticsearch.tasks.Task;
|
||||
import org.elasticsearch.test.SecurityIntegTestCase;
|
||||
import org.elasticsearch.test.SecuritySettingsSource;
|
||||
import org.elasticsearch.xpack.XPackSettings;
|
||||
import org.elasticsearch.xpack.ml.MlMetadata;
|
||||
import org.elasticsearch.xpack.ml.action.CloseJobAction;
|
||||
|
@ -80,7 +81,7 @@ abstract class MlNativeAutodetectIntegTestCase extends SecurityIntegTestCase {
|
|||
protected Settings externalClusterClientSettings() {
|
||||
Settings.Builder builder = Settings.builder();
|
||||
builder.put(NetworkModule.TRANSPORT_TYPE_KEY, Security.NAME4);
|
||||
builder.put(Security.USER_SETTING.getKey(), "elastic:changeme");
|
||||
builder.put(Security.USER_SETTING.getKey(), "elastic:" + SecuritySettingsSource.TEST_PASSWORD_SECURE_STRING);
|
||||
builder.put(XPackSettings.MACHINE_LEARNING_ENABLED.getKey(), true);
|
||||
return builder.build();
|
||||
}
|
||||
|
|
|
@ -16,9 +16,7 @@ import org.elasticsearch.xpack.ml.job.results.Bucket;
|
|||
import org.junit.After;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import static org.hamcrest.Matchers.equalTo;
|
||||
|
@ -57,16 +55,14 @@ public class UpdateInterimResultsIT extends MlNativeAutodetectIntegTestCase {
|
|||
openJob(job.getId());
|
||||
|
||||
time = 1400000000;
|
||||
Map<Long, Integer> anomalies = new HashMap<>();
|
||||
anomalies.put(1400021500L, 14);
|
||||
|
||||
// push some data, flush job, verify no interim results
|
||||
assertThat(postData(job.getId(), createData(50, anomalies)).getProcessedRecordCount(), equalTo(50L));
|
||||
assertThat(postData(job.getId(), createData(50)).getProcessedRecordCount(), equalTo(50L));
|
||||
flushJob(job.getId(), false);
|
||||
assertThat(getInterimResults(job.getId()).isEmpty(), is(true));
|
||||
|
||||
// push some more data, flush job, verify no interim results
|
||||
assertThat(postData(job.getId(), createData(30, anomalies)).getProcessedRecordCount(), equalTo(30L));
|
||||
assertThat(postData(job.getId(), createData(30)).getProcessedRecordCount(), equalTo(30L));
|
||||
flushJob(job.getId(), false);
|
||||
assertThat(getInterimResults(job.getId()).isEmpty(), is(true));
|
||||
assertThat(time, equalTo(1400040000L));
|
||||
|
@ -81,7 +77,7 @@ public class UpdateInterimResultsIT extends MlNativeAutodetectIntegTestCase {
|
|||
// We might need to retry this while waiting for a refresh
|
||||
assertBusy(() -> {
|
||||
List<Bucket> firstInterimBuckets = getInterimResults(job.getId());
|
||||
assertThat(firstInterimBuckets.size(), equalTo(2));
|
||||
assertThat("interim buckets were: " + firstInterimBuckets, firstInterimBuckets.size(), equalTo(2));
|
||||
assertThat(firstInterimBuckets.get(0).getTimestamp().getTime(), equalTo(1400039000000L));
|
||||
assertThat(firstInterimBuckets.get(1).getTimestamp().getTime(), equalTo(1400040000000L));
|
||||
assertThat(firstInterimBuckets.get(1).getRecords().get(0).getActual().get(0), equalTo(16.0));
|
||||
|
@ -101,7 +97,7 @@ public class UpdateInterimResultsIT extends MlNativeAutodetectIntegTestCase {
|
|||
|
||||
// push rest of data, close, verify no interim results
|
||||
time += BUCKET_SPAN_SECONDS;
|
||||
assertThat(postData(job.getId(), createData(30, anomalies)).getProcessedRecordCount(), equalTo(30L));
|
||||
assertThat(postData(job.getId(), createData(30)).getProcessedRecordCount(), equalTo(30L));
|
||||
closeJob(job.getId());
|
||||
assertThat(getInterimResults(job.getId()).isEmpty(), is(true));
|
||||
|
||||
|
@ -114,10 +110,10 @@ public class UpdateInterimResultsIT extends MlNativeAutodetectIntegTestCase {
|
|||
assertThat(bucket.get(0).getRecords().get(0).getActual().get(0), equalTo(14.0));
|
||||
}
|
||||
|
||||
private String createData(int halfBuckets, Map<Long, Integer> timeToValueMap) {
|
||||
private String createData(int halfBuckets) {
|
||||
StringBuilder data = new StringBuilder();
|
||||
for (int i = 0; i < halfBuckets; i++) {
|
||||
int value = timeToValueMap.getOrDefault(time, randomIntBetween(1, 3));
|
||||
int value = randomIntBetween(1, 3);
|
||||
data.append("{\"time\":").append(time).append(", \"value\":").append(value).append("}\n");
|
||||
time += BUCKET_SPAN_SECONDS / 2;
|
||||
}
|
||||
|
|
|
@ -84,8 +84,8 @@ public class OldMonitoringIndicesBackwardsCompatibilityTests extends AbstractOld
|
|||
httpExporter.put("type", "http");
|
||||
httpExporter.put("enabled", port == null ? "false" : "true");
|
||||
httpExporter.put("host", "http://localhost:" + (port == null ? "does_not_matter" : port));
|
||||
httpExporter.put("auth.username", SecuritySettingsSource.DEFAULT_USER_NAME);
|
||||
httpExporter.put("auth.password", SecuritySettingsSource.DEFAULT_PASSWORD);
|
||||
httpExporter.put("auth.username", SecuritySettingsSource.TEST_USER_NAME);
|
||||
httpExporter.put("auth.password", SecuritySettingsSource.TEST_PASSWORD);
|
||||
|
||||
settings.putProperties(httpExporter, k -> MonitoringSettings.EXPORTERS_SETTINGS.getKey() + "my_exporter." + k);
|
||||
}
|
||||
|
|
|
@ -27,6 +27,7 @@ import org.elasticsearch.index.IndexNotFoundException;
|
|||
import org.elasticsearch.index.query.QueryBuilders;
|
||||
import org.elasticsearch.plugins.Plugin;
|
||||
import org.elasticsearch.test.ESIntegTestCase;
|
||||
import org.elasticsearch.test.SecuritySettingsSource;
|
||||
import org.elasticsearch.test.TestCluster;
|
||||
import org.elasticsearch.test.store.MockFSIndexStore;
|
||||
import org.elasticsearch.test.transport.MockTransportService;
|
||||
|
@ -157,7 +158,7 @@ public abstract class MonitoringIntegTestCase extends ESIntegTestCase {
|
|||
return Settings.builder()
|
||||
.put(super.transportClientSettings())
|
||||
.put("client.transport.sniff", false)
|
||||
.put(Security.USER_SETTING.getKey(), "test:changeme")
|
||||
.put(Security.USER_SETTING.getKey(), "test:" + SecuritySettings.TEST_PASSWORD)
|
||||
.put(NetworkModule.TRANSPORT_TYPE_KEY, Security.NAME4)
|
||||
.put(NetworkModule.HTTP_TYPE_KEY, Security.NAME4)
|
||||
.put(XPackSettings.WATCHER_ENABLED.getKey(), watcherEnabled)
|
||||
|
@ -467,7 +468,7 @@ public abstract class MonitoringIntegTestCase extends ESIntegTestCase {
|
|||
public static class SecuritySettings {
|
||||
|
||||
public static final String TEST_USERNAME = "test";
|
||||
public static final String TEST_PASSWORD = "changeme";
|
||||
public static final String TEST_PASSWORD = SecuritySettingsSource.TEST_PASSWORD;
|
||||
private static final String TEST_PASSWORD_HASHED = new String(Hasher.BCRYPT.hash(new SecureString(TEST_PASSWORD.toCharArray())));
|
||||
|
||||
static boolean auditLogsEnabled = SystemPropertyUtil.getBoolean("tests.audit_logs", true);
|
||||
|
|
|
@ -6,10 +6,12 @@
|
|||
package org.elasticsearch.xpack.notification.email;
|
||||
|
||||
import org.elasticsearch.action.get.GetResponse;
|
||||
import org.elasticsearch.common.settings.MockSecureSettings;
|
||||
import org.elasticsearch.common.settings.Settings;
|
||||
import org.elasticsearch.common.xcontent.support.XContentMapValues;
|
||||
import org.elasticsearch.xpack.notification.email.support.EmailServer;
|
||||
import org.elasticsearch.xpack.security.crypto.CryptoService;
|
||||
import org.elasticsearch.xpack.watcher.Watcher;
|
||||
import org.elasticsearch.xpack.watcher.client.WatcherClient;
|
||||
import org.elasticsearch.xpack.watcher.condition.AlwaysCondition;
|
||||
import org.elasticsearch.xpack.watcher.execution.ActionExecutionMode;
|
||||
|
@ -43,6 +45,7 @@ public class EmailSecretsIntegrationTests extends AbstractWatcherIntegrationTest
|
|||
|
||||
private EmailServer server;
|
||||
private Boolean encryptSensitiveData;
|
||||
private byte[] encryptionKey;
|
||||
|
||||
@Override
|
||||
public void setUp() throws Exception {
|
||||
|
@ -58,15 +61,23 @@ public class EmailSecretsIntegrationTests extends AbstractWatcherIntegrationTest
|
|||
@Override
|
||||
protected Settings nodeSettings(int nodeOrdinal) {
|
||||
if (encryptSensitiveData == null) {
|
||||
encryptSensitiveData = securityEnabled() && randomBoolean();
|
||||
encryptSensitiveData = randomBoolean();
|
||||
if (encryptSensitiveData) {
|
||||
encryptionKey = CryptoService.generateKey();
|
||||
}
|
||||
}
|
||||
return Settings.builder()
|
||||
Settings.Builder builder = Settings.builder()
|
||||
.put(super.nodeSettings(nodeOrdinal))
|
||||
.put("xpack.notification.email.account.test.smtp.auth", true)
|
||||
.put("xpack.notification.email.account.test.smtp.port", server.port())
|
||||
.put("xpack.notification.email.account.test.smtp.host", "localhost")
|
||||
.put("xpack.watcher.encrypt_sensitive_data", encryptSensitiveData)
|
||||
.build();
|
||||
.put("xpack.watcher.encrypt_sensitive_data", encryptSensitiveData);
|
||||
if (encryptSensitiveData) {
|
||||
MockSecureSettings secureSettings = new MockSecureSettings();
|
||||
secureSettings.setFile(Watcher.ENCRYPTION_KEY_SETTING.getKey(), encryptionKey);
|
||||
builder.setSecureSettings(secureSettings);
|
||||
}
|
||||
return builder.build();
|
||||
}
|
||||
|
||||
public void testEmail() throws Exception {
|
||||
|
@ -91,9 +102,12 @@ public class EmailSecretsIntegrationTests extends AbstractWatcherIntegrationTest
|
|||
Map<String, Object> source = response.getSource();
|
||||
Object value = XContentMapValues.extractValue("actions._email.email.password", source);
|
||||
assertThat(value, notNullValue());
|
||||
if (securityEnabled() && encryptSensitiveData) {
|
||||
if (encryptSensitiveData) {
|
||||
assertThat(value, not(is(EmailServer.PASSWORD)));
|
||||
CryptoService cryptoService = getInstanceFromMaster(CryptoService.class);
|
||||
MockSecureSettings mockSecureSettings = new MockSecureSettings();
|
||||
mockSecureSettings.setFile(Watcher.ENCRYPTION_KEY_SETTING.getKey(), encryptionKey);
|
||||
Settings settings = Settings.builder().setSecureSettings(mockSecureSettings).build();
|
||||
CryptoService cryptoService = new CryptoService(settings);
|
||||
assertThat(new String(cryptoService.decrypt(((String) value).toCharArray())), is(EmailServer.PASSWORD));
|
||||
} else {
|
||||
assertThat(value, is(EmailServer.PASSWORD));
|
||||
|
|
|
@ -43,8 +43,8 @@ public class SecurityPluginTests extends SecurityIntegTestCase {
|
|||
logger.info("executing authorized request to /_xpack infos");
|
||||
Response response = getRestClient().performRequest("GET", "/_xpack",
|
||||
new BasicHeader(UsernamePasswordToken.BASIC_AUTH_HEADER,
|
||||
basicAuthHeaderValue(SecuritySettingsSource.DEFAULT_USER_NAME,
|
||||
new SecureString(SecuritySettingsSource.DEFAULT_PASSWORD.toCharArray()))));
|
||||
basicAuthHeaderValue(SecuritySettingsSource.TEST_USER_NAME,
|
||||
new SecureString(SecuritySettingsSource.TEST_PASSWORD.toCharArray()))));
|
||||
assertThat(response.getStatusLine().getStatusCode(), is(OK.getStatus()));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -5,15 +5,22 @@
|
|||
*/
|
||||
package org.elasticsearch.xpack.security;
|
||||
|
||||
import org.apache.http.HttpEntity;
|
||||
import org.apache.http.HttpHost;
|
||||
import org.apache.http.entity.ContentType;
|
||||
import org.apache.http.message.BasicHeader;
|
||||
import org.apache.http.nio.entity.NStringEntity;
|
||||
import org.elasticsearch.ElasticsearchSecurityException;
|
||||
import org.elasticsearch.action.admin.cluster.health.ClusterHealthResponse;
|
||||
import org.elasticsearch.client.Client;
|
||||
import org.elasticsearch.client.RestClient;
|
||||
import org.elasticsearch.client.RestClientBuilder;
|
||||
import org.elasticsearch.cluster.ClusterState;
|
||||
import org.elasticsearch.cluster.ClusterStateObserver;
|
||||
import org.elasticsearch.cluster.service.ClusterService;
|
||||
import org.elasticsearch.common.UUIDs;
|
||||
import org.elasticsearch.common.network.NetworkModule;
|
||||
import org.elasticsearch.common.settings.MockSecureSettings;
|
||||
import org.elasticsearch.common.settings.SecureSettings;
|
||||
import org.elasticsearch.common.settings.SecureString;
|
||||
import org.elasticsearch.common.settings.Settings;
|
||||
import org.elasticsearch.common.unit.TimeValue;
|
||||
|
@ -33,11 +40,14 @@ import org.elasticsearch.xpack.security.action.role.PutRoleResponse;
|
|||
import org.elasticsearch.xpack.security.action.user.PutUserResponse;
|
||||
import org.elasticsearch.xpack.security.authc.support.UsernamePasswordToken;
|
||||
import org.elasticsearch.xpack.security.client.SecurityClient;
|
||||
import org.elasticsearch.xpack.security.user.ElasticUser;
|
||||
import org.elasticsearch.xpack.security.support.IndexLifecycleManager;
|
||||
|
||||
import org.junit.After;
|
||||
import org.junit.AfterClass;
|
||||
import org.junit.BeforeClass;
|
||||
|
||||
import java.net.InetSocketAddress;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
|
@ -76,7 +86,16 @@ public class SecurityTribeIT extends NativeRealmIntegTestCase {
|
|||
super.setUp();
|
||||
if (cluster2 == null) {
|
||||
SecuritySettingsSource cluster2SettingsSource =
|
||||
new SecuritySettingsSource(defaultMaxNumberOfNodes(), useGeneratedSSL, createTempDir(), Scope.SUITE);
|
||||
new SecuritySettingsSource(defaultMaxNumberOfNodes(), useGeneratedSSL, createTempDir(), Scope.SUITE) {
|
||||
@Override
|
||||
public Settings nodeSettings(int nodeOrdinal) {
|
||||
return Settings.builder()
|
||||
.put(super.nodeSettings(nodeOrdinal))
|
||||
.put(NetworkModule.HTTP_ENABLED.getKey(), true)
|
||||
.build();
|
||||
}
|
||||
};
|
||||
|
||||
cluster2 = new InternalTestCluster(randomLong(), createTempDir(), true, true, 1, 2,
|
||||
UUIDs.randomBase64UUID(random()), cluster2SettingsSource, 0, false, SECOND_CLUSTER_NODE_PREFIX, getMockPlugins(),
|
||||
getClientWrapper());
|
||||
|
@ -85,6 +104,11 @@ public class SecurityTribeIT extends NativeRealmIntegTestCase {
|
|||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean shouldSetReservedUserPasswords() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean useGeneratedSSLConfig() {
|
||||
return useGeneratedSSL;
|
||||
|
@ -138,8 +162,17 @@ public class SecurityTribeIT extends NativeRealmIntegTestCase {
|
|||
|
||||
private void setupTribeNode(Settings settings) throws NodeValidationException, InterruptedException {
|
||||
SecuritySettingsSource cluster2SettingsSource =
|
||||
new SecuritySettingsSource(1, useGeneratedSSL, createTempDir(), Scope.TEST);
|
||||
Map<String,String> asMap = new HashMap<>(cluster2SettingsSource.nodeSettings(0).getAsMap());
|
||||
new SecuritySettingsSource(1, useGeneratedSSL, createTempDir(), Scope.TEST) {
|
||||
@Override
|
||||
public Settings nodeSettings(int nodeOrdinal) {
|
||||
return Settings.builder()
|
||||
.put(super.nodeSettings(nodeOrdinal))
|
||||
.put(NetworkModule.HTTP_ENABLED.getKey(), true)
|
||||
.build();
|
||||
}
|
||||
};
|
||||
|
||||
Map<String, String> asMap = new HashMap<>(cluster2SettingsSource.nodeSettings(0).getAsMap());
|
||||
asMap.remove(NodeEnvironment.MAX_LOCAL_STORAGE_NODES_SETTING.getKey());
|
||||
Settings.Builder tribe1Defaults = Settings.builder();
|
||||
Settings.Builder tribe2Defaults = Settings.builder();
|
||||
|
@ -216,9 +249,25 @@ public class SecurityTribeIT extends NativeRealmIntegTestCase {
|
|||
}
|
||||
|
||||
public void testThatTribeCanAuthenticateElasticUser() throws Exception {
|
||||
InetSocketAddress[] inetSocketAddresses = cluster2.httpAddresses();
|
||||
List<HttpHost> hosts = new ArrayList<>();
|
||||
for (InetSocketAddress address : inetSocketAddresses) {
|
||||
hosts.add(new HttpHost(address.getAddress(), address.getPort()));
|
||||
}
|
||||
RestClientBuilder builder = RestClient.builder(hosts.toArray(new HttpHost[hosts.size()]));
|
||||
RestClient client = builder.build();
|
||||
|
||||
String payload = "{\"password\": \"" + SecuritySettingsSource.TEST_PASSWORD + "\"}";
|
||||
HttpEntity entity = new NStringEntity(payload, ContentType.APPLICATION_JSON);
|
||||
BasicHeader authHeader = new BasicHeader(UsernamePasswordToken.BASIC_AUTH_HEADER,
|
||||
UsernamePasswordToken.basicAuthHeaderValue(ElasticUser.NAME, new SecureString("".toCharArray())));
|
||||
String route = "/_xpack/security/user/" + ElasticUser.NAME + "/_password";
|
||||
client.performRequest("PUT", route, Collections.emptyMap(), entity, authHeader);
|
||||
client.close();
|
||||
|
||||
setupTribeNode(Settings.EMPTY);
|
||||
ClusterHealthResponse response = tribeClient.filterWithHeader(Collections.singletonMap("Authorization",
|
||||
UsernamePasswordToken.basicAuthHeaderValue("elastic", new SecureString("changeme".toCharArray()))))
|
||||
UsernamePasswordToken.basicAuthHeaderValue("elastic", SecuritySettingsSource.TEST_PASSWORD_SECURE_STRING)))
|
||||
.admin().cluster().prepareHealth().get();
|
||||
assertNoTimeout(response);
|
||||
}
|
||||
|
@ -308,7 +357,7 @@ public class SecurityTribeIT extends NativeRealmIntegTestCase {
|
|||
PutUserResponse response =
|
||||
securityClient(nonPreferredClient).preparePutUser(username, "password".toCharArray(), "superuser").get();
|
||||
assertTrue(response.created());
|
||||
shouldBeSuccessfulUsers.add(username);
|
||||
shouldBeSuccessfulUsers.add(username);
|
||||
}
|
||||
|
||||
assertTribeNodeHasAllIndices();
|
||||
|
|
|
@ -9,8 +9,8 @@ import org.elasticsearch.ElasticsearchSecurityException;
|
|||
import org.elasticsearch.action.ActionListener;
|
||||
import org.elasticsearch.action.support.ActionFilters;
|
||||
import org.elasticsearch.cluster.metadata.IndexNameExpressionResolver;
|
||||
import org.elasticsearch.common.settings.SecureString;
|
||||
import org.elasticsearch.common.settings.Settings;
|
||||
import org.elasticsearch.test.SecuritySettingsSource;
|
||||
import org.elasticsearch.xpack.security.authc.esnative.NativeUsersStore;
|
||||
import org.elasticsearch.xpack.security.authc.support.Hasher;
|
||||
import org.elasticsearch.xpack.security.user.AnonymousUser;
|
||||
|
@ -54,7 +54,7 @@ public class TransportChangePasswordActionTests extends ESTestCase {
|
|||
|
||||
ChangePasswordRequest request = new ChangePasswordRequest();
|
||||
request.username(anonymousUser.principal());
|
||||
request.passwordHash(Hasher.BCRYPT.hash(new SecureString("changeme".toCharArray())));
|
||||
request.passwordHash(Hasher.BCRYPT.hash(SecuritySettingsSource.TEST_PASSWORD_SECURE_STRING));
|
||||
|
||||
final AtomicReference<Throwable> throwableRef = new AtomicReference<>();
|
||||
final AtomicReference<ChangePasswordResponse> responseRef = new AtomicReference<>();
|
||||
|
@ -85,7 +85,7 @@ public class TransportChangePasswordActionTests extends ESTestCase {
|
|||
|
||||
ChangePasswordRequest request = new ChangePasswordRequest();
|
||||
request.username(randomFrom(SystemUser.INSTANCE.principal(), XPackUser.INSTANCE.principal()));
|
||||
request.passwordHash(Hasher.BCRYPT.hash(new SecureString("changeme".toCharArray())));
|
||||
request.passwordHash(Hasher.BCRYPT.hash(SecuritySettingsSource.TEST_PASSWORD_SECURE_STRING));
|
||||
|
||||
final AtomicReference<Throwable> throwableRef = new AtomicReference<>();
|
||||
final AtomicReference<ChangePasswordResponse> responseRef = new AtomicReference<>();
|
||||
|
@ -112,15 +112,13 @@ public class TransportChangePasswordActionTests extends ESTestCase {
|
|||
NativeUsersStore usersStore = mock(NativeUsersStore.class);
|
||||
ChangePasswordRequest request = new ChangePasswordRequest();
|
||||
request.username(user.principal());
|
||||
request.passwordHash(Hasher.BCRYPT.hash(new SecureString("changeme".toCharArray())));
|
||||
doAnswer(new Answer() {
|
||||
public Void answer(InvocationOnMock invocation) {
|
||||
Object[] args = invocation.getArguments();
|
||||
assert args.length == 2;
|
||||
ActionListener<Void> listener = (ActionListener<Void>) args[1];
|
||||
listener.onResponse(null);
|
||||
return null;
|
||||
}
|
||||
request.passwordHash(Hasher.BCRYPT.hash(SecuritySettingsSource.TEST_PASSWORD_SECURE_STRING));
|
||||
doAnswer(invocation -> {
|
||||
Object[] args = invocation.getArguments();
|
||||
assert args.length == 2;
|
||||
ActionListener<Void> listener = (ActionListener<Void>) args[1];
|
||||
listener.onResponse(null);
|
||||
return null;
|
||||
}).when(usersStore).changePassword(eq(request), any(ActionListener.class));
|
||||
TransportService transportService = new TransportService(Settings.EMPTY, null, null, TransportService.NOOP_TRANSPORT_INTERCEPTOR,
|
||||
x -> null, null);
|
||||
|
@ -152,7 +150,7 @@ public class TransportChangePasswordActionTests extends ESTestCase {
|
|||
NativeUsersStore usersStore = mock(NativeUsersStore.class);
|
||||
ChangePasswordRequest request = new ChangePasswordRequest();
|
||||
request.username(user.principal());
|
||||
request.passwordHash(Hasher.BCRYPT.hash(new SecureString("changeme".toCharArray())));
|
||||
request.passwordHash(Hasher.BCRYPT.hash(SecuritySettingsSource.TEST_PASSWORD_SECURE_STRING));
|
||||
final Exception e = randomFrom(new ElasticsearchSecurityException(""), new IllegalStateException(), new RuntimeException());
|
||||
doAnswer(new Answer() {
|
||||
public Void answer(InvocationOnMock invocation) {
|
||||
|
|
|
@ -20,6 +20,7 @@ import org.elasticsearch.xpack.security.authc.esnative.NativeUsersStore;
|
|||
import org.elasticsearch.xpack.security.authc.esnative.ReservedRealm;
|
||||
import org.elasticsearch.xpack.security.authc.esnative.ReservedRealmTests;
|
||||
import org.elasticsearch.xpack.security.user.AnonymousUser;
|
||||
import org.elasticsearch.xpack.security.user.ElasticUser;
|
||||
import org.elasticsearch.xpack.security.user.SystemUser;
|
||||
import org.elasticsearch.xpack.security.user.User;
|
||||
import org.elasticsearch.test.ESTestCase;
|
||||
|
@ -180,9 +181,11 @@ public class TransportGetUsersActionTests extends ESTestCase {
|
|||
}
|
||||
});
|
||||
|
||||
User[] users = responseRef.get().users();
|
||||
|
||||
assertThat(throwableRef.get(), is(nullValue()));
|
||||
assertThat(responseRef.get(), is(notNullValue()));
|
||||
assertThat(responseRef.get().users(), arrayContaining(reservedUsers.toArray(new User[reservedUsers.size()])));
|
||||
assertThat(users, arrayContaining(reservedUsers.toArray(new User[reservedUsers.size()])));
|
||||
}
|
||||
|
||||
public void testGetAllUsers() {
|
||||
|
|
|
@ -11,10 +11,10 @@ import org.elasticsearch.action.support.ActionFilters;
|
|||
import org.elasticsearch.action.support.PlainActionFuture;
|
||||
import org.elasticsearch.cluster.metadata.IndexNameExpressionResolver;
|
||||
import org.elasticsearch.common.ValidationException;
|
||||
import org.elasticsearch.common.settings.SecureString;
|
||||
import org.elasticsearch.common.settings.Settings;
|
||||
import org.elasticsearch.common.util.concurrent.ThreadContext;
|
||||
import org.elasticsearch.env.Environment;
|
||||
import org.elasticsearch.test.SecuritySettingsSource;
|
||||
import org.elasticsearch.xpack.security.SecurityLifecycleService;
|
||||
import org.elasticsearch.xpack.security.authc.esnative.NativeUsersStore;
|
||||
import org.elasticsearch.xpack.security.authc.esnative.ReservedRealm;
|
||||
|
@ -163,7 +163,7 @@ public class TransportPutUserActionTests extends ESTestCase {
|
|||
final PutUserRequest request = new PutUserRequest();
|
||||
request.username(user.principal());
|
||||
if (isCreate) {
|
||||
request.passwordHash(Hasher.BCRYPT.hash(new SecureString("changeme".toCharArray())));
|
||||
request.passwordHash(Hasher.BCRYPT.hash(SecuritySettingsSource.TEST_PASSWORD_SECURE_STRING));
|
||||
}
|
||||
final boolean created = isCreate ? randomBoolean() : false; // updates should always return false for create
|
||||
doAnswer(new Answer() {
|
||||
|
|
|
@ -15,8 +15,6 @@ import java.util.concurrent.atomic.AtomicReference;
|
|||
import org.apache.http.message.BasicHeader;
|
||||
import org.elasticsearch.action.ActionFuture;
|
||||
import org.elasticsearch.action.admin.indices.exists.indices.IndicesExistsResponse;
|
||||
import org.elasticsearch.action.admin.indices.recovery.RecoveryAction;
|
||||
import org.elasticsearch.action.admin.indices.recovery.RecoveryRequestBuilder;
|
||||
import org.elasticsearch.action.search.SearchRequest;
|
||||
import org.elasticsearch.action.support.PlainActionFuture;
|
||||
import org.elasticsearch.client.Client;
|
||||
|
@ -24,7 +22,6 @@ import org.elasticsearch.client.Requests;
|
|||
import org.elasticsearch.client.ResponseException;
|
||||
import org.elasticsearch.common.network.NetworkModule;
|
||||
import org.elasticsearch.common.settings.Settings;
|
||||
import org.elasticsearch.common.unit.TimeValue;
|
||||
import org.elasticsearch.index.query.QueryBuilders;
|
||||
import org.elasticsearch.search.SearchHit;
|
||||
import org.elasticsearch.test.SecurityIntegTestCase;
|
||||
|
@ -37,7 +34,7 @@ import org.elasticsearch.xpack.security.authc.support.UsernamePasswordToken;
|
|||
import org.joda.time.DateTime;
|
||||
import org.joda.time.DateTimeZone;
|
||||
|
||||
import static org.elasticsearch.test.SecuritySettingsSource.DEFAULT_PASSWORD_SECURE_STRING;
|
||||
import static org.elasticsearch.test.SecuritySettingsSource.TEST_PASSWORD_SECURE_STRING;
|
||||
import static org.hamcrest.Matchers.arrayContaining;
|
||||
import static org.hamcrest.Matchers.containsInAnyOrder;
|
||||
import static org.hamcrest.Matchers.equalTo;
|
||||
|
@ -70,7 +67,7 @@ public class AuditTrailTests extends SecurityIntegTestCase {
|
|||
@Override
|
||||
public String configUsers() {
|
||||
return super.configUsers()
|
||||
+ AUTHENTICATE_USER + ":" + SecuritySettingsSource.DEFAULT_PASSWORD_HASHED + "\n"
|
||||
+ AUTHENTICATE_USER + ":" + SecuritySettingsSource.TEST_PASSWORD_HASHED + "\n"
|
||||
+ EXECUTE_USER + ":xx_no_password_xx\n";
|
||||
}
|
||||
|
||||
|
@ -90,7 +87,7 @@ public class AuditTrailTests extends SecurityIntegTestCase {
|
|||
try {
|
||||
getRestClient().performRequest("GET", "/.security/_search",
|
||||
new BasicHeader(UsernamePasswordToken.BASIC_AUTH_HEADER,
|
||||
UsernamePasswordToken.basicAuthHeaderValue(AUTHENTICATE_USER, DEFAULT_PASSWORD_SECURE_STRING)),
|
||||
UsernamePasswordToken.basicAuthHeaderValue(AUTHENTICATE_USER, TEST_PASSWORD_SECURE_STRING)),
|
||||
new BasicHeader(AuthenticationService.RUN_AS_USER_HEADER, EXECUTE_USER));
|
||||
fail("request should have failed");
|
||||
} catch (ResponseException e) {
|
||||
|
@ -112,7 +109,7 @@ public class AuditTrailTests extends SecurityIntegTestCase {
|
|||
try {
|
||||
getRestClient().performRequest("GET", "/.security/_search",
|
||||
new BasicHeader(UsernamePasswordToken.BASIC_AUTH_HEADER,
|
||||
UsernamePasswordToken.basicAuthHeaderValue(AUTHENTICATE_USER, DEFAULT_PASSWORD_SECURE_STRING)),
|
||||
UsernamePasswordToken.basicAuthHeaderValue(AUTHENTICATE_USER, TEST_PASSWORD_SECURE_STRING)),
|
||||
new BasicHeader(AuthenticationService.RUN_AS_USER_HEADER, ""));
|
||||
fail("request should have failed");
|
||||
} catch (ResponseException e) {
|
||||
|
|
|
@ -183,8 +183,8 @@ public class IndexAuditTrailTests extends SecurityIntegTestCase {
|
|||
Settings.Builder builder = Settings.builder()
|
||||
.put("xpack.security.audit.index.client." + XPackSettings.SECURITY_ENABLED.getKey(), useSecurity)
|
||||
.put(remoteSettings(NetworkAddress.format(inet.address().getAddress()), inet.address().getPort(), cluster2Name))
|
||||
.put("xpack.security.audit.index.client.xpack.security.user", SecuritySettingsSource.DEFAULT_USER_NAME + ":" +
|
||||
SecuritySettingsSource.DEFAULT_PASSWORD);
|
||||
.put("xpack.security.audit.index.client.xpack.security.user", SecuritySettingsSource.TEST_USER_NAME + ":" +
|
||||
SecuritySettingsSource.TEST_PASSWORD);
|
||||
|
||||
if (useGeneratedSSL == false) {
|
||||
cluster2SettingsSource.addClientSSLSettings(builder, "xpack.security.audit.index.client.");
|
||||
|
|
|
@ -101,7 +101,7 @@ public class RemoteIndexAuditTrailStartingTests extends SecurityIntegTestCase {
|
|||
.put("xpack.security.audit.outputs", randomFrom("index", "index,logfile"))
|
||||
.putArray("xpack.security.audit.index.client.hosts", addresses.toArray(new String[addresses.size()]))
|
||||
.put("xpack.security.audit.index.client.cluster.name", clusterName)
|
||||
.put("xpack.security.audit.index.client.xpack.security.user", DEFAULT_USER_NAME + ":" + DEFAULT_PASSWORD);
|
||||
.put("xpack.security.audit.index.client.xpack.security.user", TEST_USER_NAME + ":" + TEST_PASSWORD);
|
||||
|
||||
addClientSSLSettings(builder, "xpack.security.audit.index.client.");
|
||||
return builder.build();
|
||||
|
|
|
@ -5,16 +5,6 @@
|
|||
*/
|
||||
package org.elasticsearch.xpack.security.authc;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.time.Clock;
|
||||
import java.util.Arrays;
|
||||
import java.util.Base64;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.CountDownLatch;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
|
||||
import org.apache.lucene.util.SetOnce;
|
||||
import org.elasticsearch.ElasticsearchException;
|
||||
import org.elasticsearch.ElasticsearchSecurityException;
|
||||
|
@ -24,11 +14,14 @@ import org.elasticsearch.action.get.GetRequest;
|
|||
import org.elasticsearch.action.get.GetResponse;
|
||||
import org.elasticsearch.action.support.PlainActionFuture;
|
||||
import org.elasticsearch.client.Client;
|
||||
import org.elasticsearch.common.SuppressForbidden;
|
||||
import org.elasticsearch.common.io.stream.BytesStreamOutput;
|
||||
import org.elasticsearch.common.io.stream.StreamInput;
|
||||
import org.elasticsearch.common.settings.SecureString;
|
||||
import org.elasticsearch.common.settings.Settings;
|
||||
import org.elasticsearch.common.transport.TransportAddress;
|
||||
import org.elasticsearch.common.util.concurrent.ThreadContext;
|
||||
import org.elasticsearch.common.xcontent.NamedXContentRegistry;
|
||||
import org.elasticsearch.env.Environment;
|
||||
import org.elasticsearch.license.XPackLicenseState;
|
||||
import org.elasticsearch.rest.RestRequest;
|
||||
|
@ -53,6 +46,18 @@ import org.elasticsearch.xpack.security.user.User;
|
|||
import org.junit.After;
|
||||
import org.junit.Before;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.InetAddress;
|
||||
import java.net.InetSocketAddress;
|
||||
import java.time.Clock;
|
||||
import java.util.Arrays;
|
||||
import java.util.Base64;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.CountDownLatch;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
|
||||
import static org.elasticsearch.test.SecurityTestsUtils.assertAuthenticationException;
|
||||
import static org.elasticsearch.xpack.security.support.Exceptions.authenticationError;
|
||||
import static org.hamcrest.Matchers.arrayContaining;
|
||||
|
@ -93,12 +98,16 @@ public class AuthenticationServiceTests extends ESTestCase {
|
|||
private TokenService tokenService;
|
||||
private SecurityLifecycleService lifecycleService;
|
||||
private Client client;
|
||||
private InetSocketAddress remoteAddress;
|
||||
|
||||
@Before
|
||||
@SuppressForbidden(reason = "Allow accessing localhost")
|
||||
public void init() throws Exception {
|
||||
token = mock(AuthenticationToken.class);
|
||||
message = new InternalMessage();
|
||||
restRequest = new FakeRestRequest();
|
||||
remoteAddress = new InetSocketAddress(InetAddress.getLocalHost(), 100);
|
||||
message.remoteAddress(new TransportAddress(remoteAddress));
|
||||
restRequest = new FakeRestRequest.Builder(NamedXContentRegistry.EMPTY).withRemoteAddress(remoteAddress).build();
|
||||
threadContext = new ThreadContext(Settings.EMPTY);
|
||||
|
||||
firstRealm = mock(Realm.class);
|
||||
|
@ -206,7 +215,7 @@ public class AuthenticationServiceTests extends ESTestCase {
|
|||
}, this::logAndFail));
|
||||
verify(auditTrail).authenticationSuccess(secondRealm.name(), user, "_action", message);
|
||||
verifyNoMoreInteractions(auditTrail);
|
||||
verify(firstRealm, never()).authenticate(eq(token), any(ActionListener.class));
|
||||
verify(firstRealm, never()).authenticate(eq(token), any(ActionListener.class), any(IncomingRequest.class));
|
||||
assertTrue(completed.get());
|
||||
}
|
||||
|
||||
|
@ -562,7 +571,7 @@ public class AuthenticationServiceTests extends ESTestCase {
|
|||
when(secondRealm.token(threadContext)).thenReturn(token);
|
||||
when(secondRealm.supports(token)).thenReturn(true);
|
||||
doThrow(authenticationError("realm doesn't like authenticate"))
|
||||
.when(secondRealm).authenticate(eq(token), any(ActionListener.class));
|
||||
.when(secondRealm).authenticate(eq(token), any(ActionListener.class), any(IncomingRequest.class));
|
||||
try {
|
||||
authenticateBlocking("_action", message, null);
|
||||
fail("exception should bubble out");
|
||||
|
@ -577,7 +586,7 @@ public class AuthenticationServiceTests extends ESTestCase {
|
|||
when(secondRealm.token(threadContext)).thenReturn(token);
|
||||
when(secondRealm.supports(token)).thenReturn(true);
|
||||
doThrow(authenticationError("realm doesn't like authenticate"))
|
||||
.when(secondRealm).authenticate(eq(token), any(ActionListener.class));
|
||||
.when(secondRealm).authenticate(eq(token), any(ActionListener.class), any(IncomingRequest.class));
|
||||
try {
|
||||
authenticateBlocking(restRequest);
|
||||
fail("exception should bubble out");
|
||||
|
@ -869,7 +878,7 @@ public class AuthenticationServiceTests extends ESTestCase {
|
|||
ActionListener listener = (ActionListener) i.getArguments()[1];
|
||||
listener.onResponse(user);
|
||||
return null;
|
||||
}).when(realm).authenticate(eq(token), any(ActionListener.class));
|
||||
}).when(realm).authenticate(eq(token), any(ActionListener.class), any(IncomingRequest.class));
|
||||
}
|
||||
|
||||
private Authentication authenticateBlocking(RestRequest restRequest) {
|
||||
|
|
|
@ -436,7 +436,7 @@ public class RealmsTests extends ESTestCase {
|
|||
}
|
||||
|
||||
@Override
|
||||
public void authenticate(AuthenticationToken token, ActionListener<User> listener) {
|
||||
public void authenticate(AuthenticationToken token, ActionListener<User> listener, IncomingRequest incomingRequest) {
|
||||
listener.onResponse(null);
|
||||
}
|
||||
|
||||
|
|
|
@ -29,7 +29,7 @@ import java.util.HashMap;
|
|||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import static org.elasticsearch.test.SecuritySettingsSource.DEFAULT_PASSWORD_SECURE_STRING;
|
||||
import static org.elasticsearch.test.SecuritySettingsSource.TEST_PASSWORD_SECURE_STRING;
|
||||
import static org.hamcrest.Matchers.containsString;
|
||||
import static org.hamcrest.Matchers.greaterThan;
|
||||
import static org.hamcrest.Matchers.is;
|
||||
|
@ -40,7 +40,7 @@ public class RunAsIntegTests extends SecurityIntegTestCase {
|
|||
private static final String TRANSPORT_CLIENT_USER = "transport_user";
|
||||
private static final String ROLES =
|
||||
"run_as_role:\n" +
|
||||
" run_as: [ '" + SecuritySettingsSource.DEFAULT_USER_NAME + "', 'idontexist' ]\n";
|
||||
" run_as: [ '" + SecuritySettingsSource.TEST_USER_NAME + "', 'idontexist' ]\n";
|
||||
|
||||
// indicates whether the RUN_AS_USER that is being authenticated is also a superuser
|
||||
private static boolean runAsHasSuperUserRole;
|
||||
|
@ -66,8 +66,8 @@ public class RunAsIntegTests extends SecurityIntegTestCase {
|
|||
@Override
|
||||
public String configUsers() {
|
||||
return super.configUsers()
|
||||
+ RUN_AS_USER + ":" + SecuritySettingsSource.DEFAULT_PASSWORD_HASHED + "\n"
|
||||
+ TRANSPORT_CLIENT_USER + ":" + SecuritySettingsSource.DEFAULT_PASSWORD_HASHED + "\n";
|
||||
+ RUN_AS_USER + ":" + SecuritySettingsSource.TEST_PASSWORD_HASHED + "\n"
|
||||
+ TRANSPORT_CLIENT_USER + ":" + SecuritySettingsSource.TEST_PASSWORD_HASHED + "\n";
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -89,7 +89,7 @@ public class RunAsIntegTests extends SecurityIntegTestCase {
|
|||
|
||||
public void testUserImpersonation() throws Exception {
|
||||
try (TransportClient client = getTransportClient(Settings.builder()
|
||||
.put(Security.USER_SETTING.getKey(), TRANSPORT_CLIENT_USER + ":" + SecuritySettingsSource.DEFAULT_PASSWORD).build())) {
|
||||
.put(Security.USER_SETTING.getKey(), TRANSPORT_CLIENT_USER + ":" + SecuritySettingsSource.TEST_PASSWORD).build())) {
|
||||
//ensure the client can connect
|
||||
assertBusy(() -> assertThat(client.connectedNodes().size(), greaterThan(0)));
|
||||
|
||||
|
@ -104,7 +104,7 @@ public class RunAsIntegTests extends SecurityIntegTestCase {
|
|||
// let's run as without authorization
|
||||
try {
|
||||
Map<String, String> headers = Collections.singletonMap(AuthenticationService.RUN_AS_USER_HEADER,
|
||||
SecuritySettingsSource.DEFAULT_USER_NAME);
|
||||
SecuritySettingsSource.TEST_USER_NAME);
|
||||
client.filterWithHeader(headers)
|
||||
.admin().cluster().prepareHealth().get();
|
||||
fail("run as should be unauthorized for the transport client user");
|
||||
|
@ -115,8 +115,8 @@ public class RunAsIntegTests extends SecurityIntegTestCase {
|
|||
|
||||
Map<String, String> headers = new HashMap<>();
|
||||
headers.put("Authorization", UsernamePasswordToken.basicAuthHeaderValue(RUN_AS_USER,
|
||||
new SecureString(SecuritySettingsSource.DEFAULT_PASSWORD.toCharArray())));
|
||||
headers.put(AuthenticationService.RUN_AS_USER_HEADER, SecuritySettingsSource.DEFAULT_USER_NAME);
|
||||
new SecureString(SecuritySettingsSource.TEST_PASSWORD.toCharArray())));
|
||||
headers.put(AuthenticationService.RUN_AS_USER_HEADER, SecuritySettingsSource.TEST_USER_NAME);
|
||||
// lets set the user
|
||||
ClusterHealthResponse response = client.filterWithHeader(headers).admin().cluster().prepareHealth().get();
|
||||
assertThat(response.isTimedOut(), is(false));
|
||||
|
@ -129,8 +129,8 @@ public class RunAsIntegTests extends SecurityIntegTestCase {
|
|||
getRestClient().performRequest("GET", "/_nodes",
|
||||
new BasicHeader(UsernamePasswordToken.BASIC_AUTH_HEADER,
|
||||
UsernamePasswordToken.basicAuthHeaderValue(TRANSPORT_CLIENT_USER,
|
||||
DEFAULT_PASSWORD_SECURE_STRING)),
|
||||
new BasicHeader(AuthenticationService.RUN_AS_USER_HEADER, SecuritySettingsSource.DEFAULT_USER_NAME));
|
||||
TEST_PASSWORD_SECURE_STRING)),
|
||||
new BasicHeader(AuthenticationService.RUN_AS_USER_HEADER, SecuritySettingsSource.TEST_USER_NAME));
|
||||
fail("request should have failed");
|
||||
} catch(ResponseException e) {
|
||||
assertThat(e.getResponse().getStatusLine().getStatusCode(), is(403));
|
||||
|
@ -142,7 +142,7 @@ public class RunAsIntegTests extends SecurityIntegTestCase {
|
|||
getRestClient().performRequest("GET", "/_nodes",
|
||||
new BasicHeader(UsernamePasswordToken.BASIC_AUTH_HEADER,
|
||||
UsernamePasswordToken.basicAuthHeaderValue(RUN_AS_USER,
|
||||
DEFAULT_PASSWORD_SECURE_STRING)));
|
||||
TEST_PASSWORD_SECURE_STRING)));
|
||||
fail("request should have failed");
|
||||
} catch (ResponseException e) {
|
||||
assertThat(e.getResponse().getStatusLine().getStatusCode(), is(403));
|
||||
|
@ -153,14 +153,14 @@ public class RunAsIntegTests extends SecurityIntegTestCase {
|
|||
Response response = getRestClient().performRequest("GET", "/_nodes",
|
||||
new BasicHeader(UsernamePasswordToken.BASIC_AUTH_HEADER,
|
||||
UsernamePasswordToken.basicAuthHeaderValue(RUN_AS_USER,
|
||||
DEFAULT_PASSWORD_SECURE_STRING)),
|
||||
new BasicHeader(AuthenticationService.RUN_AS_USER_HEADER, SecuritySettingsSource.DEFAULT_USER_NAME));
|
||||
TEST_PASSWORD_SECURE_STRING)),
|
||||
new BasicHeader(AuthenticationService.RUN_AS_USER_HEADER, SecuritySettingsSource.TEST_USER_NAME));
|
||||
assertThat(response.getStatusLine().getStatusCode(), is(200));
|
||||
}
|
||||
|
||||
public void testEmptyUserImpersonationHeader() throws Exception {
|
||||
try (TransportClient client = getTransportClient(Settings.builder()
|
||||
.put(Security.USER_SETTING.getKey(), TRANSPORT_CLIENT_USER + ":" + SecuritySettingsSource.DEFAULT_PASSWORD).build())) {
|
||||
.put(Security.USER_SETTING.getKey(), TRANSPORT_CLIENT_USER + ":" + SecuritySettingsSource.TEST_PASSWORD).build())) {
|
||||
//ensure the client can connect
|
||||
awaitBusy(() -> {
|
||||
return client.connectedNodes().size() > 0;
|
||||
|
@ -169,7 +169,7 @@ public class RunAsIntegTests extends SecurityIntegTestCase {
|
|||
try {
|
||||
Map<String, String> headers = new HashMap<>();
|
||||
headers.put("Authorization", UsernamePasswordToken.basicAuthHeaderValue(RUN_AS_USER,
|
||||
new SecureString(SecuritySettingsSource.DEFAULT_PASSWORD.toCharArray())));
|
||||
new SecureString(SecuritySettingsSource.TEST_PASSWORD.toCharArray())));
|
||||
headers.put(AuthenticationService.RUN_AS_USER_HEADER, "");
|
||||
|
||||
client.filterWithHeader(headers).admin().cluster().prepareHealth().get();
|
||||
|
@ -185,7 +185,7 @@ public class RunAsIntegTests extends SecurityIntegTestCase {
|
|||
getRestClient().performRequest("GET", "/_nodes",
|
||||
new BasicHeader(UsernamePasswordToken.BASIC_AUTH_HEADER,
|
||||
UsernamePasswordToken.basicAuthHeaderValue(RUN_AS_USER,
|
||||
DEFAULT_PASSWORD_SECURE_STRING)),
|
||||
TEST_PASSWORD_SECURE_STRING)),
|
||||
new BasicHeader(AuthenticationService.RUN_AS_USER_HEADER, ""));
|
||||
fail("request should have failed");
|
||||
} catch(ResponseException e) {
|
||||
|
@ -195,7 +195,7 @@ public class RunAsIntegTests extends SecurityIntegTestCase {
|
|||
|
||||
public void testNonExistentRunAsUser() throws Exception {
|
||||
try (TransportClient client = getTransportClient(Settings.builder()
|
||||
.put(Security.USER_SETTING.getKey(), TRANSPORT_CLIENT_USER + ":" + SecuritySettingsSource.DEFAULT_PASSWORD).build())) {
|
||||
.put(Security.USER_SETTING.getKey(), TRANSPORT_CLIENT_USER + ":" + SecuritySettingsSource.TEST_PASSWORD).build())) {
|
||||
//ensure the client can connect
|
||||
awaitBusy(() -> {
|
||||
return client.connectedNodes().size() > 0;
|
||||
|
@ -204,7 +204,7 @@ public class RunAsIntegTests extends SecurityIntegTestCase {
|
|||
try {
|
||||
Map<String, String> headers = new HashMap<>();
|
||||
headers.put("Authorization", UsernamePasswordToken.basicAuthHeaderValue(RUN_AS_USER,
|
||||
new SecureString(SecuritySettingsSource.DEFAULT_PASSWORD.toCharArray())));
|
||||
new SecureString(SecuritySettingsSource.TEST_PASSWORD.toCharArray())));
|
||||
headers.put(AuthenticationService.RUN_AS_USER_HEADER, "idontexist");
|
||||
|
||||
client.filterWithHeader(headers).admin().cluster().prepareHealth().get();
|
||||
|
@ -220,7 +220,7 @@ public class RunAsIntegTests extends SecurityIntegTestCase {
|
|||
getRestClient().performRequest("GET", "/_nodes",
|
||||
new BasicHeader(UsernamePasswordToken.BASIC_AUTH_HEADER,
|
||||
UsernamePasswordToken.basicAuthHeaderValue(RUN_AS_USER,
|
||||
DEFAULT_PASSWORD_SECURE_STRING)),
|
||||
TEST_PASSWORD_SECURE_STRING)),
|
||||
new BasicHeader(AuthenticationService.RUN_AS_USER_HEADER, "idontexist"));
|
||||
fail("request should have failed");
|
||||
} catch (ResponseException e) {
|
||||
|
|
|
@ -50,8 +50,8 @@ public class TokenAuthIntegTests extends SecurityIntegTestCase {
|
|||
SecurityClient securityClient = new SecurityClient(client);
|
||||
CreateTokenResponse response = securityClient.prepareCreateToken()
|
||||
.setGrantType("password")
|
||||
.setUsername(SecuritySettingsSource.DEFAULT_USER_NAME)
|
||||
.setPassword(new SecureString(SecuritySettingsSource.DEFAULT_PASSWORD.toCharArray()))
|
||||
.setUsername(SecuritySettingsSource.TEST_USER_NAME)
|
||||
.setPassword(new SecureString(SecuritySettingsSource.TEST_PASSWORD.toCharArray()))
|
||||
.get();
|
||||
Instant created = Instant.now();
|
||||
|
||||
|
@ -90,8 +90,8 @@ public class TokenAuthIntegTests extends SecurityIntegTestCase {
|
|||
public void testExpireMultipleTimes() throws Exception {
|
||||
CreateTokenResponse response = securityClient().prepareCreateToken()
|
||||
.setGrantType("password")
|
||||
.setUsername(SecuritySettingsSource.DEFAULT_USER_NAME)
|
||||
.setPassword(new SecureString(SecuritySettingsSource.DEFAULT_PASSWORD.toCharArray()))
|
||||
.setUsername(SecuritySettingsSource.TEST_USER_NAME)
|
||||
.setPassword(new SecureString(SecuritySettingsSource.TEST_PASSWORD.toCharArray()))
|
||||
.get();
|
||||
|
||||
InvalidateTokenResponse invalidateResponse = securityClient().prepareInvalidateToken(response.getTokenString()).get();
|
||||
|
|
|
@ -17,6 +17,7 @@ import org.elasticsearch.test.SecuritySettingsSource;
|
|||
import org.elasticsearch.xpack.security.SecurityLifecycleService;
|
||||
import org.elasticsearch.xpack.security.authc.support.CharArrays;
|
||||
import org.elasticsearch.xpack.security.client.SecurityClient;
|
||||
import org.junit.AfterClass;
|
||||
import org.junit.BeforeClass;
|
||||
|
||||
import java.nio.charset.StandardCharsets;
|
||||
|
@ -39,6 +40,11 @@ public class ESNativeMigrateToolTests extends NativeRealmIntegTestCase {
|
|||
useSSL = randomBoolean();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean shouldSetReservedUserPasswords() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Settings nodeSettings(int nodeOrdinal) {
|
||||
logger.info("--> use SSL? {}", useSSL);
|
||||
|
|
|
@ -15,6 +15,7 @@ import org.elasticsearch.cli.Terminal.Verbosity;
|
|||
import org.elasticsearch.common.Strings;
|
||||
import org.elasticsearch.common.settings.Settings;
|
||||
import org.elasticsearch.env.Environment;
|
||||
import org.elasticsearch.test.SecuritySettingsSource;
|
||||
import org.elasticsearch.xpack.security.authz.RoleDescriptor;
|
||||
|
||||
import java.io.FileNotFoundException;
|
||||
|
@ -104,9 +105,12 @@ public class ESNativeRealmMigrateToolTests extends CommandTestCase {
|
|||
Files.createDirectories(xpackConfDir);
|
||||
|
||||
ESNativeRealmMigrateTool.MigrateUserOrRoles muor = new ESNativeRealmMigrateTool.MigrateUserOrRoles();
|
||||
OptionSet options = muor.getParser().parse("-u", "elastic", "-p", "changeme", "-U", "http://localhost:9200");
|
||||
|
||||
OptionSet options = muor.getParser().parse("-u", "elastic", "-p", SecuritySettingsSource.TEST_PASSWORD,
|
||||
"-U", "http://localhost:9200");
|
||||
Settings settings = Settings.builder().put("path.home", homeDir).build();
|
||||
Environment environment = new Environment(settings, confDir);
|
||||
|
||||
MockTerminal mockTerminal = new MockTerminal();
|
||||
|
||||
FileNotFoundException fnfe = expectThrows(FileNotFoundException.class,
|
||||
|
|
|
@ -252,13 +252,13 @@ public class NativeRealmIntegTests extends NativeRealmIntegTestCase {
|
|||
public void testUpdatingUserAndAuthentication() throws Exception {
|
||||
SecurityClient c = securityClient();
|
||||
logger.error("--> creating user");
|
||||
c.preparePutUser("joe", "s3krit".toCharArray(), SecuritySettingsSource.DEFAULT_ROLE).get();
|
||||
c.preparePutUser("joe", "s3krit".toCharArray(), SecuritySettingsSource.TEST_ROLE).get();
|
||||
logger.error("--> waiting for .security index");
|
||||
ensureGreen(SecurityLifecycleService.SECURITY_INDEX_NAME);
|
||||
logger.info("--> retrieving user");
|
||||
GetUsersResponse resp = c.prepareGetUsers("joe").get();
|
||||
assertTrue("user should exist", resp.hasUsers());
|
||||
assertThat(resp.users()[0].roles(), arrayContaining(SecuritySettingsSource.DEFAULT_ROLE));
|
||||
assertThat(resp.users()[0].roles(), arrayContaining(SecuritySettingsSource.TEST_ROLE));
|
||||
|
||||
createIndex("idx");
|
||||
ensureGreen("idx");
|
||||
|
@ -269,7 +269,7 @@ public class NativeRealmIntegTests extends NativeRealmIntegTestCase {
|
|||
|
||||
assertEquals(searchResp.getHits().getTotalHits(), 1L);
|
||||
|
||||
c.preparePutUser("joe", "s3krit2".toCharArray(), SecuritySettingsSource.DEFAULT_ROLE).get();
|
||||
c.preparePutUser("joe", "s3krit2".toCharArray(), SecuritySettingsSource.TEST_ROLE).get();
|
||||
|
||||
try {
|
||||
client().filterWithHeader(Collections.singletonMap("Authorization", token)).prepareSearch("idx").get();
|
||||
|
@ -287,13 +287,13 @@ public class NativeRealmIntegTests extends NativeRealmIntegTestCase {
|
|||
public void testCreateDeleteAuthenticate() {
|
||||
SecurityClient c = securityClient();
|
||||
logger.error("--> creating user");
|
||||
c.preparePutUser("joe", "s3krit".toCharArray(), SecuritySettingsSource.DEFAULT_ROLE).get();
|
||||
c.preparePutUser("joe", "s3krit".toCharArray(), SecuritySettingsSource.TEST_ROLE).get();
|
||||
logger.error("--> waiting for .security index");
|
||||
ensureGreen(SecurityLifecycleService.SECURITY_INDEX_NAME);
|
||||
logger.info("--> retrieving user");
|
||||
GetUsersResponse resp = c.prepareGetUsers("joe").get();
|
||||
assertTrue("user should exist", resp.hasUsers());
|
||||
assertThat(resp.users()[0].roles(), arrayContaining(SecuritySettingsSource.DEFAULT_ROLE));
|
||||
assertThat(resp.users()[0].roles(), arrayContaining(SecuritySettingsSource.TEST_ROLE));
|
||||
|
||||
createIndex("idx");
|
||||
ensureGreen("idx");
|
||||
|
@ -417,9 +417,9 @@ public class NativeRealmIntegTests extends NativeRealmIntegTestCase {
|
|||
assertThat(client.prepareGetUsers("joes").get().hasUsers(), is(false));
|
||||
|
||||
// create joe with a password and verify the user works
|
||||
client.preparePutUser("joe", "changeme".toCharArray(), "admin_role").get();
|
||||
client.preparePutUser("joe", SecuritySettingsSource.TEST_PASSWORD.toCharArray(), "admin_role").get();
|
||||
assertThat(client.prepareGetUsers("joe").get().hasUsers(), is(true));
|
||||
final String token = basicAuthHeaderValue("joe", new SecureString("changeme".toCharArray()));
|
||||
final String token = basicAuthHeaderValue("joe", SecuritySettingsSource.TEST_PASSWORD_SECURE_STRING);
|
||||
ClusterHealthResponse response = client().filterWithHeader(Collections.singletonMap("Authorization", token)).admin().cluster()
|
||||
.prepareHealth().get();
|
||||
assertFalse(response.isTimedOut());
|
||||
|
@ -445,7 +445,8 @@ public class NativeRealmIntegTests extends NativeRealmIntegTestCase {
|
|||
}
|
||||
|
||||
// update the user with password and admin role again
|
||||
client.preparePutUser("joe", "changeme2".toCharArray(), "admin_role").fullName("Joe Smith").get();
|
||||
String secondPassword = SecuritySettingsSource.TEST_PASSWORD + "2";
|
||||
client.preparePutUser("joe", secondPassword.toCharArray(), "admin_role").fullName("Joe Smith").get();
|
||||
getUsersResponse = client.prepareGetUsers("joe").get();
|
||||
assertThat(getUsersResponse.hasUsers(), is(true));
|
||||
assertThat(getUsersResponse.users().length, is(1));
|
||||
|
@ -465,7 +466,7 @@ public class NativeRealmIntegTests extends NativeRealmIntegTestCase {
|
|||
response = client()
|
||||
.filterWithHeader(
|
||||
Collections.singletonMap("Authorization",
|
||||
basicAuthHeaderValue("joe", new SecureString("changeme2".toCharArray()))))
|
||||
basicAuthHeaderValue("joe", new SecureString(secondPassword.toCharArray()))))
|
||||
.admin().cluster().prepareHealth().get();
|
||||
assertFalse(response.isTimedOut());
|
||||
}
|
||||
|
@ -493,7 +494,7 @@ public class NativeRealmIntegTests extends NativeRealmIntegTestCase {
|
|||
|
||||
SecurityClient client = securityClient();
|
||||
if (randomBoolean()) {
|
||||
client.preparePutUser("joe", "s3krit".toCharArray(), SecuritySettingsSource.DEFAULT_ROLE).get();
|
||||
client.preparePutUser("joe", "s3krit".toCharArray(), SecuritySettingsSource.TEST_ROLE).get();
|
||||
} else {
|
||||
client.preparePutRole("read_role")
|
||||
.cluster("none")
|
||||
|
@ -512,7 +513,8 @@ public class NativeRealmIntegTests extends NativeRealmIntegTestCase {
|
|||
public void testOperationsOnReservedUsers() throws Exception {
|
||||
final String username = randomFrom(ElasticUser.NAME, KibanaUser.NAME);
|
||||
IllegalArgumentException exception = expectThrows(IllegalArgumentException.class,
|
||||
() -> securityClient().preparePutUser(username, randomBoolean() ? "changeme".toCharArray() : null, "admin").get());
|
||||
() -> securityClient().preparePutUser(username, randomBoolean() ? SecuritySettingsSource.TEST_PASSWORD.toCharArray()
|
||||
: null, "admin").get());
|
||||
assertThat(exception.getMessage(), containsString("Username [" + username + "] is reserved"));
|
||||
|
||||
exception = expectThrows(IllegalArgumentException.class,
|
||||
|
@ -551,7 +553,7 @@ public class NativeRealmIntegTests extends NativeRealmIntegTestCase {
|
|||
// authenticate should work
|
||||
AuthenticateResponse authenticateResponse = client()
|
||||
.filterWithHeader(Collections.singletonMap("Authorization",
|
||||
basicAuthHeaderValue(username, new SecureString("changeme".toCharArray()))))
|
||||
basicAuthHeaderValue(username, getReservedPassword())))
|
||||
.execute(AuthenticateAction.INSTANCE, new AuthenticateRequest(username))
|
||||
.get();
|
||||
assertThat(authenticateResponse.user().principal(), is(username));
|
||||
|
@ -574,7 +576,7 @@ public class NativeRealmIntegTests extends NativeRealmIntegTestCase {
|
|||
}
|
||||
|
||||
public void testCreateAndChangePassword() throws Exception {
|
||||
securityClient().preparePutUser("joe", "s3krit".toCharArray(), SecuritySettingsSource.DEFAULT_ROLE).get();
|
||||
securityClient().preparePutUser("joe", "s3krit".toCharArray(), SecuritySettingsSource.TEST_ROLE).get();
|
||||
final String token = basicAuthHeaderValue("joe", new SecureString("s3krit".toCharArray()));
|
||||
ClusterHealthResponse response = client().filterWithHeader(Collections.singletonMap("Authorization", token))
|
||||
.admin().cluster().prepareHealth().get();
|
||||
|
@ -582,7 +584,7 @@ public class NativeRealmIntegTests extends NativeRealmIntegTestCase {
|
|||
|
||||
ChangePasswordResponse passwordResponse = securityClient(
|
||||
client().filterWithHeader(Collections.singletonMap("Authorization", token)))
|
||||
.prepareChangePassword("joe", "changeme".toCharArray())
|
||||
.prepareChangePassword("joe", SecuritySettingsSource.TEST_PASSWORD.toCharArray())
|
||||
.get();
|
||||
assertThat(passwordResponse, notNullValue());
|
||||
|
||||
|
@ -594,7 +596,7 @@ public class NativeRealmIntegTests extends NativeRealmIntegTestCase {
|
|||
response = client()
|
||||
.filterWithHeader(
|
||||
Collections.singletonMap("Authorization",
|
||||
basicAuthHeaderValue("joe", new SecureString("changeme".toCharArray()))))
|
||||
basicAuthHeaderValue("joe", SecuritySettingsSource.TEST_PASSWORD_SECURE_STRING)))
|
||||
.admin().cluster().prepareHealth().get();
|
||||
assertThat(response.isTimedOut(), is(false));
|
||||
}
|
||||
|
@ -660,7 +662,7 @@ public class NativeRealmIntegTests extends NativeRealmIntegTestCase {
|
|||
}
|
||||
|
||||
public void testSetEnabled() throws Exception {
|
||||
securityClient().preparePutUser("joe", "s3krit".toCharArray(), SecuritySettingsSource.DEFAULT_ROLE).get();
|
||||
securityClient().preparePutUser("joe", "s3krit".toCharArray(), SecuritySettingsSource.TEST_ROLE).get();
|
||||
final String token = basicAuthHeaderValue("joe", new SecureString("s3krit".toCharArray()));
|
||||
ClusterHealthResponse response = client().filterWithHeader(Collections.singletonMap("Authorization", token))
|
||||
.admin().cluster().prepareHealth().get();
|
||||
|
@ -720,7 +722,7 @@ public class NativeRealmIntegTests extends NativeRealmIntegTestCase {
|
|||
* the loader returned a null value, while the other caller(s) would get a null value unexpectedly
|
||||
*/
|
||||
public void testConcurrentRunAs() throws Exception {
|
||||
securityClient().preparePutUser("joe", "s3krit".toCharArray(), SecuritySettingsSource.DEFAULT_ROLE).get();
|
||||
securityClient().preparePutUser("joe", "s3krit".toCharArray(), SecuritySettingsSource.TEST_ROLE).get();
|
||||
securityClient().preparePutUser("executor", "s3krit".toCharArray(), "superuser").get();
|
||||
final String token = basicAuthHeaderValue("executor", new SecureString("s3krit".toCharArray()));
|
||||
final Client client = client().filterWithHeader(MapBuilder.<String, String>newMapBuilder()
|
||||
|
|
|
@ -168,7 +168,7 @@ public class NativeRealmMigratorTests extends ESTestCase {
|
|||
this.reservedUsers = Collections.singletonMap(
|
||||
KibanaUser.NAME,
|
||||
MapBuilder.<String, Object>newMapBuilder()
|
||||
.put(User.Fields.PASSWORD.getPreferredName(), new String(Hasher.BCRYPT.hash(ReservedRealm.DEFAULT_PASSWORD_TEXT)))
|
||||
.put(User.Fields.PASSWORD.getPreferredName(), new String(Hasher.BCRYPT.hash(ReservedRealm.EMPTY_PASSWORD_TEXT)))
|
||||
.put(User.Fields.ENABLED.getPreferredName(), false)
|
||||
.immutableMap()
|
||||
);
|
||||
|
@ -181,7 +181,7 @@ public class NativeRealmMigratorTests extends ESTestCase {
|
|||
this.reservedUsers = Collections.singletonMap(
|
||||
KibanaUser.NAME,
|
||||
MapBuilder.<String, Object>newMapBuilder()
|
||||
.put(User.Fields.PASSWORD.getPreferredName(), new String(Hasher.BCRYPT.hash(ReservedRealm.DEFAULT_PASSWORD_TEXT)))
|
||||
.put(User.Fields.PASSWORD.getPreferredName(), new String(Hasher.BCRYPT.hash(ReservedRealm.EMPTY_PASSWORD_TEXT)))
|
||||
.put(User.Fields.ENABLED.getPreferredName(), false)
|
||||
.immutableMap()
|
||||
);
|
||||
|
@ -195,7 +195,7 @@ public class NativeRealmMigratorTests extends ESTestCase {
|
|||
.stream().collect(Collectors.toMap(Function.identity(),
|
||||
name -> MapBuilder.<String, Object>newMapBuilder()
|
||||
.put(User.Fields.PASSWORD.getPreferredName(),
|
||||
new String(Hasher.BCRYPT.hash(ReservedRealm.DEFAULT_PASSWORD_TEXT)))
|
||||
new String(Hasher.BCRYPT.hash(ReservedRealm.EMPTY_PASSWORD_TEXT)))
|
||||
.put(User.Fields.ENABLED.getPreferredName(), randomBoolean())
|
||||
.immutableMap()
|
||||
));
|
||||
|
|
|
@ -111,9 +111,9 @@ public class NativeUsersStoreTests extends ESTestCase {
|
|||
actionRespond(GetRequest.class, new GetResponse(result));
|
||||
|
||||
final NativeUsersStore.ReservedUserInfo userInfo = future.get();
|
||||
assertThat(userInfo.hasDefaultPassword, equalTo(true));
|
||||
assertThat(userInfo.hasEmptyPassword, equalTo(true));
|
||||
assertThat(userInfo.enabled, equalTo(true));
|
||||
assertThat(userInfo.passwordHash, equalTo(ReservedRealm.DEFAULT_PASSWORD_HASH));
|
||||
assertThat(userInfo.passwordHash, equalTo(ReservedRealm.EMPTY_PASSWORD_HASH));
|
||||
}
|
||||
|
||||
public void testInContainerTrueReturnsEmptyPasswordForNonElasticReservedUsers() throws Exception {
|
||||
|
@ -142,9 +142,9 @@ public class NativeUsersStoreTests extends ESTestCase {
|
|||
actionRespond(GetRequest.class, new GetResponse(result));
|
||||
|
||||
final NativeUsersStore.ReservedUserInfo userInfo = future.get();
|
||||
assertThat(userInfo.hasDefaultPassword, equalTo(true));
|
||||
assertThat(userInfo.hasEmptyPassword, equalTo(true));
|
||||
assertThat(userInfo.enabled, equalTo(true));
|
||||
assertThat(userInfo.passwordHash, equalTo(ReservedRealm.DEFAULT_PASSWORD_HASH));
|
||||
assertThat(userInfo.passwordHash, equalTo(ReservedRealm.EMPTY_PASSWORD_HASH));
|
||||
}
|
||||
|
||||
public void testInContainerTrueReturnsBootstrapPasswordForElastic() throws Exception {
|
||||
|
@ -171,7 +171,7 @@ public class NativeUsersStoreTests extends ESTestCase {
|
|||
actionRespond(GetRequest.class, new GetResponse(result));
|
||||
|
||||
final NativeUsersStore.ReservedUserInfo userInfo = future.get();
|
||||
assertThat(userInfo.hasDefaultPassword, equalTo(false));
|
||||
assertThat(userInfo.hasEmptyPassword, equalTo(false));
|
||||
assertThat(userInfo.enabled, equalTo(true));
|
||||
assertThat(userInfo.passwordHash, equalTo(passwordHash));
|
||||
}
|
||||
|
|
|
@ -8,11 +8,13 @@ package org.elasticsearch.xpack.security.authc.esnative;
|
|||
import org.elasticsearch.ElasticsearchSecurityException;
|
||||
import org.elasticsearch.action.admin.cluster.health.ClusterHealthResponse;
|
||||
import org.elasticsearch.common.settings.SecureString;
|
||||
import org.elasticsearch.test.NativeRealmIntegTestCase;
|
||||
import org.elasticsearch.xpack.security.action.user.ChangePasswordResponse;
|
||||
import org.elasticsearch.xpack.security.client.SecurityClient;
|
||||
import org.elasticsearch.xpack.security.user.BeatsSystemUser;
|
||||
import org.elasticsearch.xpack.security.user.ElasticUser;
|
||||
import org.elasticsearch.xpack.security.user.KibanaUser;
|
||||
import org.elasticsearch.xpack.security.action.user.ChangePasswordResponse;
|
||||
import org.elasticsearch.test.NativeRealmIntegTestCase;
|
||||
import org.elasticsearch.xpack.security.user.LogstashSystemUser;
|
||||
|
||||
import java.util.Arrays;
|
||||
|
||||
|
@ -27,12 +29,10 @@ import static org.hamcrest.Matchers.notNullValue;
|
|||
*/
|
||||
public class ReservedRealmIntegTests extends NativeRealmIntegTestCase {
|
||||
|
||||
private static final SecureString DEFAULT_PASSWORD = new SecureString("changeme".toCharArray());
|
||||
|
||||
public void testAuthenticate() {
|
||||
for (String username : Arrays.asList(ElasticUser.NAME, KibanaUser.NAME)) {
|
||||
for (String username : Arrays.asList(ElasticUser.NAME, KibanaUser.NAME, BeatsSystemUser.NAME, LogstashSystemUser.NAME)) {
|
||||
ClusterHealthResponse response = client()
|
||||
.filterWithHeader(singletonMap("Authorization", basicAuthHeaderValue(username, DEFAULT_PASSWORD)))
|
||||
.filterWithHeader(singletonMap("Authorization", basicAuthHeaderValue(username, getReservedPassword())))
|
||||
.admin()
|
||||
.cluster()
|
||||
.prepareHealth()
|
||||
|
@ -43,15 +43,15 @@ public class ReservedRealmIntegTests extends NativeRealmIntegTestCase {
|
|||
}
|
||||
|
||||
/**
|
||||
* Enabling a user forces a doc to be written to the security index, and "user doc with default password" has a special case code in
|
||||
* Enabling a user forces a doc to be written to the security index, and "user doc with empty password" has a special case code in
|
||||
* the reserved realm.
|
||||
*/
|
||||
public void testAuthenticateAfterEnablingUser() {
|
||||
final SecurityClient c = securityClient();
|
||||
for (String username : Arrays.asList(ElasticUser.NAME, KibanaUser.NAME)) {
|
||||
for (String username : Arrays.asList(ElasticUser.NAME, KibanaUser.NAME, BeatsSystemUser.NAME, LogstashSystemUser.NAME)) {
|
||||
c.prepareSetEnabled(username, true).get();
|
||||
ClusterHealthResponse response = client()
|
||||
.filterWithHeader(singletonMap("Authorization", basicAuthHeaderValue(username, DEFAULT_PASSWORD)))
|
||||
.filterWithHeader(singletonMap("Authorization", basicAuthHeaderValue(username, getReservedPassword())))
|
||||
.admin()
|
||||
.cluster()
|
||||
.prepareHealth()
|
||||
|
@ -62,12 +62,12 @@ public class ReservedRealmIntegTests extends NativeRealmIntegTestCase {
|
|||
}
|
||||
|
||||
public void testChangingPassword() {
|
||||
String username = randomFrom(ElasticUser.NAME, KibanaUser.NAME);
|
||||
String username = randomFrom(ElasticUser.NAME, KibanaUser.NAME, BeatsSystemUser.NAME, LogstashSystemUser.NAME);
|
||||
final char[] newPassword = "supersecretvalue".toCharArray();
|
||||
|
||||
if (randomBoolean()) {
|
||||
ClusterHealthResponse response = client()
|
||||
.filterWithHeader(singletonMap("Authorization", basicAuthHeaderValue(username, DEFAULT_PASSWORD)))
|
||||
.filterWithHeader(singletonMap("Authorization", basicAuthHeaderValue(username, getReservedPassword())))
|
||||
.admin()
|
||||
.cluster()
|
||||
.prepareHealth()
|
||||
|
@ -81,7 +81,7 @@ public class ReservedRealmIntegTests extends NativeRealmIntegTestCase {
|
|||
assertThat(response, notNullValue());
|
||||
|
||||
ElasticsearchSecurityException elasticsearchSecurityException = expectThrows(ElasticsearchSecurityException.class, () -> client()
|
||||
.filterWithHeader(singletonMap("Authorization", basicAuthHeaderValue(username, DEFAULT_PASSWORD)))
|
||||
.filterWithHeader(singletonMap("Authorization", basicAuthHeaderValue(username, getReservedPassword())))
|
||||
.admin()
|
||||
.cluster()
|
||||
.prepareHealth()
|
||||
|
@ -100,7 +100,7 @@ public class ReservedRealmIntegTests extends NativeRealmIntegTestCase {
|
|||
public void testDisablingUser() throws Exception {
|
||||
// validate the user works
|
||||
ClusterHealthResponse response = client()
|
||||
.filterWithHeader(singletonMap("Authorization", basicAuthHeaderValue(ElasticUser.NAME, DEFAULT_PASSWORD)))
|
||||
.filterWithHeader(singletonMap("Authorization", basicAuthHeaderValue(ElasticUser.NAME, getReservedPassword())))
|
||||
.admin()
|
||||
.cluster()
|
||||
.prepareHealth()
|
||||
|
@ -110,7 +110,7 @@ public class ReservedRealmIntegTests extends NativeRealmIntegTestCase {
|
|||
// disable user
|
||||
securityClient().prepareSetEnabled(ElasticUser.NAME, false).get();
|
||||
ElasticsearchSecurityException elasticsearchSecurityException = expectThrows(ElasticsearchSecurityException.class, () -> client()
|
||||
.filterWithHeader(singletonMap("Authorization", basicAuthHeaderValue(ElasticUser.NAME, DEFAULT_PASSWORD)))
|
||||
.filterWithHeader(singletonMap("Authorization", basicAuthHeaderValue(ElasticUser.NAME, getReservedPassword())))
|
||||
.admin()
|
||||
.cluster()
|
||||
.prepareHealth()
|
||||
|
@ -120,7 +120,7 @@ public class ReservedRealmIntegTests extends NativeRealmIntegTestCase {
|
|||
//enable
|
||||
securityClient().prepareSetEnabled(ElasticUser.NAME, true).get();
|
||||
response = client()
|
||||
.filterWithHeader(singletonMap("Authorization", basicAuthHeaderValue(ElasticUser.NAME, DEFAULT_PASSWORD)))
|
||||
.filterWithHeader(singletonMap("Authorization", basicAuthHeaderValue(ElasticUser.NAME, getReservedPassword())))
|
||||
.admin()
|
||||
.cluster()
|
||||
.prepareHealth()
|
||||
|
|
|
@ -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()));
|
||||
}
|
||||
}
|
|
@ -9,6 +9,7 @@ import org.elasticsearch.ElasticsearchSecurityException;
|
|||
import org.elasticsearch.Version;
|
||||
import org.elasticsearch.action.ActionListener;
|
||||
import org.elasticsearch.action.support.PlainActionFuture;
|
||||
import org.elasticsearch.common.SuppressForbidden;
|
||||
import org.elasticsearch.common.settings.SecureString;
|
||||
import org.elasticsearch.common.settings.Settings;
|
||||
import org.elasticsearch.common.util.concurrent.ThreadContext;
|
||||
|
@ -16,6 +17,7 @@ import org.elasticsearch.env.Environment;
|
|||
import org.elasticsearch.test.ESTestCase;
|
||||
import org.elasticsearch.xpack.XPackSettings;
|
||||
import org.elasticsearch.xpack.security.SecurityLifecycleService;
|
||||
import org.elasticsearch.xpack.security.authc.IncomingRequest;
|
||||
import org.elasticsearch.xpack.security.authc.esnative.NativeUsersStore.ReservedUserInfo;
|
||||
import org.elasticsearch.xpack.security.authc.support.Hasher;
|
||||
import org.elasticsearch.xpack.security.authc.support.UsernamePasswordToken;
|
||||
|
@ -28,6 +30,9 @@ import org.elasticsearch.xpack.security.user.User;
|
|||
import org.junit.Before;
|
||||
import org.mockito.ArgumentCaptor;
|
||||
|
||||
import java.net.InetAddress;
|
||||
import java.net.InetSocketAddress;
|
||||
import java.net.UnknownHostException;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.Map;
|
||||
|
@ -58,62 +63,38 @@ import static org.mockito.Mockito.when;
|
|||
*/
|
||||
public class ReservedRealmTests extends ESTestCase {
|
||||
|
||||
private static final SecureString DEFAULT_PASSWORD = new SecureString("changeme".toCharArray());
|
||||
private static final SecureString EMPTY_PASSWORD = new SecureString("".toCharArray());
|
||||
public static final String ACCEPT_DEFAULT_PASSWORDS = ReservedRealm.ACCEPT_DEFAULT_PASSWORD_SETTING.getKey();
|
||||
private NativeUsersStore usersStore;
|
||||
private SecurityLifecycleService securityLifecycleService;
|
||||
private IncomingRequest incomingRequest;
|
||||
|
||||
@Before
|
||||
public void setupMocks() throws Exception {
|
||||
usersStore = mock(NativeUsersStore.class);
|
||||
securityLifecycleService = mock(SecurityLifecycleService.class);
|
||||
incomingRequest = mock(IncomingRequest.class);
|
||||
when(securityLifecycleService.isSecurityIndexAvailable()).thenReturn(true);
|
||||
when(securityLifecycleService.checkSecurityMappingVersion(any())).thenReturn(true);
|
||||
mockGetAllReservedUserInfo(usersStore, Collections.emptyMap());
|
||||
}
|
||||
|
||||
public void testMappingVersionFromBeforeUserExisted() throws ExecutionException, InterruptedException {
|
||||
@SuppressForbidden(reason = "allow getting localhost")
|
||||
public void testMappingVersionFromBeforeUserExisted() throws ExecutionException, InterruptedException, UnknownHostException {
|
||||
when(securityLifecycleService.checkSecurityMappingVersion(any())).thenReturn(false);
|
||||
final ReservedRealm reservedRealm =
|
||||
new ReservedRealm(mock(Environment.class), Settings.EMPTY, usersStore,
|
||||
new AnonymousUser(Settings.EMPTY), securityLifecycleService, new ThreadContext(Settings.EMPTY));
|
||||
final String principal = randomFrom(ElasticUser.NAME, KibanaUser.NAME, LogstashSystemUser.NAME);
|
||||
final String principal = ElasticUser.NAME;
|
||||
|
||||
PlainActionFuture<User> future = new PlainActionFuture<>();
|
||||
reservedRealm.authenticate(new UsernamePasswordToken(principal, DEFAULT_PASSWORD), future);
|
||||
InetSocketAddress address = new InetSocketAddress(InetAddress.getLocalHost(), 100);
|
||||
when(incomingRequest.getRemoteAddress()).thenReturn(address);
|
||||
when(incomingRequest.getType()).thenReturn(IncomingRequest.RequestType.REST);
|
||||
reservedRealm.authenticate(new UsernamePasswordToken(principal, EMPTY_PASSWORD), future, incomingRequest);
|
||||
assertThat(future.get().enabled(), equalTo(false));
|
||||
}
|
||||
|
||||
public void testSuccessfulDefaultPasswordAuthentication() throws Throwable {
|
||||
final User expected = randomFrom(new ElasticUser(true), new KibanaUser(true), new LogstashSystemUser(true));
|
||||
final String principal = expected.principal();
|
||||
final boolean securityIndexExists = randomBoolean();
|
||||
if (securityIndexExists) {
|
||||
when(securityLifecycleService.isSecurityIndexExisting()).thenReturn(true);
|
||||
doAnswer((i) -> {
|
||||
ActionListener listener = (ActionListener) i.getArguments()[1];
|
||||
listener.onResponse(null);
|
||||
return null;
|
||||
}).when(usersStore).getReservedUserInfo(eq(principal), any(ActionListener.class));
|
||||
}
|
||||
final ReservedRealm reservedRealm =
|
||||
new ReservedRealm(mock(Environment.class), Settings.EMPTY, usersStore,
|
||||
new AnonymousUser(Settings.EMPTY), securityLifecycleService, new ThreadContext(Settings.EMPTY));
|
||||
|
||||
PlainActionFuture<User> listener = new PlainActionFuture<>();
|
||||
reservedRealm.doAuthenticate(new UsernamePasswordToken(principal, DEFAULT_PASSWORD), listener);
|
||||
final User authenticated = listener.actionGet();
|
||||
assertEquals(expected, authenticated);
|
||||
verify(securityLifecycleService).isSecurityIndexExisting();
|
||||
if (securityIndexExists) {
|
||||
verify(usersStore).getReservedUserInfo(eq(principal), any(ActionListener.class));
|
||||
}
|
||||
final ArgumentCaptor<Predicate> predicateCaptor = ArgumentCaptor.forClass(Predicate.class);
|
||||
verify(securityLifecycleService).checkSecurityMappingVersion(predicateCaptor.capture());
|
||||
verifyVersionPredicate(principal, predicateCaptor.getValue());
|
||||
verifyNoMoreInteractions(usersStore);
|
||||
}
|
||||
|
||||
public void testDisableDefaultPasswordAuthentication() throws Throwable {
|
||||
final User expected = randomFrom(new ElasticUser(true), new KibanaUser(true), new LogstashSystemUser(true));
|
||||
|
||||
|
@ -135,7 +116,51 @@ public class ReservedRealmTests extends ESTestCase {
|
|||
assertThat(e.getMessage(), containsString("failed to authenticate"));
|
||||
}
|
||||
};
|
||||
reservedRealm.doAuthenticate(new UsernamePasswordToken(expected.principal(), DEFAULT_PASSWORD), listener);
|
||||
reservedRealm.doAuthenticate(new UsernamePasswordToken(expected.principal(), EMPTY_PASSWORD), listener, incomingRequest);
|
||||
}
|
||||
|
||||
public void testElasticEmptyPasswordAuthenticationFailsFromNonLocalhost() throws Throwable {
|
||||
final User expected = new ElasticUser(true);
|
||||
final String principal = expected.principal();
|
||||
|
||||
Settings settings = Settings.builder().put(ACCEPT_DEFAULT_PASSWORDS, true).build();
|
||||
final ReservedRealm reservedRealm =
|
||||
new ReservedRealm(mock(Environment.class), settings, usersStore,
|
||||
new AnonymousUser(Settings.EMPTY), securityLifecycleService, new ThreadContext(Settings.EMPTY));
|
||||
|
||||
PlainActionFuture<User> listener = new PlainActionFuture<>();
|
||||
|
||||
InetSocketAddress address = new InetSocketAddress(InetAddress.getByName("128.9.8.1"), 100);
|
||||
|
||||
when(incomingRequest.getRemoteAddress()).thenReturn(address);
|
||||
reservedRealm.doAuthenticate(new UsernamePasswordToken(principal, EMPTY_PASSWORD), listener, incomingRequest);
|
||||
|
||||
ElasticsearchSecurityException actual = expectThrows(ElasticsearchSecurityException.class, listener::actionGet);
|
||||
assertThat(actual.getMessage(), containsString("failed to authenticate user [" + principal));
|
||||
}
|
||||
|
||||
@SuppressForbidden(reason = "allow getting localhost")
|
||||
public void testElasticEmptyPasswordAuthenticationSucceedsInSetupModeIfRestRequestComesFromLocalhost() throws Throwable {
|
||||
final User expected = new ElasticUser(true, true);
|
||||
final String principal = expected.principal();
|
||||
|
||||
Settings settings = Settings.builder().put(ACCEPT_DEFAULT_PASSWORDS, true).build();
|
||||
final ReservedRealm reservedRealm =
|
||||
new ReservedRealm(mock(Environment.class), settings, usersStore,
|
||||
new AnonymousUser(Settings.EMPTY), securityLifecycleService, new ThreadContext(Settings.EMPTY));
|
||||
|
||||
PlainActionFuture<User> listener = new PlainActionFuture<>();
|
||||
|
||||
InetSocketAddress address = new InetSocketAddress(InetAddress.getLocalHost(), 100);
|
||||
|
||||
when(incomingRequest.getRemoteAddress()).thenReturn(address);
|
||||
when(incomingRequest.getType()).thenReturn(IncomingRequest.RequestType.REST);
|
||||
reservedRealm.doAuthenticate(new UsernamePasswordToken(principal, EMPTY_PASSWORD), listener, incomingRequest);
|
||||
|
||||
User user = listener.actionGet();
|
||||
|
||||
assertEquals(expected, user);
|
||||
assertNotEquals(new ElasticUser(true, false), user);
|
||||
}
|
||||
|
||||
public void testAuthenticationDisabled() throws Throwable {
|
||||
|
@ -151,7 +176,7 @@ public class ReservedRealmTests extends ESTestCase {
|
|||
final String principal = expected.principal();
|
||||
|
||||
PlainActionFuture<User> listener = new PlainActionFuture<>();
|
||||
reservedRealm.doAuthenticate(new UsernamePasswordToken(principal, DEFAULT_PASSWORD), listener);
|
||||
reservedRealm.doAuthenticate(new UsernamePasswordToken(principal, EMPTY_PASSWORD), listener, mock(IncomingRequest.class));
|
||||
final User authenticated = listener.actionGet();
|
||||
assertNull(authenticated);
|
||||
verifyZeroInteractions(usersStore);
|
||||
|
@ -179,9 +204,9 @@ public class ReservedRealmTests extends ESTestCase {
|
|||
return null;
|
||||
}).when(usersStore).getReservedUserInfo(eq(principal), any(ActionListener.class));
|
||||
|
||||
// test default password
|
||||
// test empty password
|
||||
final PlainActionFuture<User> listener = new PlainActionFuture<>();
|
||||
reservedRealm.doAuthenticate(new UsernamePasswordToken(principal, DEFAULT_PASSWORD), listener);
|
||||
reservedRealm.doAuthenticate(new UsernamePasswordToken(principal, EMPTY_PASSWORD), listener, incomingRequest);
|
||||
ElasticsearchSecurityException expected = expectThrows(ElasticsearchSecurityException.class, listener::actionGet);
|
||||
assertThat(expected.getMessage(), containsString("failed to authenticate user [" + principal));
|
||||
|
||||
|
@ -194,7 +219,7 @@ public class ReservedRealmTests extends ESTestCase {
|
|||
|
||||
// test new password
|
||||
final PlainActionFuture<User> authListener = new PlainActionFuture<>();
|
||||
reservedRealm.doAuthenticate(new UsernamePasswordToken(principal, newPassword), authListener);
|
||||
reservedRealm.doAuthenticate(new UsernamePasswordToken(principal, newPassword), authListener, incomingRequest);
|
||||
final User authenticated = authListener.actionGet();
|
||||
assertEquals(expectedUser, authenticated);
|
||||
assertThat(expectedUser.enabled(), is(enabled));
|
||||
|
@ -211,7 +236,7 @@ public class ReservedRealmTests extends ESTestCase {
|
|||
final ReservedRealm reservedRealm =
|
||||
new ReservedRealm(mock(Environment.class), Settings.EMPTY, usersStore,
|
||||
new AnonymousUser(Settings.EMPTY), securityLifecycleService, new ThreadContext(Settings.EMPTY));
|
||||
final User expectedUser = randomFrom(new ElasticUser(true), new KibanaUser(true), new LogstashSystemUser(true));
|
||||
final User expectedUser = randomFrom(new ElasticUser(true, true), new KibanaUser(true), new LogstashSystemUser(true));
|
||||
final String principal = expectedUser.principal();
|
||||
|
||||
PlainActionFuture<User> listener = new PlainActionFuture<>();
|
||||
|
@ -299,7 +324,7 @@ public class ReservedRealmTests extends ESTestCase {
|
|||
new AnonymousUser(Settings.EMPTY), securityLifecycleService, new ThreadContext(Settings.EMPTY));
|
||||
PlainActionFuture<Collection<User>> userFuture = new PlainActionFuture<>();
|
||||
reservedRealm.users(userFuture);
|
||||
assertThat(userFuture.actionGet(), containsInAnyOrder(new ElasticUser(true), new KibanaUser(true),
|
||||
assertThat(userFuture.actionGet(), containsInAnyOrder(new ElasticUser(true, true), new KibanaUser(true),
|
||||
new LogstashSystemUser(true), new BeatsSystemUser(true)));
|
||||
}
|
||||
|
||||
|
@ -321,19 +346,29 @@ public class ReservedRealmTests extends ESTestCase {
|
|||
}
|
||||
}
|
||||
|
||||
public void testFailedAuthentication() {
|
||||
@SuppressForbidden(reason = "allow getting localhost")
|
||||
public void testFailedAuthentication() throws UnknownHostException {
|
||||
final ReservedRealm reservedRealm = new ReservedRealm(mock(Environment.class), Settings.EMPTY, usersStore,
|
||||
new AnonymousUser(Settings.EMPTY), securityLifecycleService, new ThreadContext(Settings.EMPTY));
|
||||
InetSocketAddress address = new InetSocketAddress(InetAddress.getLocalHost(), 100);
|
||||
|
||||
// maybe cache a successful auth
|
||||
if (randomBoolean()) {
|
||||
PlainActionFuture<User> future = new PlainActionFuture<>();
|
||||
reservedRealm.authenticate(new UsernamePasswordToken(ElasticUser.NAME, new SecureString("changeme".toCharArray())), future);
|
||||
|
||||
IncomingRequest r = mock(IncomingRequest.class);
|
||||
when(r.getRemoteAddress()).thenReturn(address);
|
||||
when(r.getType()).thenReturn(IncomingRequest.RequestType.REST);
|
||||
reservedRealm.authenticate(new UsernamePasswordToken(ElasticUser.NAME, EMPTY_PASSWORD), future, r);
|
||||
User user = future.actionGet();
|
||||
assertEquals(new ElasticUser(true), user);
|
||||
assertEquals(new ElasticUser(true, true), user);
|
||||
}
|
||||
|
||||
PlainActionFuture<User> future = new PlainActionFuture<>();
|
||||
reservedRealm.authenticate(new UsernamePasswordToken(ElasticUser.NAME, new SecureString("foobar".toCharArray())), future);
|
||||
IncomingRequest r = mock(IncomingRequest.class);
|
||||
when(r.getRemoteAddress()).thenReturn(address);
|
||||
when(r.getType()).thenReturn(IncomingRequest.RequestType.REST);
|
||||
reservedRealm.authenticate(new UsernamePasswordToken(ElasticUser.NAME, new SecureString("foobar".toCharArray())), future, r);
|
||||
ElasticsearchSecurityException e = expectThrows(ElasticsearchSecurityException.class, future::actionGet);
|
||||
assertThat(e.getMessage(), containsString("failed to authenticate"));
|
||||
}
|
||||
|
|
|
@ -61,7 +61,7 @@ public class SetupPasswordToolTests extends CommandTestCase {
|
|||
execute("auto", pathHomeParameter, "-b", "true");
|
||||
|
||||
ArgumentCaptor<String> passwordCaptor = ArgumentCaptor.forClass(String.class);
|
||||
SecureString defaultPassword = new SecureString("changeme".toCharArray());
|
||||
SecureString defaultPassword = new SecureString("".toCharArray());
|
||||
|
||||
InOrder inOrder = Mockito.inOrder(httpClient);
|
||||
String elasticUrl = "http://localhost:9200/_xpack/security/user/elastic/_password";
|
||||
|
@ -80,7 +80,7 @@ public class SetupPasswordToolTests extends CommandTestCase {
|
|||
execute("auto", pathHomeParameter, "-u", url, "-b");
|
||||
|
||||
ArgumentCaptor<String> passwordCaptor = ArgumentCaptor.forClass(String.class);
|
||||
SecureString defaultPassword = new SecureString("changeme".toCharArray());
|
||||
SecureString defaultPassword = new SecureString("".toCharArray());
|
||||
|
||||
InOrder inOrder = Mockito.inOrder(httpClient);
|
||||
String elasticUrl = url + "/_xpack/security/user/elastic/_password";
|
||||
|
@ -99,7 +99,7 @@ public class SetupPasswordToolTests extends CommandTestCase {
|
|||
|
||||
execute("interactive", pathHomeParameter);
|
||||
|
||||
SecureString defaultPassword = new SecureString("changeme".toCharArray());
|
||||
SecureString defaultPassword = new SecureString("".toCharArray());
|
||||
|
||||
InOrder inOrder = Mockito.inOrder(httpClient);
|
||||
String elasticUrl = "http://localhost:9200/_xpack/security/user/elastic/_password";
|
||||
|
|
|
@ -10,6 +10,7 @@ import org.elasticsearch.common.settings.SecureString;
|
|||
import org.elasticsearch.common.settings.Settings;
|
||||
import org.elasticsearch.common.util.concurrent.ThreadContext;
|
||||
import org.elasticsearch.env.Environment;
|
||||
import org.elasticsearch.xpack.security.authc.IncomingRequest;
|
||||
import org.elasticsearch.xpack.security.authc.RealmConfig;
|
||||
import org.elasticsearch.xpack.security.authc.support.Hasher;
|
||||
import org.elasticsearch.xpack.security.authc.support.UsernamePasswordToken;
|
||||
|
@ -53,7 +54,7 @@ public class FileRealmTests extends ESTestCase {
|
|||
RealmConfig config = new RealmConfig("file-test", Settings.EMPTY, globalSettings, new Environment(globalSettings), new ThreadContext(globalSettings));
|
||||
FileRealm realm = new FileRealm(config, userPasswdStore, userRolesStore);
|
||||
PlainActionFuture<User> future = new PlainActionFuture<>();
|
||||
realm.authenticate(new UsernamePasswordToken("user1", new SecureString("test123")), future);
|
||||
realm.authenticate(new UsernamePasswordToken("user1", new SecureString("test123")), future, mock(IncomingRequest.class));
|
||||
User user = future.actionGet();
|
||||
assertThat(user, notNullValue());
|
||||
assertThat(user.principal(), equalTo("user1"));
|
||||
|
@ -71,10 +72,10 @@ public class FileRealmTests extends ESTestCase {
|
|||
when(userRolesStore.roles("user1")).thenReturn(new String[]{"role1", "role2"});
|
||||
FileRealm realm = new FileRealm(config, userPasswdStore, userRolesStore);
|
||||
PlainActionFuture<User> future = new PlainActionFuture<>();
|
||||
realm.authenticate(new UsernamePasswordToken("user1", new SecureString("test123")), future);
|
||||
realm.authenticate(new UsernamePasswordToken("user1", new SecureString("test123")), future, mock(IncomingRequest.class));
|
||||
User user1 = future.actionGet();
|
||||
future = new PlainActionFuture<>();
|
||||
realm.authenticate(new UsernamePasswordToken("user1", new SecureString("test123")), future);
|
||||
realm.authenticate(new UsernamePasswordToken("user1", new SecureString("test123")), future, mock(IncomingRequest.class));
|
||||
User user2 = future.actionGet();
|
||||
assertThat(user1, sameInstance(user2));
|
||||
}
|
||||
|
@ -87,32 +88,32 @@ public class FileRealmTests extends ESTestCase {
|
|||
doReturn(new String[] { "role1", "role2" }).when(userRolesStore).roles("user1");
|
||||
FileRealm realm = new FileRealm(config, userPasswdStore, userRolesStore);
|
||||
PlainActionFuture<User> future = new PlainActionFuture<>();
|
||||
realm.authenticate(new UsernamePasswordToken("user1", new SecureString("test123")), future);
|
||||
realm.authenticate(new UsernamePasswordToken("user1", new SecureString("test123")), future, mock(IncomingRequest.class));
|
||||
User user1 = future.actionGet();
|
||||
future = new PlainActionFuture<>();
|
||||
realm.authenticate(new UsernamePasswordToken("user1", new SecureString("test123")), future);
|
||||
realm.authenticate(new UsernamePasswordToken("user1", new SecureString("test123")), future, mock(IncomingRequest.class));
|
||||
User user2 = future.actionGet();
|
||||
assertThat(user1, sameInstance(user2));
|
||||
|
||||
userPasswdStore.notifyRefresh();
|
||||
|
||||
future = new PlainActionFuture<>();
|
||||
realm.authenticate(new UsernamePasswordToken("user1", new SecureString("test123")), future);
|
||||
realm.authenticate(new UsernamePasswordToken("user1", new SecureString("test123")), future, mock(IncomingRequest.class));
|
||||
User user3 = future.actionGet();
|
||||
assertThat(user2, not(sameInstance(user3)));
|
||||
future = new PlainActionFuture<>();
|
||||
realm.authenticate(new UsernamePasswordToken("user1", new SecureString("test123")), future);
|
||||
realm.authenticate(new UsernamePasswordToken("user1", new SecureString("test123")), future, mock(IncomingRequest.class));
|
||||
User user4 = future.actionGet();
|
||||
assertThat(user3, sameInstance(user4));
|
||||
|
||||
userRolesStore.notifyRefresh();
|
||||
|
||||
future = new PlainActionFuture<>();
|
||||
realm.authenticate(new UsernamePasswordToken("user1", new SecureString("test123")), future);
|
||||
realm.authenticate(new UsernamePasswordToken("user1", new SecureString("test123")), future, mock(IncomingRequest.class));
|
||||
User user5 = future.actionGet();
|
||||
assertThat(user4, not(sameInstance(user5)));
|
||||
future = new PlainActionFuture<>();
|
||||
realm.authenticate(new UsernamePasswordToken("user1", new SecureString("test123")), future);
|
||||
realm.authenticate(new UsernamePasswordToken("user1", new SecureString("test123")), future, mock(IncomingRequest.class));
|
||||
User user6 = future.actionGet();
|
||||
assertThat(user5, sameInstance(user6));
|
||||
}
|
||||
|
|
|
@ -17,6 +17,7 @@ import org.elasticsearch.common.io.PathUtilsForTesting;
|
|||
import org.elasticsearch.common.settings.SecureString;
|
||||
import org.elasticsearch.common.settings.Settings;
|
||||
import org.elasticsearch.env.Environment;
|
||||
import org.elasticsearch.test.SecuritySettingsSource;
|
||||
import org.elasticsearch.xpack.XPackSettings;
|
||||
import org.elasticsearch.xpack.security.authc.support.Hasher;
|
||||
import org.elasticsearch.xpack.security.authz.store.ReservedRolesStore;
|
||||
|
@ -64,10 +65,11 @@ public class UsersToolTests extends CommandTestCase {
|
|||
IOUtils.rm(homeDir);
|
||||
confDir = homeDir.resolve("config").resolve(XPackPlugin.NAME);
|
||||
Files.createDirectories(confDir);
|
||||
String defaultPassword = SecuritySettingsSource.TEST_PASSWORD;
|
||||
Files.write(confDir.resolve("users"), Arrays.asList(
|
||||
"existing_user:" + new String(Hasher.BCRYPT.hash(new SecureString("changeme".toCharArray()))),
|
||||
"existing_user2:" + new String(Hasher.BCRYPT.hash(new SecureString("changeme2".toCharArray()))),
|
||||
"existing_user3:" + new String(Hasher.BCRYPT.hash(new SecureString("changeme3".toCharArray())))
|
||||
"existing_user:" + new String(Hasher.BCRYPT.hash(SecuritySettingsSource.TEST_PASSWORD_SECURE_STRING)),
|
||||
"existing_user2:" + new String(Hasher.BCRYPT.hash(new SecureString((defaultPassword + "2").toCharArray()))),
|
||||
"existing_user3:" + new String(Hasher.BCRYPT.hash(new SecureString((defaultPassword + "3").toCharArray())))
|
||||
), StandardCharsets.UTF_8);
|
||||
Files.write(confDir.resolve("users_roles"), Arrays.asList(
|
||||
"test_admin:existing_user,existing_user2",
|
||||
|
@ -268,20 +270,20 @@ public class UsersToolTests extends CommandTestCase {
|
|||
}
|
||||
|
||||
public void testUseraddNoPassword() throws Exception {
|
||||
terminal.addSecretInput("changeme");
|
||||
terminal.addSecretInput("changeme");
|
||||
terminal.addSecretInput(SecuritySettingsSource.TEST_PASSWORD);
|
||||
terminal.addSecretInput(SecuritySettingsSource.TEST_PASSWORD);
|
||||
execute("useradd", pathHomeParameter, fileTypeParameter, "username");
|
||||
assertUser("username", "changeme");
|
||||
assertUser("username", SecuritySettingsSource.TEST_PASSWORD);
|
||||
}
|
||||
|
||||
public void testUseraddPasswordOption() throws Exception {
|
||||
execute("useradd", pathHomeParameter, fileTypeParameter, "username", "-p", "changeme");
|
||||
assertUser("username", "changeme");
|
||||
execute("useradd", pathHomeParameter, fileTypeParameter, "username", "-p", SecuritySettingsSource.TEST_PASSWORD);
|
||||
assertUser("username", SecuritySettingsSource.TEST_PASSWORD);
|
||||
}
|
||||
|
||||
public void testUseraddUserExists() throws Exception {
|
||||
UserException e = expectThrows(UserException.class, () -> {
|
||||
execute("useradd", pathHomeParameter, fileTypeParameter, "existing_user", "-p", "changeme");
|
||||
execute("useradd", pathHomeParameter, fileTypeParameter, "existing_user", "-p", SecuritySettingsSource.TEST_PASSWORD);
|
||||
});
|
||||
assertEquals(ExitCodes.CODE_ERROR, e.exitCode);
|
||||
assertEquals("User [existing_user] already exists", e.getMessage());
|
||||
|
@ -290,7 +292,7 @@ public class UsersToolTests extends CommandTestCase {
|
|||
public void testUseraddReservedUser() throws Exception {
|
||||
final String name = randomFrom(ElasticUser.NAME, KibanaUser.NAME);
|
||||
UserException e = expectThrows(UserException.class, () -> {
|
||||
execute("useradd", pathHomeParameter, fileTypeParameter, name, "-p", "changeme");
|
||||
execute("useradd", pathHomeParameter, fileTypeParameter, name, "-p", SecuritySettingsSource.TEST_PASSWORD);
|
||||
});
|
||||
assertEquals(ExitCodes.DATA_ERROR, e.exitCode);
|
||||
assertEquals("Invalid username [" + name + "]... Username [" + name + "] is reserved and may not be used.", e.getMessage());
|
||||
|
@ -299,7 +301,7 @@ public class UsersToolTests extends CommandTestCase {
|
|||
public void testUseraddNoRoles() throws Exception {
|
||||
Files.delete(confDir.resolve("users_roles"));
|
||||
Files.createFile(confDir.resolve("users_roles"));
|
||||
execute("useradd", pathHomeParameter, fileTypeParameter, "username", "-p", "changeme");
|
||||
execute("useradd", pathHomeParameter, fileTypeParameter, "username", "-p", SecuritySettingsSource.TEST_PASSWORD);
|
||||
List<String> lines = Files.readAllLines(confDir.resolve("users_roles"), StandardCharsets.UTF_8);
|
||||
assertTrue(lines.toString(), lines.isEmpty());
|
||||
}
|
||||
|
@ -319,7 +321,7 @@ public class UsersToolTests extends CommandTestCase {
|
|||
|
||||
public void testPasswdUnknownUser() throws Exception {
|
||||
UserException e = expectThrows(UserException.class, () -> {
|
||||
execute("passwd", pathHomeParameter, fileTypeParameter, "unknown", "-p", "changeme");
|
||||
execute("passwd", pathHomeParameter, fileTypeParameter, "unknown", "-p", SecuritySettingsSource.TEST_PASSWORD);
|
||||
});
|
||||
assertEquals(ExitCodes.NO_USER, e.exitCode);
|
||||
assertTrue(e.getMessage(), e.getMessage().contains("User [unknown] doesn't exist"));
|
||||
|
@ -365,7 +367,8 @@ public class UsersToolTests extends CommandTestCase {
|
|||
}
|
||||
|
||||
public void testRolesRemoveLeavesExisting() throws Exception {
|
||||
execute("useradd", pathHomeParameter, fileTypeParameter, "username", "-p", "changeme", "-r", "test_admin");
|
||||
execute("useradd", pathHomeParameter, fileTypeParameter, "username", "-p", SecuritySettingsSource.TEST_PASSWORD,
|
||||
"-r", "test_admin");
|
||||
execute("roles", pathHomeParameter, fileTypeParameter, "existing_user", "-r", "test_admin");
|
||||
assertRole("test_admin", "username");
|
||||
}
|
||||
|
@ -407,7 +410,8 @@ public class UsersToolTests extends CommandTestCase {
|
|||
}
|
||||
|
||||
public void testListUnknownRoles() throws Exception {
|
||||
execute("useradd", pathHomeParameter, fileTypeParameter, "username", "-p", "changeme", "-r", "test_r1,r2,r3");
|
||||
execute("useradd", pathHomeParameter, fileTypeParameter, "username", "-p", SecuritySettingsSource.TEST_PASSWORD,
|
||||
"-r", "test_r1,r2,r3");
|
||||
String output = execute("list", pathHomeParameter, fileTypeParameter, "username");
|
||||
assertTrue(output, output.contains("username"));
|
||||
assertTrue(output, output.contains("r2*,r3*,test_r1"));
|
||||
|
|
|
@ -19,6 +19,7 @@ import org.elasticsearch.common.settings.SecureString;
|
|||
import org.elasticsearch.common.settings.Settings;
|
||||
import org.elasticsearch.common.util.concurrent.ThreadContext;
|
||||
import org.elasticsearch.env.Environment;
|
||||
import org.elasticsearch.xpack.security.authc.IncomingRequest;
|
||||
import org.elasticsearch.xpack.security.authc.ldap.ActiveDirectorySessionFactory.DownLevelADAuthenticator;
|
||||
import org.elasticsearch.xpack.security.authc.ldap.ActiveDirectorySessionFactory.UpnADAuthenticator;
|
||||
import org.elasticsearch.xpack.security.user.User;
|
||||
|
@ -53,6 +54,7 @@ import static org.hamcrest.Matchers.is;
|
|||
import static org.hamcrest.Matchers.notNullValue;
|
||||
import static org.mockito.Matchers.any;
|
||||
import static org.mockito.Matchers.eq;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.spy;
|
||||
import static org.mockito.Mockito.times;
|
||||
import static org.mockito.Mockito.verify;
|
||||
|
@ -138,7 +140,7 @@ public class ActiveDirectoryRealmTests extends ESTestCase {
|
|||
LdapRealm realm = new LdapRealm(LdapRealm.AD_TYPE, config, sessionFactory, roleMapper, threadPool);
|
||||
|
||||
PlainActionFuture<User> future = new PlainActionFuture<>();
|
||||
realm.authenticate(new UsernamePasswordToken("CN=ironman", new SecureString(PASSWORD)), future);
|
||||
realm.authenticate(new UsernamePasswordToken("CN=ironman", new SecureString(PASSWORD)), future, mock(IncomingRequest.class));
|
||||
User user = future.actionGet();
|
||||
assertThat(user, is(notNullValue()));
|
||||
assertThat(user.roles(), arrayContaining(containsString("Avengers")));
|
||||
|
@ -153,7 +155,7 @@ public class ActiveDirectoryRealmTests extends ESTestCase {
|
|||
|
||||
// Thor does not have a UPN of form CN=Thor@ad.test.elasticsearch.com
|
||||
PlainActionFuture<User> future = new PlainActionFuture<>();
|
||||
realm.authenticate(new UsernamePasswordToken("CN=Thor", new SecureString(PASSWORD)), future);
|
||||
realm.authenticate(new UsernamePasswordToken("CN=Thor", new SecureString(PASSWORD)), future, mock(IncomingRequest.class));
|
||||
User user = future.actionGet();
|
||||
assertThat(user, is(notNullValue()));
|
||||
assertThat(user.roles(), arrayContaining(containsString("Avengers")));
|
||||
|
@ -178,7 +180,7 @@ public class ActiveDirectoryRealmTests extends ESTestCase {
|
|||
int count = randomIntBetween(2, 10);
|
||||
for (int i = 0; i < count; i++) {
|
||||
PlainActionFuture<User> future = new PlainActionFuture<>();
|
||||
realm.authenticate(new UsernamePasswordToken("CN=ironman", new SecureString(PASSWORD)), future);
|
||||
realm.authenticate(new UsernamePasswordToken("CN=ironman", new SecureString(PASSWORD)), future, mock(IncomingRequest.class));
|
||||
future.actionGet();
|
||||
}
|
||||
|
||||
|
@ -196,7 +198,7 @@ public class ActiveDirectoryRealmTests extends ESTestCase {
|
|||
int count = randomIntBetween(2, 10);
|
||||
for (int i = 0; i < count; i++) {
|
||||
PlainActionFuture<User> future = new PlainActionFuture<>();
|
||||
realm.authenticate(new UsernamePasswordToken("CN=ironman", new SecureString(PASSWORD)), future);
|
||||
realm.authenticate(new UsernamePasswordToken("CN=ironman", new SecureString(PASSWORD)), future, mock(IncomingRequest.class));
|
||||
future.actionGet();
|
||||
}
|
||||
|
||||
|
@ -214,7 +216,7 @@ public class ActiveDirectoryRealmTests extends ESTestCase {
|
|||
int count = randomIntBetween(2, 10);
|
||||
for (int i = 0; i < count; i++) {
|
||||
PlainActionFuture<User> future = new PlainActionFuture<>();
|
||||
realm.authenticate(new UsernamePasswordToken("CN=ironman", new SecureString(PASSWORD)), future);
|
||||
realm.authenticate(new UsernamePasswordToken("CN=ironman", new SecureString(PASSWORD)), future, mock(IncomingRequest.class));
|
||||
future.actionGet();
|
||||
}
|
||||
|
||||
|
@ -226,7 +228,7 @@ public class ActiveDirectoryRealmTests extends ESTestCase {
|
|||
|
||||
for (int i = 0; i < count; i++) {
|
||||
PlainActionFuture<User> future = new PlainActionFuture<>();
|
||||
realm.authenticate(new UsernamePasswordToken("CN=ironman", new SecureString(PASSWORD)), future);
|
||||
realm.authenticate(new UsernamePasswordToken("CN=ironman", new SecureString(PASSWORD)), future, mock(IncomingRequest.class));
|
||||
future.actionGet();
|
||||
}
|
||||
|
||||
|
@ -243,7 +245,7 @@ public class ActiveDirectoryRealmTests extends ESTestCase {
|
|||
LdapRealm realm = new LdapRealm(LdapRealm.AD_TYPE, config, sessionFactory, roleMapper, threadPool);
|
||||
|
||||
PlainActionFuture<User> future = new PlainActionFuture<>();
|
||||
realm.authenticate(new UsernamePasswordToken("CN=ironman", new SecureString(PASSWORD)), future);
|
||||
realm.authenticate(new UsernamePasswordToken("CN=ironman", new SecureString(PASSWORD)), future, mock(IncomingRequest.class));
|
||||
User user = future.actionGet();
|
||||
assertThat(user, is(notNullValue()));
|
||||
assertThat(user.roles(), arrayContaining(equalTo("group_role")));
|
||||
|
@ -259,7 +261,7 @@ public class ActiveDirectoryRealmTests extends ESTestCase {
|
|||
LdapRealm realm = new LdapRealm(LdapRealm.AD_TYPE, config, sessionFactory, roleMapper, threadPool);
|
||||
|
||||
PlainActionFuture<User> future = new PlainActionFuture<>();
|
||||
realm.authenticate(new UsernamePasswordToken("CN=Thor", new SecureString(PASSWORD)), future);
|
||||
realm.authenticate(new UsernamePasswordToken("CN=Thor", new SecureString(PASSWORD)), future, mock(IncomingRequest.class));
|
||||
User user = future.actionGet();
|
||||
assertThat(user, is(notNullValue()));
|
||||
assertThat(user.roles(), arrayContainingInAnyOrder(equalTo("group_role"), equalTo("user_role")));
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue