security: ssl by default on the transport layer
This commit adds the necessary changes to make SSL work on the transport layer by default. A large portion of the SSL configuration/settings was re-worked with this change. Some notable highlights include support for PEM cert/keys, reloadable SSL configuration, separate HTTP ssl configuration, and separate LDAP configuration. The following is a list of specific items addressed: * `SSLSettings` renamed to `SSLConfiguration` * `KeyConfig` and `TrustConfig` abstractions created. These hide the details of how `KeyManager[]` and `TrustManager[]` are loaded. These are also responsible for settings validation (ie keystore password is not null) * Configuration fallback is changed. Previously any setting would fallback to the "global" value (`xpack.security.ssl.*`). Now a keystore path, key path, ca paths, or truststore path must be specified otherwise the configuration for that key/trust will fallback to the global configuration. In other words if you want to change part of a keystore or truststore in a profile you need to supply all the information. This could be considered breaking if a user relied on the old fallback * JDK trusted certificates (`cacerts`) are trusted by default (breaking change). This can be disabled via a setting. * We now monitor the SSL files for changes and enable dynamic reloading of the configuration. This will make it easier for users when they are getting set up with certificates so they do not need to restart every time. This can be disabled via a setting * LDAP realms can now have their own SSL configurations * HTTP can now have its own SSL configuration * SSL is enabled by default on the transport layer only. Hostname verification is enabled as well. On startup if no global SSL settings are present and SSL is configured to be used, we auto generate one based on the default CA that is shipped. This process includes a best effort attempt to generate the subject alternative names. * `xpack.security.ssl.hostname_verification` is deprecated in favor of `xpack.security.ssl.hostname_verification.enabled` * added Bouncy Castle info to NOTICE * consolidated NOTICE and LICENSE files Closes elastic/elasticsearch#14 Closes elastic/elasticsearch#34 Closes elastic/elasticsearch#1483 Closes elastic/elasticsearch#1933 Addresses security portion of elastic/elasticsearch#673 Original commit: elastic/x-pack-elasticsearch@7c359db90b
This commit is contained in:
parent
29b996ea1d
commit
773876caee
|
@ -4,6 +4,14 @@ dependencies {
|
|||
testCompile project(path: ':x-plugins:elasticsearch:x-pack', configuration: 'runtime')
|
||||
}
|
||||
|
||||
String outputDir = "generated-resources/${project.name}"
|
||||
task copyXPackPluginProps(type: Copy) {
|
||||
from project(':x-plugins:elasticsearch:x-pack').file('src/main/plugin-metadata')
|
||||
from project(':x-plugins:elasticsearch:x-pack').tasks.pluginProperties
|
||||
into outputDir
|
||||
}
|
||||
project.sourceSets.test.output.dir(outputDir, builtBy: copyXPackPluginProps)
|
||||
|
||||
integTest {
|
||||
cluster {
|
||||
plugin 'x-pack', project(':x-plugins:elasticsearch:x-pack')
|
||||
|
|
|
@ -5,6 +5,7 @@
|
|||
*/
|
||||
package org.elasticsearch.shield.audit;
|
||||
|
||||
import com.carrotsearch.hppc.cursors.ObjectCursor;
|
||||
import org.elasticsearch.action.admin.indices.template.delete.DeleteIndexTemplateResponse;
|
||||
import org.elasticsearch.action.admin.indices.template.get.GetIndexTemplatesResponse;
|
||||
import org.elasticsearch.action.search.SearchResponse;
|
||||
|
@ -38,13 +39,22 @@ public class IndexAuditIT extends ESIntegTestCase {
|
|||
assertThat(response.getStatusCode(), is(200));
|
||||
|
||||
boolean found = awaitBusy(() -> {
|
||||
if (client().admin().cluster().prepareState().get().getState().getMetaData().getIndices().size() < 1) {
|
||||
boolean exists = false;
|
||||
for (ObjectCursor<String> cursor :
|
||||
client().admin().cluster().prepareState().get().getState().getMetaData().getIndices().keys()) {
|
||||
if (cursor.value.startsWith(".shield_audit_log")) {
|
||||
exists = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (exists == false) {
|
||||
return false;
|
||||
}
|
||||
|
||||
client().admin().indices().prepareRefresh().get();
|
||||
return client().prepareSearch(".shield_audit_log*").setQuery(QueryBuilders.matchQuery("principal", USER))
|
||||
.get().getHits().totalHits() > 0;
|
||||
}, 5L, TimeUnit.SECONDS);
|
||||
}, 10L, TimeUnit.SECONDS);
|
||||
|
||||
assertThat(found, is(true));
|
||||
|
||||
|
|
|
@ -4,6 +4,14 @@ dependencies {
|
|||
testCompile project(path: ':x-plugins:elasticsearch:x-pack', configuration: 'runtime')
|
||||
}
|
||||
|
||||
String outputDir = "generated-resources/${project.name}"
|
||||
task copyXPackPluginProps(type: Copy) {
|
||||
from project(':x-plugins:elasticsearch:x-pack').file('src/main/plugin-metadata')
|
||||
from project(':x-plugins:elasticsearch:x-pack').tasks.pluginProperties
|
||||
into outputDir
|
||||
}
|
||||
project.sourceSets.test.output.dir(outputDir, builtBy: copyXPackPluginProps)
|
||||
|
||||
integTest {
|
||||
cluster {
|
||||
plugin 'x-pack', project(':x-plugins:elasticsearch:x-pack')
|
||||
|
|
|
@ -23,6 +23,14 @@ Map generateSubstitutions() {
|
|||
]
|
||||
}
|
||||
|
||||
String outputDir = "generated-resources/${project.name}"
|
||||
task copyXPackPluginProps(type: Copy) {
|
||||
from project(':x-plugins:elasticsearch:x-pack').file('src/main/plugin-metadata')
|
||||
from project(':x-plugins:elasticsearch:x-pack').tasks.pluginProperties
|
||||
into outputDir
|
||||
}
|
||||
project.sourceSets.test.output.dir(outputDir, builtBy: copyXPackPluginProps)
|
||||
|
||||
processResources {
|
||||
MavenFilteringHack.filter(it, generateSubstitutions())
|
||||
}
|
||||
|
|
|
@ -7,6 +7,14 @@ dependencies {
|
|||
testCompile project(path: ':x-plugins:elasticsearch:x-pack', configuration: 'runtime')
|
||||
}
|
||||
|
||||
String outputDir = "generated-resources/${project.name}"
|
||||
task copyXPackPluginProps(type: Copy) {
|
||||
from project(':x-plugins:elasticsearch:x-pack').file('src/main/plugin-metadata')
|
||||
from project(':x-plugins:elasticsearch:x-pack').tasks.pluginProperties
|
||||
into outputDir
|
||||
}
|
||||
project.sourceSets.test.output.dir(outputDir, builtBy: copyXPackPluginProps)
|
||||
|
||||
// needed to be consistent with ssl host checking
|
||||
Object san = new SanEvaluator()
|
||||
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
Elasticsearch Shield
|
||||
Copyright 2009-2015 Elasticsearch
|
||||
Elasticsearch X-Pack
|
||||
Copyright 2009-2016 Elasticsearch
|
||||
|
||||
---
|
||||
This product includes software developed by The Apache Software
|
||||
|
@ -131,4 +131,76 @@ remaining provisions shall in no way be affected or impaired thereby. This
|
|||
Agreement and performance hereunder shall be governed by and construed in
|
||||
accordance with the laws of the State of Texas without regard to its conflict
|
||||
of laws rules. Any disputes related to this Agreement shall be exclusively
|
||||
litigated in the state or federal courts located in Travis County, Texas.
|
||||
litigated in the state or federal courts located in Travis County, Texas.
|
||||
|
||||
|
||||
---
|
||||
This product contains software distributed under
|
||||
Common Development and Distribution License 1.0 (CDDL)
|
||||
|
||||
JavaMail API 1.5.3
|
||||
https://java.net/projects/javamail/pages/Home
|
||||
https://java.net/projects/javamail/pages/License
|
||||
|
||||
JavaBeans Activation Framework 1.1.1
|
||||
http://www.oracle.com/technetwork/articles/java/index-135046.html
|
||||
|
||||
|
||||
|
||||
---
|
||||
This product contains software developed by Mike Samuel. The
|
||||
following is the copyright and notice text for this software:
|
||||
|
||||
Copyright (c) 2011, Mike Samuel
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions
|
||||
are met:
|
||||
|
||||
Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
Neither the name of the OWASP nor the names of its contributors may
|
||||
be used to endorse or promote products derived from this software
|
||||
without specific prior written permission.
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
|
||||
FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
|
||||
COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
||||
BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
|
||||
ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
|
||||
---
|
||||
This product contains software developed by The Legion of the Bouncy Castle.
|
||||
The following is the copyright and notice text for this software:
|
||||
|
||||
Copyright (c) 2000 - 2015 The Legion of the Bouncy Castle Inc.
|
||||
(http://www.bouncycastle.org)
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a
|
||||
copy of this software and associated documentation files (the "Software"),
|
||||
to deal in the Software without restriction, including without limitation
|
||||
the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
and/or sell copies of the Software, and to permit persons to whom the
|
||||
Software is furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
DEALINGS IN THE SOFTWARE.
|
|
@ -27,6 +27,8 @@ dependencies {
|
|||
// shield deps
|
||||
compile 'dk.brics.automaton:automaton:1.11-8'
|
||||
compile 'com.unboundid:unboundid-ldapsdk:2.3.8'
|
||||
compile 'org.bouncycastle:bcprov-jdk15on:1.54'
|
||||
compile 'org.bouncycastle:bcpkix-jdk15on:1.54'
|
||||
testCompile 'com.google.jimfs:jimfs:1.0'
|
||||
|
||||
// watcher deps
|
||||
|
@ -47,7 +49,6 @@ dependencies {
|
|||
testCompile "com.squareup.okhttp:okhttp:${versions.okhttp}"
|
||||
testCompile "com.squareup.okhttp:okhttp-ws:${versions.okhttp}"
|
||||
testCompile 'com.squareup.okio:okio:1.6.0'
|
||||
testCompile 'org.bouncycastle:bcprov-jdk15on:1.50'
|
||||
}
|
||||
|
||||
// we keep the source directories in the original structure of split plugins,
|
||||
|
@ -99,6 +100,7 @@ processTestResources {
|
|||
forbiddenPatterns {
|
||||
exclude '**/*.key'
|
||||
exclude '**/*.p12'
|
||||
exclude '**/*.der'
|
||||
}
|
||||
|
||||
// TODO: standardize packaging config for plugins
|
||||
|
|
|
@ -1,439 +0,0 @@
|
|||
SOFTWARE END USER LICENSE AGREEMENT
|
||||
|
||||
READ THIS AGREEMENT CAREFULLY, WHICH CONSTITUTES A LEGALLY BINDING AGREEMENT AND GOVERNS YOUR USE OF
|
||||
ELASTICSEARCH’S PROPRIETARY SOFTWARE. BY INSTALLING AND/OR USING SUCH SOFTWARE, YOU ARE INDICATING THAT YOU AGREE TO THE
|
||||
TERMS AND CONDITIONS SET FORTH IN THIS AGREEMENT. IF YOU DO NOT AGREE WITH SUCH TERMS AND CONDITIONS, YOU MAY NOT
|
||||
INSTALL OR USE ANY OF THE SOFTWARE.
|
||||
|
||||
This END USER LICENSE AGREEMENT (this “Agreement") is entered into by and between the applicable Elasticsearch
|
||||
entity referenced in Attachment 1 hereto (“Elasticsearch”) and the person or entity (“You”) that has downloaded any of
|
||||
Elasticsearch’s proprietary software to which this Agreement is attached or in connection with which this Agreement is
|
||||
presented to You (collectively, the “Software”). This Agreement is effective upon the earlier of the date on the
|
||||
commencement of any License granted pursuant to Section 1.1. below (as applicable, the “Effective Date”).
|
||||
|
||||
1. SOFTWARE LICENSE AND RESTRICTIONS
|
||||
1.1 License Grants.
|
||||
(a) Trial Version License. Subject to the terms and conditions of this Agreement, Elasticsearch agrees to
|
||||
grant, and does hereby grant to You, for a period of thirty (30) days from the date on which You first install the
|
||||
Software (the “Trial Term”), a License to the to use the Eligible Features and Functions of the Software that are
|
||||
applicable to the Trial Version of the Software. You understand and agree that upon the expiration of a Trial Term,
|
||||
You will no longer be able to use the Software, unless you either (i) purchase a Subscription, in which case You will
|
||||
receive a License under Section 1.1(b) below to use the Eligible Features and Functions of the Software that are
|
||||
applicable to the Subscription that You purchase, (ii) undertake the Registration of Your use of the Software with
|
||||
Elasticsearch, in which case You will receive a License under Section 1.1(c) below to the Basic Version of the Software
|
||||
or (iii) obtain from Elasticsearch written consent (e-mail sufficient) to extend the Trial Term, which may be granted by
|
||||
Elasticsearch in its sole and absolute discretion.
|
||||
(b) Subscription License. Subject to the terms and conditions of this Agreement and complete payment of any and
|
||||
all applicable Subscription fees, Elasticsearch agrees to grant, and does hereby grant to You during the Subscription
|
||||
Term, and for the restricted scope of this Agreement, a License (i) to use the Eligible Features and Functions of the
|
||||
Software that are applicable to the Subscription level that You have purchased, (ii) for the number of Nodes (as defined
|
||||
in the Elasticsearch Support Services Policy) and (iii) for the specific project for which you have purchased a
|
||||
Subscription. The level of Subscription, the number of Nodes and specific project for which you have purchased such
|
||||
Subscription, are set forth on the applicable ordering document entered into by Elasticsearch and You for the purchase
|
||||
of the applicable Subscription (“Order Form”).
|
||||
(c) Basic Version License. Subject to the terms and conditions of this Agreement, and in consideration of the
|
||||
Registration of Your use the Software, Elasticsearch agrees to grant, and does hereby grant to You, for a period of one
|
||||
(1) year from the date of Registration (“Basic Term”), a License to use the Eligible Features and Functions of the
|
||||
Software that are applicable to the Basic Version of the Software.
|
||||
1.2 Reservation of Rights; Restrictions. As between Elasticsearch and You, Elasticsearch owns all right title and
|
||||
interest in and to the Software and any derivative works thereof, and except as expressly set forth in Section 1.1
|
||||
above, no other license to the Software is granted to You by implication, estoppel or otherwise. You agree not to: (i)
|
||||
reverse engineer or decompile, decrypt, disassemble or otherwise reduce any Software or any portion thereof to
|
||||
human-readable form, except and only to the extent any such restriction is prohibited by applicable law, (ii) deploy the
|
||||
Software on more Nodes (as defined in Elasticsearch’s Support Services Policy) than are permitted under the applicable
|
||||
License grant in Section 1.1 above (iii) where You have purchased a Subscription, use the Software in connection with
|
||||
any project other than the project for which you have purchased such Subscription, as identified on the applicable Order
|
||||
Form, (iv) prepare derivative works from, modify, copy or use the Software in any manner except as expressly permitted
|
||||
in this Agreement; (v) except as expressly permitted in Section 1.1 above, transfer, sell, rent, lease, distribute,
|
||||
sublicense, loan or otherwise transfer the Software in whole or in part to any third party; (vi) except as may be
|
||||
expressly permitted on an applicable Order Form, use the Software for providing time-sharing services, any
|
||||
software-as-a-service offering (“SaaS”), service bureau services or as part of an application services provider or other
|
||||
service offering; (vii) circumvent the limitations on use of the Software that are imposed or preserved by any License
|
||||
Key, (viii) alter or remove any proprietary notices in the Software; or (ix) make available to any third party any
|
||||
analysis of the results of operation of the Software, including benchmarking results, without the prior written consent
|
||||
of Elasticsearch. The Software may contain or be provided with open source libraries, components, utilities and other
|
||||
open source software (collectively, “Open Source Software”), which Open Source Software may have applicable license
|
||||
terms as identified on a website designated by Elasticsearch or otherwise provided with the Software or Documentation.
|
||||
Notwithstanding anything to the contrary herein, use of the Open Source Software shall be subject to the license terms
|
||||
and conditions applicable to such Open Source Software, to the extent required by the applicable licensor (which terms
|
||||
shall not restrict the license rights granted to You hereunder, but may contain additional rights).
|
||||
1.3 Audit Rights. You agree that, unless such right is waived in writing by Elasticsearch, Elasticsearch shall have the
|
||||
right, upon fifteen (15) days’ notice to You, to audit Your use of the Software for compliance with any quantitative
|
||||
limitations on Your use of the Software that are set forth in the applicable Order Form. You agree to provide
|
||||
Elasticsearch with the necessary access to the Software to conduct such an audit either (i) remotely, or (ii) if remote
|
||||
performance is not possible, at Your facilities, during normal business hours and no more than one (1) time in any
|
||||
twelve (12) month period. In the event any such audit reveals that You have used the Software in excess of the
|
||||
applicable quantitative limitations, You agree to solely for Your internal business operations, a limited,
|
||||
non-exclusive, non-transferable, fully paid up, right and license (without the right to grant or authorize sublicenses)
|
||||
promptly pay to Elasticsearch an amount equal to the difference between the fees actually paid and the fees that You
|
||||
should have paid to remain in compliance with such quantitative limitations. This Section 1.3 shall survive for a
|
||||
period of two (2) years from the termination or expiration of this Agreement.
|
||||
1.4 Cluster Metadata. You understand and agree that once deployed, and on a daily basis, the Software may provide
|
||||
metadata to Elasticsearch about Your cluster statistics and associates that metadata with Your IP address. However, no
|
||||
other information is provided to Elasticsearch by the Software, including any information about the data You process or
|
||||
store in connection with your use of the Software. Instructions for disabling this feature are contained in the
|
||||
Software, however leaving this feature active enables Elasticsearch to gather cluster statistics and provide an improved
|
||||
level of support to You.
|
||||
|
||||
2. TERM AND TERMINATION
|
||||
2.1 Term. Unless earlier terminated under Section 2.2 below, this Agreement shall commence on the Effective Date, and
|
||||
shall continue in force for the term of the last to expire applicable license set forth in Section 1.1 above.
|
||||
2.2 Termination. Either party may, upon written notice to the other party, terminate this Agreement for material breach
|
||||
by the other party automatically and without any other formality, if such party has failed to cure such material breach
|
||||
within thirty (30) days of receiving written notice of such material breach from the non-breaching party.
|
||||
Notwithstanding the foregoing, this Agreement shall automatically terminate in the event that You intentionally breach
|
||||
the scope of the license granted in Section 1.1 of this Agreement, provided that Elasticsearch reserves the right to
|
||||
retroactively waive such automatic termination upon written notice to You.
|
||||
2.3 Post Termination or Expiration. Upon termination or expiration of this Agreement, for any reason, You shall
|
||||
promptly cease the use of the Software and Documentation and destroy (and certify to Elasticsearch in writing the fact
|
||||
of such destruction), or return to Elasticsearch, all copies of the Software and Documentation then in Your possession
|
||||
or under Your control.
|
||||
2.4 Survival. Sections 2.3, 2.4, 3, 4 and 5 (as any such Sections may be modified by Attachment 1, if applicable) shall
|
||||
survive any termination or expiration of this Agreement.
|
||||
3. LIMITED WARRANTY AND DISCLAIMER OF WARRANTIES
|
||||
3.1 Limited Performance Warranty. Subject to You purchasing a Subscription, Elasticsearch warrants that during the
|
||||
applicable Subscription Term, the Software will perform in all material respects in accordance with the Documentation.
|
||||
In the event of a breach of the foregoing warranty, Elasticsearch’s sole obligation, and Your exclusive remedy shall be
|
||||
for Elasticsearch to (i) correct any failure(s) of the Software to perform in all material respects in accordance with
|
||||
the Documentation or (ii) if Elasticsearch is unable to provide such a correction within thirty (30) days of receipt of
|
||||
notice of the applicable non-conformity, promptly refund to Customer any pre-paid, unused fees paid by You to
|
||||
Elasticsearch for the applicable Subscription. The warranty set forth in this Section 3.1 does not apply if the
|
||||
applicable Software or any portion thereof: (a) has been altered, except by or on behalf Elasticsearch; (b) has not been
|
||||
used, installed, operated, repaired, or maintained in accordance with this Agreement and/or the Documentation; (c) has
|
||||
been subjected to abnormal physical or electrical stress, misuse, negligence, or accident; or (d) is used on equipment,
|
||||
products, or systems not meeting specifications identified by Elasticsearch in the Documentation. Additionally, the
|
||||
warranties set forth herein only apply when notice of a warranty claim is provided to Elasticsearch within the
|
||||
applicable warranty period specified herein and do not apply to any bug, defect or error caused by or attributable to
|
||||
software or hardware not supplied by Elasticsearch.
|
||||
3.2 Malicious Code. Elasticsearch represents and warrants that prior to making it available for delivery to You,
|
||||
Elasticsearch will use standard industry practices including, without limitation, the use of an updated commercial
|
||||
anti-virus program, to test the Software for Malicious Code and remove any Malicious Code it discovers. In the event of
|
||||
a breach of the foregoing warranty, Elasticsearch’s sole obligation, and Your exclusive remedy shall be for
|
||||
Elasticsearch to replace the Software with Software that does not contain any Malicious Code.
|
||||
3.3 Warranty Disclaimer. TO THE MAXIMUM EXTENT PERMITTED UNDER APPLICABLE LAW, THE SOFTWARE IS PROVIDED “AS IS” WITHOUT
|
||||
WARRANTY OF ANY KIND, AND ELASTICSEARCH AND ITS LICENSORS MAKE NO WARRANTIES WHETHER EXPRESSED, IMPLIED OR STATUTORY
|
||||
REGARDING OR RELATING TO THE SOFTWARE OR DOCUMENTATION. TO THE MAXIMUM EXTENT PERMITTED UNDER APPLICABLE LAW,
|
||||
ELASTICSEARCH AND ITS LICENSORS SPECIFICALLY DISCLAIM ALL IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
|
||||
PARTICULAR PURPOSE AND NON-INFRINGEMENT WITH RESPECT TO THE SOFTWARE AND DOCUMENTATION, AND WITH RESPECT TO THE USE OF
|
||||
THE FOREGOING. FURTHER, ELASTICSEARCH DOES NOT WARRANT RESULTS OF USE OR THAT THE SOFTWARE WILL BE ERROR FREE OR THAT
|
||||
THE USE OF THE SOFTWARE WILL BE UNINTERRUPTED.
|
||||
4. LIMITATION OF LIABILITY
|
||||
The provisions of this Section 4 apply if You have not purchased a Subscription. If you have purchased a Subscription,
|
||||
then the limitations of liability set forth in the applicable Subscription Agreement will apply in lieu of those set
|
||||
forth in this Section 4.
|
||||
4.1 Disclaimer of Certain Damages. IN NO EVENT SHALL YOU OR ELASTICSEARCH OR ITS LICENSORS BE LIABLE FOR ANY LOSS OF
|
||||
PROFITS, LOSS OF USE, BUSINESS INTERRUPTION, LOSS OF DATA, COST OF SUBSTITUTE GOODS OR SERVICES, OR FOR ANY INDIRECT,
|
||||
SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES OF ANY KIND IN CONNECTION WITH OR ARISING OUT OF THE USE OR INABILITY TO
|
||||
USE THE SOFTWARE, OR THE PERFORMANCE OF OR FAILURE TO PERFORM THIS AGREEMENT, WHETHER ALLEGED AS A BREACH OF CONTRACT OR
|
||||
TORTIOUS CONDUCT, INCLUDING NEGLIGENCE, EVEN IF THE RESPONSIBLE PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
|
||||
DAMAGES. THE LIMITATIONS OF LIABILITY SET FORTH IN THIS SECTION 4.1 SHALL NOT APPLY TO A BREACH THROUGH GROSS NEGLIGENCE
|
||||
OR INTENTIONAL MISCONDUCT BY YOU OF THE SCOPE OF THE LICENSE GRANTED IN SECTION 1.1 OR TO ANY OTHER LIABILITY THAT
|
||||
CANNOT BE EXCLUDED OR LIMITED UNDER APPLICABLE LAW.
|
||||
4.2 Damages Cap. IN NO EVENT SHALL ELASTICSEARCH’S OR ITS LICENSORS’ AGGREGATE, CUMULATIVE LIABILITY UNDER THIS
|
||||
AGREEMENT EXCEED ONE THOUSAND DOLLARS ($1,000).
|
||||
4.3 YOU AGREE THAT THE FOREGOING LIMITATIONS, EXCLUSIONS AND DISCLAIMERS ARE A REASONABLE ALLOCATION OF THE RISK BETWEEN
|
||||
THE PARTIES AND WILL APPLY TO THE MAXIMUM EXTENT PERMITTED BY APPLICABLE LAW, EVEN IF ANY REMEDY FAILS IN ITS ESSENTIAL
|
||||
PURPOSE.
|
||||
5. DEFINITIONS
|
||||
The following terms have the meanings ascribed:
|
||||
5.1 “License” means a limited, non-exclusive, non-transferable, fully paid up, right and license (without the right to
|
||||
grant or authorize sublicenses) solely for Your internal business operations to (i) install and use, in object code
|
||||
format, the applicable Eligible Features and Functions of the Software, (ii) use, and distribute internally a reasonable
|
||||
number of copies of the Documentation, provided that You must include on such copies all Marks and Notices; (iii) permit
|
||||
Contractors to use the Software and Documentation as set forth in (i) and (ii) above, provided that such use must be
|
||||
solely for Your benefit, and You shall be responsible for all acts and omissions of such Contractors in connection with
|
||||
their use of the Software that are contrary to the terms and conditions of this Agreement..
|
||||
5.2 “License Key” means an alphanumeric code that enables the Eligible Features and Functions of the Software.
|
||||
5.3 “Basic Version” means that version of the Software available for use without the purchase of a Qualifying
|
||||
Subscription, but which does require Registration.
|
||||
5.4 “Contractor” means third party contractors performing services on Your behalf.
|
||||
5.5 “Documentation” means the published end user documentation provided by Elasticsearch with the Software.
|
||||
5.6 “Eligible Features and Functions” means those features and functions of the Software that are eligible for use with
|
||||
respect to a particular version of the Software or level of the Subscription. A list of the Eligible Features and
|
||||
Functions that correspond to each version of the Software and Subscription levels may be found at
|
||||
https://www.elastic.co/subscriptions.
|
||||
5.7 “Malicious Code” means any code that is designed to harm, or otherwise disrupt in any unauthorized manner, the
|
||||
operation of a recipient’s computer programs or computer systems or destroy or damage recipient’s data. For clarity,
|
||||
Malicious Code shall not include any software bugs or errors handled through Support Services, or any standard features
|
||||
of functions of the Software and/or any License Key that are intended to enforce the temporal and other limitations on
|
||||
the scope of the use of the Software to the scope of the license purchased by You.
|
||||
5.8 “Marks and Notices” means all Elasticsearch trademarks, trade names, logos and notices present on the Documentation
|
||||
as originally provided by Elasticsearch.
|
||||
5.9 “Registration” means Elasticsearch’s then-current process under which You may register Your use of the Software with
|
||||
Elasticsearch by providing certain information to Elasticsearch regarding your use of the Software.
|
||||
5.10 “Subscription” means the right to receive Support Services and a License to the Software.
|
||||
5.11 “Subscription Term” means the period of time for which You have purchased a Subscription.
|
||||
5.12 “Trial Version” means that version of the Software available for use without the purchase of a Qualifying
|
||||
Subscription and without Registration.
|
||||
6. MISCELLANEOUS
|
||||
This Agreement, including Attachment 1 hereto, which is hereby incorporated herein by this reference, completely and
|
||||
exclusively states the entire agreement of the parties regarding the subject matter herein, and it supersedes, and its
|
||||
terms govern, all prior proposals, agreements, or other communications between the parties, oral or written, regarding
|
||||
such subject matter. For the avoidance of doubt, the parties hereby expressly acknowledge and agree that if You issue
|
||||
any purchase order or similar document in connection with its purchase of a license to the Software, You will do so only
|
||||
for Your internal, administrative purposes and not with the intent to provide any contractual terms. This Agreement may
|
||||
not be modified except by a subsequently dated, written amendment that expressly amends this Agreement and which is
|
||||
signed on behalf of Elasticsearch and You, by duly authorized representatives. If any provision hereof is held
|
||||
unenforceable, this Agreement will continue without said provision and be interpreted to reflect the original intent of
|
||||
the parties.
|
||||
|
||||
|
||||
ATTACHMENT 1
|
||||
ADDITIONAL TERMS AND CONDITIONS
|
||||
|
||||
A. The following additional terms and conditions apply to all Customers with principal offices in the United States
|
||||
of America:
|
||||
|
||||
(1) Applicable Elasticsearch Entity. The entity providing the license is Elasticsearch, Inc., a Delaware corporation.
|
||||
|
||||
(2) Government Rights. The Software product is "Commercial Computer Software," as that term is defined in 48 C.F.R.
|
||||
2.101, and as the term is used in 48 C.F.R. Part 12, and is a Commercial Item comprised of "commercial computer
|
||||
software" and "commercial computer software documentation". If acquired by or on behalf of a civilian agency, the U.S.
|
||||
Government acquires this commercial computer software and/or commercial computer software documentation subject to the
|
||||
terms of this Agreement, as specified in 48 C.F.R. 12.212 (Computer Software) and 12.211 (Technical Data) of the Federal
|
||||
Acquisition Regulation ("FAR") and its successors. If acquired by or on behalf of any agency within the Department of
|
||||
Defense ("DOD"), the U.S. Government acquires this commercial computer software and/or commercial computer software
|
||||
documentation subject to the terms of the Elasticsearch Software License Agreement as specified in 48 C.F.R. 227.7202-3
|
||||
and 48 C.F.R. 227.7202-4 of the DOD FAR Supplement ("DFARS") and its successors, and consistent with 48 C.F.R. 227.7202.
|
||||
This U.S. Government Rights clause, consistent with 48 C.F.R. 12.212 and 48 C.F.R. 227.7202 is in lieu of, and
|
||||
supersedes, any other FAR, DFARS, or other clause or provision that addresses Government rights in computer software,
|
||||
computer software documentation or technical data related to the Software under this Agreement and in any Subcontract
|
||||
under which this commercial computer software and commercial computer software documentation is acquired or licensed.
|
||||
|
||||
(3) Export Control. You acknowledge that the goods, software and technology acquired from Elasticsearch are subject
|
||||
to U.S. export control laws and regulations, including but not limited to the International Traffic In Arms Regulations
|
||||
(“ITAR”) (22 C.F.R. Parts 120-130 (2010)); the Export Administration Regulations ("EAR") (15 C.F.R. Parts 730-774
|
||||
(2010)); the U.S. antiboycott regulations in the EAR and U.S. Department of the Treasury regulations; the economic
|
||||
sanctions regulations and guidelines of the U.S. Department of the Treasury, Office of Foreign Assets Control, and the
|
||||
USA Patriot Act (Title III of Pub. L. 107-56, signed into law October 26, 2001), as amended. You are now and will
|
||||
remain in the future compliant with all such export control laws and regulations, and will not export, re-export,
|
||||
otherwise transfer any Elasticsearch goods, software or technology or disclose any Elasticsearch software or technology
|
||||
to any person contrary to such laws or regulations. You acknowledge that remote access to the Software may in certain
|
||||
circumstances be considered a re-export of Software, and accordingly, may not be granted in contravention of U.S. export
|
||||
control laws and regulations.
|
||||
(4) Governing Law, Jurisdiction and Venue.
|
||||
(a) Customers in California. If Customer is located in California (as determined by the Customer address on the
|
||||
applicable Order Form, or for a trial license under 1.1(a), the location of person who installed the Software), this
|
||||
Agreement will be governed by the laws of the State of California, without regard to its conflict of laws principles,
|
||||
and all suits hereunder will be brought solely in Federal Court for the Northern District of California, or if that
|
||||
court lacks subject matter jurisdiction, in any California State Court located in Santa Clara County.
|
||||
(b) Customers Outside of California. If Customer is located anywhere other than California (as determined by the
|
||||
Customer address on the applicable Order Form, or for a trial license under 1.1(a), the location of person who installed
|
||||
the Software), this Agreement will be governed by the laws of the State of Delaware, without regard to its conflict of
|
||||
laws principles, and all suits hereunder will be brought solely in Federal Court for the District of Delaware, or if
|
||||
that court lacks subject matter jurisdiction, in any Delaware State Court located in Wilmington, Delaware.
|
||||
(c) All Customers. This Agreement shall not be governed by the 1980 UN Convention on Contracts for the International
|
||||
Sale of Goods. The parties hereby irrevocably waive any and all claims and defenses either might otherwise have in any
|
||||
action or proceeding in any of the applicable courts set forth in (a) or (b) above, based upon any alleged lack of
|
||||
personal jurisdiction, improper venue, forum non conveniens, or any similar claim or defense.
|
||||
(d) Equitable Relief. A breach or threatened breach, by either party of Section 4 may cause irreparable harm for
|
||||
which the non-breaching party shall be entitled to seek injunctive relief without being required to post a bond.
|
||||
|
||||
B. The following additional terms and conditions apply to all Customers with principal offices in Canada:
|
||||
|
||||
(1) Applicable Elasticsearch Entity. The entity providing the license is Elasticsearch B.C. Ltd., a corporation
|
||||
incorporated under laws of the Province of British Columbia.
|
||||
|
||||
(2) Export Control. You acknowledge that the goods, software and technology acquired from Elasticsearch are subject
|
||||
to the restrictions and controls set out in Section A(3) above as well as those imposed by the Export and Import Permits
|
||||
Act (Canada) and the regulations thereunder and that you will comply with all applicable laws and regulations. Without
|
||||
limitation, You acknowledge that the Marvel Software, or any portion thereof, will not be exported: (a) to any country
|
||||
on Canada's Area Control List; (b) to any country subject to UN Security Council embargo or action; or (c) contrary to
|
||||
Canada's Export Control List Item 5505. You are now and will remain in the future compliant with all such export control
|
||||
laws and regulations, and will not export, re-export, otherwise transfer any Elasticsearch goods, software or technology
|
||||
or disclose any Elasticsearch software or technology to any person contrary to such laws or regulations. You will not
|
||||
export or re-export the Marvel Software, or any portion thereof, directly or indirectly, in violation of the Canadian
|
||||
export administration laws and regulations to any country or end user, or to any end user who you know or have reason to
|
||||
know will utilize them in the design, development or production of nuclear, chemical or biological weapons. You further
|
||||
acknowledge that the Marvel Software product may include technical data subject to such Canadian export regulations.
|
||||
Elasticsearch does not represent that the Marvel Software is appropriate or available for use in all countries.
|
||||
Elasticsearch prohibits accessing materials from countries or states where contents are illegal. You are using the
|
||||
Marvel Software on your own initiative and you are responsible for compliance with all applicable laws. You hereby agree
|
||||
to indemnify Elasticsearch and its affiliates from any claims, actions, liability or expenses (including reasonable
|
||||
lawyers' fees) resulting from Your failure to act in accordance with the acknowledgements, agreements, and
|
||||
representations in this Section B(2).
|
||||
(3) Governing Law and Dispute Resolution. This Agreement shall be governed by the Province of Ontario and the
|
||||
federal laws of Canada applicable therein without regard to conflict of laws provisions. The parties hereby irrevocably
|
||||
waive any and all claims and defenses either might otherwise have in any such action or proceeding in any of such courts
|
||||
based upon any alleged lack of personal jurisdiction, improper venue, forum non conveniens or any similar claim or
|
||||
defense. Any dispute, claim or controversy arising out of or relating to this Agreement or the existence, breach,
|
||||
termination, enforcement, interpretation or validity thereof, including the determination of the scope or applicability
|
||||
of this agreement to arbitrate, (each, a “Dispute”), which the parties are unable to resolve after good faith
|
||||
negotiations, shall be submitted first to the upper management level of the parties. The parties, through their upper
|
||||
management level representatives shall meet within thirty (30) days of the Dispute being referred to them and if the
|
||||
parties are unable to resolve such Dispute within thirty (30) days of meeting, the parties agree to seek to resolve the
|
||||
Dispute through mediation with ADR Chambers in the City of Toronto, Ontario, Canada before pursuing any other
|
||||
proceedings. The costs of the mediator shall be shared equally by the parties. If the Dispute has not been resolved
|
||||
within thirty (30) days of the notice to desire to mediate, any party may terminate the mediation and proceed to
|
||||
arbitration and the matter shall be referred to and finally resolved by arbitration at ADR Chambers pursuant to the
|
||||
general ADR Chambers Rules for Arbitration in the City of Toronto, Ontario, Canada. The arbitration shall proceed in
|
||||
accordance with the provisions of the Arbitration Act (Ontario). The arbitral panel shall consist of three (3)
|
||||
arbitrators, selected as follows: each party shall appoint one (1) arbitrator; and those two (2) arbitrators shall
|
||||
discuss and select a chairman. If the two (2) party-appointed arbitrators are unable to agree on the chairman, the
|
||||
chairman shall be selected in accordance with the applicable rules of the arbitration body. Each arbitrator shall be
|
||||
independent of each of the parties. The arbitrators shall have the authority to grant specific performance and to
|
||||
allocate between the parties the costs of arbitration (including service fees, arbitrator fees and all other fees
|
||||
related to the arbitration) in such equitable manner as the arbitrators may determine. The prevailing party in any
|
||||
arbitration shall be entitled to receive reimbursement of its reasonable expenses incurred in connection therewith.
|
||||
Judgment upon the award so rendered may be entered in a court having jurisdiction or application may be made to such
|
||||
court for judicial acceptance of any award and an order of enforcement, as the case may be. Notwithstanding the
|
||||
foregoing, Elasticsearch shall have the right to institute an action in a court of proper jurisdiction for preliminary
|
||||
injunctive relief pending a final decision by the arbitrator, provided that a permanent injunction and damages shall
|
||||
only be awarded by the arbitrator. The language to be used in the arbitral proceedings shall be English.
|
||||
(4) Language. Any translation of this Agreement is done for local requirements and in the event of a dispute
|
||||
between the English and any non-English version, the English version of this Agreement shall govern. At the request of
|
||||
the parties, the official language of this Agreement and all communications and documents relating hereto is the English
|
||||
language, and the English-language version shall govern all interpretation of the Agreement. À la demande des parties,
|
||||
la langue officielle de la présente convention ainsi que toutes communications et tous documents s'y rapportant est la
|
||||
langue anglaise, et la version anglaise est celle qui régit toute interprétation de la présente convention.
|
||||
(5) Warranty Disclaimer. For Customers with principal offices in the Province of Québec, the following new sentence
|
||||
is to be added to the end of Section 3.3: “SOME JURISDICTIONS DO NOT ALLOW LIMITATIONS OR EXCLUSIONS OF CERTAIN TYPES OF
|
||||
DAMAGES AND/OR WARRANTIES AND CONDITIONS. THE LIMITATIONS, EXCLUSIONS AND DISCLAIMERS SET FORTH IN THIS AGREEMENT SHALL
|
||||
NOT APPLY IF AND ONLY IF AND TO THE EXTENT THAT THE LAWS OF A COMPETENT JURISDICTION REQUIRE LIABILITIES BEYOND AND
|
||||
DESPITE THESE LIMITATIONS, EXCLUSIONS AND DISCLAIMERS.”
|
||||
(6) Limitation of Liability. For Customers with principal offices in the Province of Québec, the following new
|
||||
sentence is to be added to the end of Section 4.1: “SOME JURISDICTIONS DO NOT ALLOW LIMITATIONS OR EXCLUSIONS OF CERTAIN
|
||||
TYPES OF DAMAGES AND/OR WARRANTIES AND CONDITIONS. THE LIMITATIONS, EXCLUSIONS AND DISCLAIMERS SET FORTH IN THIS
|
||||
AGREEMENT SHALL NOT APPLY IF AND ONLY IF AND TO THE EXTENT THAT THE LAWS OF A COMPETENT JURISDICTION REQUIRE LIABILITIES
|
||||
BEYOND AND DESPITE THESE LIMITATIONS, EXCLUSIONS AND DISCLAIMERS.”
|
||||
|
||||
C. The following additional terms and conditions apply to all Customers with principal offices outside of the United
|
||||
States of America and Canada:
|
||||
|
||||
(1) Applicable Elasticsearch Entity. The entity providing the license in Germany is Elasticsearch Gmbh; in France is
|
||||
Elasticsearch SARL, in the United Kingdom is Elasticsearch Ltd, in Australia is Elasticsearch Pty Ltd., in Japan is
|
||||
Elasticsearch KK, in Sweden is Elasticsearch AB, in Norway is Elasticsearch AS and in all other countries is
|
||||
Elasticsearch BV.
|
||||
|
||||
(2) Choice of Law. This Agreement shall be governed by and construed in accordance with the laws of the State of New
|
||||
York, without reference to or application of choice of law rules or principles. Notwithstanding any choice of law
|
||||
provision or otherwise, the Uniform Computer Information Transactions Act (UCITA) and the United Nations Convention on
|
||||
the International Sale of Goods shall not apply.
|
||||
|
||||
(3) Arbitration. Any dispute, claim or controversy arising out of or relating to this Agreement or the existence,
|
||||
breach, termination, enforcement, interpretation or validity thereof, including the determination of the scope or
|
||||
applicability of this agreement to arbitrate, (each, a “Dispute”) shall be referred to and finally resolved by
|
||||
arbitration under the rules and at the location identified below. The arbitral panel shall consist of three (3)
|
||||
arbitrators, selected as follows: each party shall appoint one (1) arbitrator; and those two (2) arbitrators shall
|
||||
discuss and select a chairman. If the two party-appointed arbitrators are unable to agree on the chairman, the chairman
|
||||
shall be selected in accordance with the applicable rules of the arbitration body. Each arbitrator shall be independent
|
||||
of each of the parties. The arbitrators shall have the authority to grant specific performance and to allocate between
|
||||
the parties the costs of arbitration (including service fees, arbitrator fees and all other fees related to the
|
||||
arbitration) in such equitable manner as the arbitrators may determine. The prevailing party in any arbitration shall
|
||||
be entitled to receive reimbursement of its reasonable expenses incurred in connection therewith. Judgment upon the
|
||||
award so rendered may be entered in a court having jurisdiction or application may be made to such court for judicial
|
||||
acceptance of any award and an order of enforcement, as the case may be. Notwithstanding the foregoing, Elasticsearch
|
||||
shall have the right to institute an action in a court of proper jurisdiction for preliminary injunctive relief pending
|
||||
a final decision by the arbitrator, provided that a permanent injunction and damages shall only be awarded by the
|
||||
arbitrator. The language to be used in the arbitral proceedings shall be English.
|
||||
|
||||
In addition, the following terms only apply to Customers with principal offices within Europe, the Middle East or Africa
|
||||
(EMEA):
|
||||
|
||||
Arbitration Rules and Location. Any Dispute shall be referred to and finally resolved by arbitration under the London
|
||||
Court of International Arbitration (“LCIA”) Rules (which Rules are deemed to be incorporated by reference into this
|
||||
clause) on the basis that the governing law is the law of the State of New York, USA. The seat, or legal place, of
|
||||
arbitration shall be London, England.
|
||||
|
||||
(b) In addition, the following terms only apply to Customers with principal offices within Asia Pacific, Australia &
|
||||
New Zealand:
|
||||
|
||||
Arbitration Rules and Location. Any Dispute shall be referred to and finally resolved by arbitration under the Rules of
|
||||
Conciliation and Arbitration of the International Chamber of Commerce (“ICC”) in force on the date when the notice of
|
||||
arbitration is submitted in accordance with such Rules (which Rules are deemed to be incorporated by reference into this
|
||||
clause) on the basis that the governing law is the law of the State of New York, USA. The seat, or legal place, of
|
||||
arbitration shall be Singapore.
|
||||
|
||||
(c) In addition, the following terms only apply to Customers with principal offices within the Americas (excluding
|
||||
North America):
|
||||
|
||||
Arbitration Rules and Location. Any Dispute shall be referred to and finally resolved by arbitration under
|
||||
International Dispute Resolution Procedures of the American Arbitration Association (“AAA”) in force on the date when
|
||||
the notice of arbitration is submitted in accordance with such Procedures (which Procedures are deemed to be
|
||||
incorporated by reference into this clause) on the basis that the governing law is the law of the State of New York,
|
||||
USA. The seat, or legal place, of arbitration shall be New York, New York, USA.
|
||||
|
||||
(4) In addition, for Customers with principal offices within the UK, the following new sentence is added to the end
|
||||
of Section 4.1:
|
||||
|
||||
Nothing in this Agreement shall have effect so as to limit or exclude a party’s liability for death or personal injury
|
||||
caused by negligence or for fraud including fraudulent misrepresentation and this Section 4.1 shall take effect subject
|
||||
to this provision.
|
||||
|
||||
(5) In addition, for Customers with principal offices within France, Sections 1.2, 3 and 4.1 of the Agreement are
|
||||
deleted and replaced with the following new Sections 1.2, 3.3 and 4.1:
|
||||
1.2 Reservation of Rights; Restrictions. Elasticsearch owns all right title and interest in and to the Software and
|
||||
any derivative works thereof, and except as expressly set forth in Section 1.1 above, no other license to the Software
|
||||
is granted to You by implication, or otherwise. You agree not to prepare derivative works from, modify, copy or use the
|
||||
Software in any manner except as expressly permitted in this Agreement; provided that You may copy the Software for
|
||||
archival purposes, only where such software is provided on a non-durable medium; and You may decompile the Software,
|
||||
where necessary for interoperability purposes and where necessary for the correction of errors making the software unfit
|
||||
for its intended purpose, if such right is not reserved by Elasticsearch as editor of the Software. Pursuant to article
|
||||
L122-6-1 of the French intellectual property code, Elasticsearch reserves the right to correct any bugs as necessary for
|
||||
the Software to serve its intended purpose. You agree not to: (i) transfer, sell, rent, lease, distribute, sublicense,
|
||||
loan or otherwise transfer the Software in whole or in part to any third party; (ii) use the Software for providing
|
||||
time-sharing services, any software-as-a-service offering (“SaaS”), service bureau services or as part of an application
|
||||
services provider or other service offering; (iii) alter or remove any proprietary notices in the Software; or (iv) make
|
||||
available to any third party any analysis of the results of operation of the Software, including benchmarking results,
|
||||
without the prior written consent of Elasticsearch.
|
||||
3.3 Warranty Disclaimer. TO THE MAXIMUM EXTENT PERMITTED UNDER APPLICABLE LAW, THE SOFTWARE IS PROVIDED “AS IS”
|
||||
WITHOUT WARRANTY OF ANY KIND, AND ELASTICSEARCH AND ITS LICENSORS MAKE NO WARRANTIES WHETHER EXPRESSED, IMPLIED OR
|
||||
STATUTORY REGARDING OR RELATING TO THE SOFTWARE OR DOCUMENTATION. TO THE MAXIMUM EXTENT PERMITTED UNDER APPLICABLE LAW,
|
||||
ELASTICSEARCH AND ITS LICENSORS SPECIFICALLY DISCLAIM ALL IMPLIED WARRANTIES OF FITNESS FOR A PARTICULAR PURPOSE WITH
|
||||
RESPECT TO THE SOFTWARE AND DOCUMENTATION, AND WITH RESPECT TO THE USE OF THE FOREGOING. FURTHER, ELASTICSEARCH DOES
|
||||
NOT WARRANT RESULTS OF USE OR THAT THE SOFTWARE WILL BE ERROR FREE OR THAT THE USE OF THE SOFTWARE WILL BE
|
||||
UNINTERRUPTED.
|
||||
4.1 Disclaimer of Certain Damages. IN NO EVENT SHALL YOU OR ELASTICSEARCH OR ITS LICENSORS BE LIABLE FOR ANY LOSS OF
|
||||
PROFITS, LOSS OF USE, BUSINESS INTERRUPTION, LOSS OF DATA, COST OF SUBSTITUTE GOODS OR SERVICES, OR FOR ANY INDIRECT OR
|
||||
UNFORESEEABLE DAMAGES OF ANY KIND IN CONNECTION WITH OR ARISING OUT OF THE USE OR INABILITY TO USE THE SOFTWARE, OR THE
|
||||
PERFORMANCE OF OR FAILURE TO PERFORM THIS AGREEMENT, WHETHER ALLEGED AS A BREACH OF CONTRACT OR TORTIOUS CONDUCT,
|
||||
INCLUDING NEGLIGENCE. THE LIMITATIONS OF LIABILITY SET FORTH IN THIS SECTION 4.1 SHALL NOT APPLY TO A BREACH, THROUGH
|
||||
GROSS NEGLIGENCE OR INTENTIONAL MISCONDUCT BY YOU, OF THE SCOPE OF THE LICENSE GRANTED IN SECTION 1.1, OR IN CASE OF
|
||||
DEATH OR PERSONAL INJURY.
|
||||
(6) In addition, for Customers with principal offices within Australia, Sections 4.1, 4.2 and 4.3 of the Agreement
|
||||
are deleted and replaced with the following new Sections 4.1, 4.2 and 4.3:
|
||||
4.1 Disclaimer of Certain Damages. Subject to clause 4.3, a party is not liable for Consequential Loss however
|
||||
caused (including by the negligence of that party) suffered or incurred by the other party in connection with this
|
||||
agreement. “Consequential Loss” means loss of revenues, loss of reputation, indirect loss, loss of profits,
|
||||
consequential loss, loss of actual or anticipated savings, indirect loss, lost opportunities, including opportunities to
|
||||
enter into arrangements with third parties, loss or damage in connection with claims against by third parties, or loss
|
||||
or corruption or data.
|
||||
4.2 Damages Cap. SUBJECT TO CLAUSES 4.1 AND 4.3, ANY LIABILITY OF ELASTICSEARCH FOR ANY LOSS OR DAMAGE, HOWEVER
|
||||
CAUSED (INCLUDING BY THE NEGLIGENCE OF ELASTICSEARCH), SUFFERED BY YOU IN CONNECTION WITH THIS AGREEMENT IS LIMITED TO
|
||||
THE AMOUNT YOU PAID, IN THE TWELVE (12) MONTHS IMMEDIATELY PRIOR TO THE EVENT GIVING RISE TO LIABILITY, UNDER THE
|
||||
ELASTICSEARCH SUPPORT SERVICES AGREEMENT IN CONNECTION WITH WHICH YOU OBTAINED THE LICENSE TO USE THE SOFTWARE. THE
|
||||
LIMITATION SET OUT IN THIS SECTION 4.2 IS AN AGGREGATE LIMIT FOR ALL CLAIMS, WHENEVER MADE.
|
||||
4.3 Limitation and Disclaimer Exceptions. If the Competition and Consumer Act 2010 (Cth) or any other legislation or
|
||||
any other legislation states that there is a guarantee in relation to any good or service supplied by Elasticsearch in
|
||||
connection with this agreement, and Elasticsearch’s liability for failing to comply with that guarantee cannot be
|
||||
excluded but may be limited, Sections 4.1 and 4.2 do not apply to that liability and instead Elasticsearch’s liability
|
||||
for such failure is limited (at Elasticsearch’s election) to, in the case of a supply of goods, the Elasticsearch
|
||||
replacing the goods or supplying equivalent goods or repairing the goods, or in the case of a supply of services,
|
||||
Elasticsearch supplying the services again or paying the cost of having the services supplied again.
|
||||
(7) In addition, for Customers with principal offices within Japan, Sections 1.2, 3 and 4.1 of the Agreement are
|
||||
deleted and replaced with the following new Sections 1.2, 3.3 and 4.1:
|
||||
1.2 Reservation of Rights; Restrictions. As between Elasticsearch and You, Elasticsearch owns all right title and
|
||||
interest in and to the Software and any derivative works thereof, and except as expressly set forth in Section 1.1
|
||||
above, no other license to the Software is granted to You by implication or otherwise. You agree not to: (i) prepare
|
||||
derivative works from, modify, copy or use the Software in any manner except as expressly permitted in this Agreement or
|
||||
applicable law; (ii) transfer, sell, rent, lease, distribute, sublicense, loan or otherwise transfer the Software in
|
||||
whole or in part to any third party; (iii) use the Software for providing time-sharing services, any
|
||||
software-as-a-service offering (“SaaS”), service bureau services or as part of an application services provider or other
|
||||
service offering; (iv) alter or remove any proprietary notices in the Software; or (v) make available to any third party
|
||||
any analysis of the results of operation of the Software, including benchmarking results, without the prior written
|
||||
consent of Elasticsearch.
|
||||
3.3 Warranty Disclaimer. TO THE MAXIMUM EXTENT PERMITTED UNDER APPLICABLE LAW, THE SOFTWARE IS PROVIDED “AS IS”
|
||||
WITHOUT WARRANTY OF ANY KIND, AND ELASTICSEARCH AND ITS LICENSORS MAKE NO WARRANTIES WHETHER EXPRESSED, IMPLIED OR
|
||||
STATUTORY REGARDING OR RELATING TO THE SOFTWARE OR DOCUMENTATION. TO THE MAXIMUM EXTENT PERMITTED UNDER APPLICABLE LAW,
|
||||
ELASTICSEARCH AND ITS LICENSORS SPECIFICALLY DISCLAIM ALL IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
|
||||
PARTICULAR PURPOSE AND NON-INFRINGEMENT WITH RESPECT TO THE SOFTWARE AND DOCUMENTATION, AND WITH RESPECT TO THE USE OF
|
||||
THE FOREGOING. FURTHER, ELASTICSEARCH DOES NOT WARRANT RESULTS OF USE OR THAT THE SOFTWARE WILL BE ERROR FREE OR THAT
|
||||
THE USE OF THE SOFTWARE WILL BE UNINTERRUPTED.
|
||||
4.1 Disclaimer of Certain Damages. IN NO EVENT SHALL YOU OR ELASTICSEARCH OR ITS LICENSORS BE LIABLE FOR ANY LOSS OF
|
||||
PROFITS, LOSS OF USE, BUSINESS INTERRUPTION, LOSS OF DATA, COST OF SUBSTITUTE GOODS OR SERVICES, OR FOR ANY
|
||||
SPECIALINDIRECT, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES OF ANY KIND IN CONNECTION WITH OR ARISING OUT OF THE USE
|
||||
OR INABILITY TO USE THE SOFTWARE, OR THE PERFORMANCE OF OR FAILURE TO PERFORM THIS AGREEMENT, WHETHER ALLEGED AS A
|
||||
BREACH OF CONTRACT OR TORTIOUS CONDUCT, INCLUDING NEGLIGENCE, EVEN IF THE RESPONSIBLE PARTY HAS BEEN ADVISED OF THE
|
||||
POSSIBILITY OF SUCH DAMAGES. THE LIMITATIONS OF LIABILITY SET FORTH IN THIS SECTION 4.1 SHALL NOT APPLY TO A BREACH
|
||||
THROUGH GROSS NEGLIGENCE OR INTENTIONAL MISCONDUCT BY YOU OF THE SCOPE OF THE LICENSE GRANTED IN SECTION 1.1 OR TO ANY
|
||||
OTHER LIABILITY THAT CANNOT BE EXCLUDED OR LIMITED UNDER APPLICABLE LAW.
|
|
@ -1,6 +0,0 @@
|
|||
Elasticsearch License
|
||||
Copyright 2009-2015 Elastic
|
||||
|
||||
---
|
||||
This product includes software developed by The Apache Software
|
||||
Foundation (http://www.apache.org/).
|
|
@ -1,439 +0,0 @@
|
|||
SOFTWARE END USER LICENSE AGREEMENT
|
||||
|
||||
READ THIS AGREEMENT CAREFULLY, WHICH CONSTITUTES A LEGALLY BINDING AGREEMENT AND GOVERNS YOUR USE OF
|
||||
ELASTICSEARCH’S PROPRIETARY SOFTWARE. BY INSTALLING AND/OR USING SUCH SOFTWARE, YOU ARE INDICATING THAT YOU AGREE TO THE
|
||||
TERMS AND CONDITIONS SET FORTH IN THIS AGREEMENT. IF YOU DO NOT AGREE WITH SUCH TERMS AND CONDITIONS, YOU MAY NOT
|
||||
INSTALL OR USE ANY OF THE SOFTWARE.
|
||||
|
||||
This END USER LICENSE AGREEMENT (this “Agreement") is entered into by and between the applicable Elasticsearch
|
||||
entity referenced in Attachment 1 hereto (“Elasticsearch”) and the person or entity (“You”) that has downloaded any of
|
||||
Elasticsearch’s proprietary software to which this Agreement is attached or in connection with which this Agreement is
|
||||
presented to You (collectively, the “Software”). This Agreement is effective upon the earlier of the date on the
|
||||
commencement of any License granted pursuant to Section 1.1. below (as applicable, the “Effective Date”).
|
||||
|
||||
1. SOFTWARE LICENSE AND RESTRICTIONS
|
||||
1.1 License Grants.
|
||||
(a) Trial Version License. Subject to the terms and conditions of this Agreement, Elasticsearch agrees to
|
||||
grant, and does hereby grant to You, for a period of thirty (30) days from the date on which You first install the
|
||||
Software (the “Trial Term”), a License to the to use the Eligible Features and Functions of the Software that are
|
||||
applicable to the Trial Version of the Software. You understand and agree that upon the expiration of a Trial Term,
|
||||
You will no longer be able to use the Software, unless you either (i) purchase a Subscription, in which case You will
|
||||
receive a License under Section 1.1(b) below to use the Eligible Features and Functions of the Software that are
|
||||
applicable to the Subscription that You purchase, (ii) undertake the Registration of Your use of the Software with
|
||||
Elasticsearch, in which case You will receive a License under Section 1.1(c) below to the Basic Version of the Software
|
||||
or (iii) obtain from Elasticsearch written consent (e-mail sufficient) to extend the Trial Term, which may be granted by
|
||||
Elasticsearch in its sole and absolute discretion.
|
||||
(b) Subscription License. Subject to the terms and conditions of this Agreement and complete payment of any and
|
||||
all applicable Subscription fees, Elasticsearch agrees to grant, and does hereby grant to You during the Subscription
|
||||
Term, and for the restricted scope of this Agreement, a License (i) to use the Eligible Features and Functions of the
|
||||
Software that are applicable to the Subscription level that You have purchased, (ii) for the number of Nodes (as defined
|
||||
in the Elasticsearch Support Services Policy) and (iii) for the specific project for which you have purchased a
|
||||
Subscription. The level of Subscription, the number of Nodes and specific project for which you have purchased such
|
||||
Subscription, are set forth on the applicable ordering document entered into by Elasticsearch and You for the purchase
|
||||
of the applicable Subscription (“Order Form”).
|
||||
(c) Basic Version License. Subject to the terms and conditions of this Agreement, and in consideration of the
|
||||
Registration of Your use the Software, Elasticsearch agrees to grant, and does hereby grant to You, for a period of one
|
||||
(1) year from the date of Registration (“Basic Term”), a License to use the Eligible Features and Functions of the
|
||||
Software that are applicable to the Basic Version of the Software.
|
||||
1.2 Reservation of Rights; Restrictions. As between Elasticsearch and You, Elasticsearch owns all right title and
|
||||
interest in and to the Software and any derivative works thereof, and except as expressly set forth in Section 1.1
|
||||
above, no other license to the Software is granted to You by implication, estoppel or otherwise. You agree not to: (i)
|
||||
reverse engineer or decompile, decrypt, disassemble or otherwise reduce any Software or any portion thereof to
|
||||
human-readable form, except and only to the extent any such restriction is prohibited by applicable law, (ii) deploy the
|
||||
Software on more Nodes (as defined in Elasticsearch’s Support Services Policy) than are permitted under the applicable
|
||||
License grant in Section 1.1 above (iii) where You have purchased a Subscription, use the Software in connection with
|
||||
any project other than the project for which you have purchased such Subscription, as identified on the applicable Order
|
||||
Form, (iv) prepare derivative works from, modify, copy or use the Software in any manner except as expressly permitted
|
||||
in this Agreement; (v) except as expressly permitted in Section 1.1 above, transfer, sell, rent, lease, distribute,
|
||||
sublicense, loan or otherwise transfer the Software in whole or in part to any third party; (vi) except as may be
|
||||
expressly permitted on an applicable Order Form, use the Software for providing time-sharing services, any
|
||||
software-as-a-service offering (“SaaS”), service bureau services or as part of an application services provider or other
|
||||
service offering; (vii) circumvent the limitations on use of the Software that are imposed or preserved by any License
|
||||
Key, (viii) alter or remove any proprietary notices in the Software; or (ix) make available to any third party any
|
||||
analysis of the results of operation of the Software, including benchmarking results, without the prior written consent
|
||||
of Elasticsearch. The Software may contain or be provided with open source libraries, components, utilities and other
|
||||
open source software (collectively, “Open Source Software”), which Open Source Software may have applicable license
|
||||
terms as identified on a website designated by Elasticsearch or otherwise provided with the Software or Documentation.
|
||||
Notwithstanding anything to the contrary herein, use of the Open Source Software shall be subject to the license terms
|
||||
and conditions applicable to such Open Source Software, to the extent required by the applicable licensor (which terms
|
||||
shall not restrict the license rights granted to You hereunder, but may contain additional rights).
|
||||
1.3 Audit Rights. You agree that, unless such right is waived in writing by Elasticsearch, Elasticsearch shall have the
|
||||
right, upon fifteen (15) days’ notice to You, to audit Your use of the Software for compliance with any quantitative
|
||||
limitations on Your use of the Software that are set forth in the applicable Order Form. You agree to provide
|
||||
Elasticsearch with the necessary access to the Software to conduct such an audit either (i) remotely, or (ii) if remote
|
||||
performance is not possible, at Your facilities, during normal business hours and no more than one (1) time in any
|
||||
twelve (12) month period. In the event any such audit reveals that You have used the Software in excess of the
|
||||
applicable quantitative limitations, You agree to solely for Your internal business operations, a limited,
|
||||
non-exclusive, non-transferable, fully paid up, right and license (without the right to grant or authorize sublicenses)
|
||||
promptly pay to Elasticsearch an amount equal to the difference between the fees actually paid and the fees that You
|
||||
should have paid to remain in compliance with such quantitative limitations. This Section 1.3 shall survive for a
|
||||
period of two (2) years from the termination or expiration of this Agreement.
|
||||
1.4 Cluster Metadata. You understand and agree that once deployed, and on a daily basis, the Software may provide
|
||||
metadata to Elasticsearch about Your cluster statistics and associates that metadata with Your IP address. However, no
|
||||
other information is provided to Elasticsearch by the Software, including any information about the data You process or
|
||||
store in connection with your use of the Software. Instructions for disabling this feature are contained in the
|
||||
Software, however leaving this feature active enables Elasticsearch to gather cluster statistics and provide an improved
|
||||
level of support to You.
|
||||
|
||||
2. TERM AND TERMINATION
|
||||
2.1 Term. Unless earlier terminated under Section 2.2 below, this Agreement shall commence on the Effective Date, and
|
||||
shall continue in force for the term of the last to expire applicable license set forth in Section 1.1 above.
|
||||
2.2 Termination. Either party may, upon written notice to the other party, terminate this Agreement for material breach
|
||||
by the other party automatically and without any other formality, if such party has failed to cure such material breach
|
||||
within thirty (30) days of receiving written notice of such material breach from the non-breaching party.
|
||||
Notwithstanding the foregoing, this Agreement shall automatically terminate in the event that You intentionally breach
|
||||
the scope of the license granted in Section 1.1 of this Agreement, provided that Elasticsearch reserves the right to
|
||||
retroactively waive such automatic termination upon written notice to You.
|
||||
2.3 Post Termination or Expiration. Upon termination or expiration of this Agreement, for any reason, You shall
|
||||
promptly cease the use of the Software and Documentation and destroy (and certify to Elasticsearch in writing the fact
|
||||
of such destruction), or return to Elasticsearch, all copies of the Software and Documentation then in Your possession
|
||||
or under Your control.
|
||||
2.4 Survival. Sections 2.3, 2.4, 3, 4 and 5 (as any such Sections may be modified by Attachment 1, if applicable) shall
|
||||
survive any termination or expiration of this Agreement.
|
||||
3. LIMITED WARRANTY AND DISCLAIMER OF WARRANTIES
|
||||
3.1 Limited Performance Warranty. Subject to You purchasing a Subscription, Elasticsearch warrants that during the
|
||||
applicable Subscription Term, the Software will perform in all material respects in accordance with the Documentation.
|
||||
In the event of a breach of the foregoing warranty, Elasticsearch’s sole obligation, and Your exclusive remedy shall be
|
||||
for Elasticsearch to (i) correct any failure(s) of the Software to perform in all material respects in accordance with
|
||||
the Documentation or (ii) if Elasticsearch is unable to provide such a correction within thirty (30) days of receipt of
|
||||
notice of the applicable non-conformity, promptly refund to Customer any pre-paid, unused fees paid by You to
|
||||
Elasticsearch for the applicable Subscription. The warranty set forth in this Section 3.1 does not apply if the
|
||||
applicable Software or any portion thereof: (a) has been altered, except by or on behalf Elasticsearch; (b) has not been
|
||||
used, installed, operated, repaired, or maintained in accordance with this Agreement and/or the Documentation; (c) has
|
||||
been subjected to abnormal physical or electrical stress, misuse, negligence, or accident; or (d) is used on equipment,
|
||||
products, or systems not meeting specifications identified by Elasticsearch in the Documentation. Additionally, the
|
||||
warranties set forth herein only apply when notice of a warranty claim is provided to Elasticsearch within the
|
||||
applicable warranty period specified herein and do not apply to any bug, defect or error caused by or attributable to
|
||||
software or hardware not supplied by Elasticsearch.
|
||||
3.2 Malicious Code. Elasticsearch represents and warrants that prior to making it available for delivery to You,
|
||||
Elasticsearch will use standard industry practices including, without limitation, the use of an updated commercial
|
||||
anti-virus program, to test the Software for Malicious Code and remove any Malicious Code it discovers. In the event of
|
||||
a breach of the foregoing warranty, Elasticsearch’s sole obligation, and Your exclusive remedy shall be for
|
||||
Elasticsearch to replace the Software with Software that does not contain any Malicious Code.
|
||||
3.3 Warranty Disclaimer. TO THE MAXIMUM EXTENT PERMITTED UNDER APPLICABLE LAW, THE SOFTWARE IS PROVIDED “AS IS” WITHOUT
|
||||
WARRANTY OF ANY KIND, AND ELASTICSEARCH AND ITS LICENSORS MAKE NO WARRANTIES WHETHER EXPRESSED, IMPLIED OR STATUTORY
|
||||
REGARDING OR RELATING TO THE SOFTWARE OR DOCUMENTATION. TO THE MAXIMUM EXTENT PERMITTED UNDER APPLICABLE LAW,
|
||||
ELASTICSEARCH AND ITS LICENSORS SPECIFICALLY DISCLAIM ALL IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
|
||||
PARTICULAR PURPOSE AND NON-INFRINGEMENT WITH RESPECT TO THE SOFTWARE AND DOCUMENTATION, AND WITH RESPECT TO THE USE OF
|
||||
THE FOREGOING. FURTHER, ELASTICSEARCH DOES NOT WARRANT RESULTS OF USE OR THAT THE SOFTWARE WILL BE ERROR FREE OR THAT
|
||||
THE USE OF THE SOFTWARE WILL BE UNINTERRUPTED.
|
||||
4. LIMITATION OF LIABILITY
|
||||
The provisions of this Section 4 apply if You have not purchased a Subscription. If you have purchased a Subscription,
|
||||
then the limitations of liability set forth in the applicable Subscription Agreement will apply in lieu of those set
|
||||
forth in this Section 4.
|
||||
4.1 Disclaimer of Certain Damages. IN NO EVENT SHALL YOU OR ELASTICSEARCH OR ITS LICENSORS BE LIABLE FOR ANY LOSS OF
|
||||
PROFITS, LOSS OF USE, BUSINESS INTERRUPTION, LOSS OF DATA, COST OF SUBSTITUTE GOODS OR SERVICES, OR FOR ANY INDIRECT,
|
||||
SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES OF ANY KIND IN CONNECTION WITH OR ARISING OUT OF THE USE OR INABILITY TO
|
||||
USE THE SOFTWARE, OR THE PERFORMANCE OF OR FAILURE TO PERFORM THIS AGREEMENT, WHETHER ALLEGED AS A BREACH OF CONTRACT OR
|
||||
TORTIOUS CONDUCT, INCLUDING NEGLIGENCE, EVEN IF THE RESPONSIBLE PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
|
||||
DAMAGES. THE LIMITATIONS OF LIABILITY SET FORTH IN THIS SECTION 4.1 SHALL NOT APPLY TO A BREACH THROUGH GROSS NEGLIGENCE
|
||||
OR INTENTIONAL MISCONDUCT BY YOU OF THE SCOPE OF THE LICENSE GRANTED IN SECTION 1.1 OR TO ANY OTHER LIABILITY THAT
|
||||
CANNOT BE EXCLUDED OR LIMITED UNDER APPLICABLE LAW.
|
||||
4.2 Damages Cap. IN NO EVENT SHALL ELASTICSEARCH’S OR ITS LICENSORS’ AGGREGATE, CUMULATIVE LIABILITY UNDER THIS
|
||||
AGREEMENT EXCEED ONE THOUSAND DOLLARS ($1,000).
|
||||
4.3 YOU AGREE THAT THE FOREGOING LIMITATIONS, EXCLUSIONS AND DISCLAIMERS ARE A REASONABLE ALLOCATION OF THE RISK BETWEEN
|
||||
THE PARTIES AND WILL APPLY TO THE MAXIMUM EXTENT PERMITTED BY APPLICABLE LAW, EVEN IF ANY REMEDY FAILS IN ITS ESSENTIAL
|
||||
PURPOSE.
|
||||
5. DEFINITIONS
|
||||
The following terms have the meanings ascribed:
|
||||
5.1 “License” means a limited, non-exclusive, non-transferable, fully paid up, right and license (without the right to
|
||||
grant or authorize sublicenses) solely for Your internal business operations to (i) install and use, in object code
|
||||
format, the applicable Eligible Features and Functions of the Software, (ii) use, and distribute internally a reasonable
|
||||
number of copies of the Documentation, provided that You must include on such copies all Marks and Notices; (iii) permit
|
||||
Contractors to use the Software and Documentation as set forth in (i) and (ii) above, provided that such use must be
|
||||
solely for Your benefit, and You shall be responsible for all acts and omissions of such Contractors in connection with
|
||||
their use of the Software that are contrary to the terms and conditions of this Agreement..
|
||||
5.2 “License Key” means an alphanumeric code that enables the Eligible Features and Functions of the Software.
|
||||
5.3 “Basic Version” means that version of the Software available for use without the purchase of a Qualifying
|
||||
Subscription, but which does require Registration.
|
||||
5.4 “Contractor” means third party contractors performing services on Your behalf.
|
||||
5.5 “Documentation” means the published end user documentation provided by Elasticsearch with the Software.
|
||||
5.6 “Eligible Features and Functions” means those features and functions of the Software that are eligible for use with
|
||||
respect to a particular version of the Software or level of the Subscription. A list of the Eligible Features and
|
||||
Functions that correspond to each version of the Software and Subscription levels may be found at
|
||||
https://www.elastic.co/subscriptions.
|
||||
5.7 “Malicious Code” means any code that is designed to harm, or otherwise disrupt in any unauthorized manner, the
|
||||
operation of a recipient’s computer programs or computer systems or destroy or damage recipient’s data. For clarity,
|
||||
Malicious Code shall not include any software bugs or errors handled through Support Services, or any standard features
|
||||
of functions of the Software and/or any License Key that are intended to enforce the temporal and other limitations on
|
||||
the scope of the use of the Software to the scope of the license purchased by You.
|
||||
5.8 “Marks and Notices” means all Elasticsearch trademarks, trade names, logos and notices present on the Documentation
|
||||
as originally provided by Elasticsearch.
|
||||
5.9 “Registration” means Elasticsearch’s then-current process under which You may register Your use of the Software with
|
||||
Elasticsearch by providing certain information to Elasticsearch regarding your use of the Software.
|
||||
5.10 “Subscription” means the right to receive Support Services and a License to the Software.
|
||||
5.11 “Subscription Term” means the period of time for which You have purchased a Subscription.
|
||||
5.12 “Trial Version” means that version of the Software available for use without the purchase of a Qualifying
|
||||
Subscription and without Registration.
|
||||
6. MISCELLANEOUS
|
||||
This Agreement, including Attachment 1 hereto, which is hereby incorporated herein by this reference, completely and
|
||||
exclusively states the entire agreement of the parties regarding the subject matter herein, and it supersedes, and its
|
||||
terms govern, all prior proposals, agreements, or other communications between the parties, oral or written, regarding
|
||||
such subject matter. For the avoidance of doubt, the parties hereby expressly acknowledge and agree that if You issue
|
||||
any purchase order or similar document in connection with its purchase of a license to the Software, You will do so only
|
||||
for Your internal, administrative purposes and not with the intent to provide any contractual terms. This Agreement may
|
||||
not be modified except by a subsequently dated, written amendment that expressly amends this Agreement and which is
|
||||
signed on behalf of Elasticsearch and You, by duly authorized representatives. If any provision hereof is held
|
||||
unenforceable, this Agreement will continue without said provision and be interpreted to reflect the original intent of
|
||||
the parties.
|
||||
|
||||
|
||||
ATTACHMENT 1
|
||||
ADDITIONAL TERMS AND CONDITIONS
|
||||
|
||||
A. The following additional terms and conditions apply to all Customers with principal offices in the United States
|
||||
of America:
|
||||
|
||||
(1) Applicable Elasticsearch Entity. The entity providing the license is Elasticsearch, Inc., a Delaware corporation.
|
||||
|
||||
(2) Government Rights. The Software product is "Commercial Computer Software," as that term is defined in 48 C.F.R.
|
||||
2.101, and as the term is used in 48 C.F.R. Part 12, and is a Commercial Item comprised of "commercial computer
|
||||
software" and "commercial computer software documentation". If acquired by or on behalf of a civilian agency, the U.S.
|
||||
Government acquires this commercial computer software and/or commercial computer software documentation subject to the
|
||||
terms of this Agreement, as specified in 48 C.F.R. 12.212 (Computer Software) and 12.211 (Technical Data) of the Federal
|
||||
Acquisition Regulation ("FAR") and its successors. If acquired by or on behalf of any agency within the Department of
|
||||
Defense ("DOD"), the U.S. Government acquires this commercial computer software and/or commercial computer software
|
||||
documentation subject to the terms of the Elasticsearch Software License Agreement as specified in 48 C.F.R. 227.7202-3
|
||||
and 48 C.F.R. 227.7202-4 of the DOD FAR Supplement ("DFARS") and its successors, and consistent with 48 C.F.R. 227.7202.
|
||||
This U.S. Government Rights clause, consistent with 48 C.F.R. 12.212 and 48 C.F.R. 227.7202 is in lieu of, and
|
||||
supersedes, any other FAR, DFARS, or other clause or provision that addresses Government rights in computer software,
|
||||
computer software documentation or technical data related to the Software under this Agreement and in any Subcontract
|
||||
under which this commercial computer software and commercial computer software documentation is acquired or licensed.
|
||||
|
||||
(3) Export Control. You acknowledge that the goods, software and technology acquired from Elasticsearch are subject
|
||||
to U.S. export control laws and regulations, including but not limited to the International Traffic In Arms Regulations
|
||||
(“ITAR”) (22 C.F.R. Parts 120-130 (2010)); the Export Administration Regulations ("EAR") (15 C.F.R. Parts 730-774
|
||||
(2010)); the U.S. antiboycott regulations in the EAR and U.S. Department of the Treasury regulations; the economic
|
||||
sanctions regulations and guidelines of the U.S. Department of the Treasury, Office of Foreign Assets Control, and the
|
||||
USA Patriot Act (Title III of Pub. L. 107-56, signed into law October 26, 2001), as amended. You are now and will
|
||||
remain in the future compliant with all such export control laws and regulations, and will not export, re-export,
|
||||
otherwise transfer any Elasticsearch goods, software or technology or disclose any Elasticsearch software or technology
|
||||
to any person contrary to such laws or regulations. You acknowledge that remote access to the Software may in certain
|
||||
circumstances be considered a re-export of Software, and accordingly, may not be granted in contravention of U.S. export
|
||||
control laws and regulations.
|
||||
(4) Governing Law, Jurisdiction and Venue.
|
||||
(a) Customers in California. If Customer is located in California (as determined by the Customer address on the
|
||||
applicable Order Form, or for a trial license under 1.1(a), the location of person who installed the Software), this
|
||||
Agreement will be governed by the laws of the State of California, without regard to its conflict of laws principles,
|
||||
and all suits hereunder will be brought solely in Federal Court for the Northern District of California, or if that
|
||||
court lacks subject matter jurisdiction, in any California State Court located in Santa Clara County.
|
||||
(b) Customers Outside of California. If Customer is located anywhere other than California (as determined by the
|
||||
Customer address on the applicable Order Form, or for a trial license under 1.1(a), the location of person who installed
|
||||
the Software), this Agreement will be governed by the laws of the State of Delaware, without regard to its conflict of
|
||||
laws principles, and all suits hereunder will be brought solely in Federal Court for the District of Delaware, or if
|
||||
that court lacks subject matter jurisdiction, in any Delaware State Court located in Wilmington, Delaware.
|
||||
(c) All Customers. This Agreement shall not be governed by the 1980 UN Convention on Contracts for the International
|
||||
Sale of Goods. The parties hereby irrevocably waive any and all claims and defenses either might otherwise have in any
|
||||
action or proceeding in any of the applicable courts set forth in (a) or (b) above, based upon any alleged lack of
|
||||
personal jurisdiction, improper venue, forum non conveniens, or any similar claim or defense.
|
||||
(d) Equitable Relief. A breach or threatened breach, by either party of Section 4 may cause irreparable harm for
|
||||
which the non-breaching party shall be entitled to seek injunctive relief without being required to post a bond.
|
||||
|
||||
B. The following additional terms and conditions apply to all Customers with principal offices in Canada:
|
||||
|
||||
(1) Applicable Elasticsearch Entity. The entity providing the license is Elasticsearch B.C. Ltd., a corporation
|
||||
incorporated under laws of the Province of British Columbia.
|
||||
|
||||
(2) Export Control. You acknowledge that the goods, software and technology acquired from Elasticsearch are subject
|
||||
to the restrictions and controls set out in Section A(3) above as well as those imposed by the Export and Import Permits
|
||||
Act (Canada) and the regulations thereunder and that you will comply with all applicable laws and regulations. Without
|
||||
limitation, You acknowledge that the Marvel Software, or any portion thereof, will not be exported: (a) to any country
|
||||
on Canada's Area Control List; (b) to any country subject to UN Security Council embargo or action; or (c) contrary to
|
||||
Canada's Export Control List Item 5505. You are now and will remain in the future compliant with all such export control
|
||||
laws and regulations, and will not export, re-export, otherwise transfer any Elasticsearch goods, software or technology
|
||||
or disclose any Elasticsearch software or technology to any person contrary to such laws or regulations. You will not
|
||||
export or re-export the Marvel Software, or any portion thereof, directly or indirectly, in violation of the Canadian
|
||||
export administration laws and regulations to any country or end user, or to any end user who you know or have reason to
|
||||
know will utilize them in the design, development or production of nuclear, chemical or biological weapons. You further
|
||||
acknowledge that the Marvel Software product may include technical data subject to such Canadian export regulations.
|
||||
Elasticsearch does not represent that the Marvel Software is appropriate or available for use in all countries.
|
||||
Elasticsearch prohibits accessing materials from countries or states where contents are illegal. You are using the
|
||||
Marvel Software on your own initiative and you are responsible for compliance with all applicable laws. You hereby agree
|
||||
to indemnify Elasticsearch and its affiliates from any claims, actions, liability or expenses (including reasonable
|
||||
lawyers' fees) resulting from Your failure to act in accordance with the acknowledgements, agreements, and
|
||||
representations in this Section B(2).
|
||||
(3) Governing Law and Dispute Resolution. This Agreement shall be governed by the Province of Ontario and the
|
||||
federal laws of Canada applicable therein without regard to conflict of laws provisions. The parties hereby irrevocably
|
||||
waive any and all claims and defenses either might otherwise have in any such action or proceeding in any of such courts
|
||||
based upon any alleged lack of personal jurisdiction, improper venue, forum non conveniens or any similar claim or
|
||||
defense. Any dispute, claim or controversy arising out of or relating to this Agreement or the existence, breach,
|
||||
termination, enforcement, interpretation or validity thereof, including the determination of the scope or applicability
|
||||
of this agreement to arbitrate, (each, a “Dispute”), which the parties are unable to resolve after good faith
|
||||
negotiations, shall be submitted first to the upper management level of the parties. The parties, through their upper
|
||||
management level representatives shall meet within thirty (30) days of the Dispute being referred to them and if the
|
||||
parties are unable to resolve such Dispute within thirty (30) days of meeting, the parties agree to seek to resolve the
|
||||
Dispute through mediation with ADR Chambers in the City of Toronto, Ontario, Canada before pursuing any other
|
||||
proceedings. The costs of the mediator shall be shared equally by the parties. If the Dispute has not been resolved
|
||||
within thirty (30) days of the notice to desire to mediate, any party may terminate the mediation and proceed to
|
||||
arbitration and the matter shall be referred to and finally resolved by arbitration at ADR Chambers pursuant to the
|
||||
general ADR Chambers Rules for Arbitration in the City of Toronto, Ontario, Canada. The arbitration shall proceed in
|
||||
accordance with the provisions of the Arbitration Act (Ontario). The arbitral panel shall consist of three (3)
|
||||
arbitrators, selected as follows: each party shall appoint one (1) arbitrator; and those two (2) arbitrators shall
|
||||
discuss and select a chairman. If the two (2) party-appointed arbitrators are unable to agree on the chairman, the
|
||||
chairman shall be selected in accordance with the applicable rules of the arbitration body. Each arbitrator shall be
|
||||
independent of each of the parties. The arbitrators shall have the authority to grant specific performance and to
|
||||
allocate between the parties the costs of arbitration (including service fees, arbitrator fees and all other fees
|
||||
related to the arbitration) in such equitable manner as the arbitrators may determine. The prevailing party in any
|
||||
arbitration shall be entitled to receive reimbursement of its reasonable expenses incurred in connection therewith.
|
||||
Judgment upon the award so rendered may be entered in a court having jurisdiction or application may be made to such
|
||||
court for judicial acceptance of any award and an order of enforcement, as the case may be. Notwithstanding the
|
||||
foregoing, Elasticsearch shall have the right to institute an action in a court of proper jurisdiction for preliminary
|
||||
injunctive relief pending a final decision by the arbitrator, provided that a permanent injunction and damages shall
|
||||
only be awarded by the arbitrator. The language to be used in the arbitral proceedings shall be English.
|
||||
(4) Language. Any translation of this Agreement is done for local requirements and in the event of a dispute
|
||||
between the English and any non-English version, the English version of this Agreement shall govern. At the request of
|
||||
the parties, the official language of this Agreement and all communications and documents relating hereto is the English
|
||||
language, and the English-language version shall govern all interpretation of the Agreement. À la demande des parties,
|
||||
la langue officielle de la présente convention ainsi que toutes communications et tous documents s'y rapportant est la
|
||||
langue anglaise, et la version anglaise est celle qui régit toute interprétation de la présente convention.
|
||||
(5) Warranty Disclaimer. For Customers with principal offices in the Province of Québec, the following new sentence
|
||||
is to be added to the end of Section 3.3: “SOME JURISDICTIONS DO NOT ALLOW LIMITATIONS OR EXCLUSIONS OF CERTAIN TYPES OF
|
||||
DAMAGES AND/OR WARRANTIES AND CONDITIONS. THE LIMITATIONS, EXCLUSIONS AND DISCLAIMERS SET FORTH IN THIS AGREEMENT SHALL
|
||||
NOT APPLY IF AND ONLY IF AND TO THE EXTENT THAT THE LAWS OF A COMPETENT JURISDICTION REQUIRE LIABILITIES BEYOND AND
|
||||
DESPITE THESE LIMITATIONS, EXCLUSIONS AND DISCLAIMERS.”
|
||||
(6) Limitation of Liability. For Customers with principal offices in the Province of Québec, the following new
|
||||
sentence is to be added to the end of Section 4.1: “SOME JURISDICTIONS DO NOT ALLOW LIMITATIONS OR EXCLUSIONS OF CERTAIN
|
||||
TYPES OF DAMAGES AND/OR WARRANTIES AND CONDITIONS. THE LIMITATIONS, EXCLUSIONS AND DISCLAIMERS SET FORTH IN THIS
|
||||
AGREEMENT SHALL NOT APPLY IF AND ONLY IF AND TO THE EXTENT THAT THE LAWS OF A COMPETENT JURISDICTION REQUIRE LIABILITIES
|
||||
BEYOND AND DESPITE THESE LIMITATIONS, EXCLUSIONS AND DISCLAIMERS.”
|
||||
|
||||
C. The following additional terms and conditions apply to all Customers with principal offices outside of the United
|
||||
States of America and Canada:
|
||||
|
||||
(1) Applicable Elasticsearch Entity. The entity providing the license in Germany is Elasticsearch Gmbh; in France is
|
||||
Elasticsearch SARL, in the United Kingdom is Elasticsearch Ltd, in Australia is Elasticsearch Pty Ltd., in Japan is
|
||||
Elasticsearch KK, in Sweden is Elasticsearch AB, in Norway is Elasticsearch AS and in all other countries is
|
||||
Elasticsearch BV.
|
||||
|
||||
(2) Choice of Law. This Agreement shall be governed by and construed in accordance with the laws of the State of New
|
||||
York, without reference to or application of choice of law rules or principles. Notwithstanding any choice of law
|
||||
provision or otherwise, the Uniform Computer Information Transactions Act (UCITA) and the United Nations Convention on
|
||||
the International Sale of Goods shall not apply.
|
||||
|
||||
(3) Arbitration. Any dispute, claim or controversy arising out of or relating to this Agreement or the existence,
|
||||
breach, termination, enforcement, interpretation or validity thereof, including the determination of the scope or
|
||||
applicability of this agreement to arbitrate, (each, a “Dispute”) shall be referred to and finally resolved by
|
||||
arbitration under the rules and at the location identified below. The arbitral panel shall consist of three (3)
|
||||
arbitrators, selected as follows: each party shall appoint one (1) arbitrator; and those two (2) arbitrators shall
|
||||
discuss and select a chairman. If the two party-appointed arbitrators are unable to agree on the chairman, the chairman
|
||||
shall be selected in accordance with the applicable rules of the arbitration body. Each arbitrator shall be independent
|
||||
of each of the parties. The arbitrators shall have the authority to grant specific performance and to allocate between
|
||||
the parties the costs of arbitration (including service fees, arbitrator fees and all other fees related to the
|
||||
arbitration) in such equitable manner as the arbitrators may determine. The prevailing party in any arbitration shall
|
||||
be entitled to receive reimbursement of its reasonable expenses incurred in connection therewith. Judgment upon the
|
||||
award so rendered may be entered in a court having jurisdiction or application may be made to such court for judicial
|
||||
acceptance of any award and an order of enforcement, as the case may be. Notwithstanding the foregoing, Elasticsearch
|
||||
shall have the right to institute an action in a court of proper jurisdiction for preliminary injunctive relief pending
|
||||
a final decision by the arbitrator, provided that a permanent injunction and damages shall only be awarded by the
|
||||
arbitrator. The language to be used in the arbitral proceedings shall be English.
|
||||
|
||||
In addition, the following terms only apply to Customers with principal offices within Europe, the Middle East or Africa
|
||||
(EMEA):
|
||||
|
||||
Arbitration Rules and Location. Any Dispute shall be referred to and finally resolved by arbitration under the London
|
||||
Court of International Arbitration (“LCIA”) Rules (which Rules are deemed to be incorporated by reference into this
|
||||
clause) on the basis that the governing law is the law of the State of New York, USA. The seat, or legal place, of
|
||||
arbitration shall be London, England.
|
||||
|
||||
(b) In addition, the following terms only apply to Customers with principal offices within Asia Pacific, Australia &
|
||||
New Zealand:
|
||||
|
||||
Arbitration Rules and Location. Any Dispute shall be referred to and finally resolved by arbitration under the Rules of
|
||||
Conciliation and Arbitration of the International Chamber of Commerce (“ICC”) in force on the date when the notice of
|
||||
arbitration is submitted in accordance with such Rules (which Rules are deemed to be incorporated by reference into this
|
||||
clause) on the basis that the governing law is the law of the State of New York, USA. The seat, or legal place, of
|
||||
arbitration shall be Singapore.
|
||||
|
||||
(c) In addition, the following terms only apply to Customers with principal offices within the Americas (excluding
|
||||
North America):
|
||||
|
||||
Arbitration Rules and Location. Any Dispute shall be referred to and finally resolved by arbitration under
|
||||
International Dispute Resolution Procedures of the American Arbitration Association (“AAA”) in force on the date when
|
||||
the notice of arbitration is submitted in accordance with such Procedures (which Procedures are deemed to be
|
||||
incorporated by reference into this clause) on the basis that the governing law is the law of the State of New York,
|
||||
USA. The seat, or legal place, of arbitration shall be New York, New York, USA.
|
||||
|
||||
(4) In addition, for Customers with principal offices within the UK, the following new sentence is added to the end
|
||||
of Section 4.1:
|
||||
|
||||
Nothing in this Agreement shall have effect so as to limit or exclude a party’s liability for death or personal injury
|
||||
caused by negligence or for fraud including fraudulent misrepresentation and this Section 4.1 shall take effect subject
|
||||
to this provision.
|
||||
|
||||
(5) In addition, for Customers with principal offices within France, Sections 1.2, 3 and 4.1 of the Agreement are
|
||||
deleted and replaced with the following new Sections 1.2, 3.3 and 4.1:
|
||||
1.2 Reservation of Rights; Restrictions. Elasticsearch owns all right title and interest in and to the Software and
|
||||
any derivative works thereof, and except as expressly set forth in Section 1.1 above, no other license to the Software
|
||||
is granted to You by implication, or otherwise. You agree not to prepare derivative works from, modify, copy or use the
|
||||
Software in any manner except as expressly permitted in this Agreement; provided that You may copy the Software for
|
||||
archival purposes, only where such software is provided on a non-durable medium; and You may decompile the Software,
|
||||
where necessary for interoperability purposes and where necessary for the correction of errors making the software unfit
|
||||
for its intended purpose, if such right is not reserved by Elasticsearch as editor of the Software. Pursuant to article
|
||||
L122-6-1 of the French intellectual property code, Elasticsearch reserves the right to correct any bugs as necessary for
|
||||
the Software to serve its intended purpose. You agree not to: (i) transfer, sell, rent, lease, distribute, sublicense,
|
||||
loan or otherwise transfer the Software in whole or in part to any third party; (ii) use the Software for providing
|
||||
time-sharing services, any software-as-a-service offering (“SaaS”), service bureau services or as part of an application
|
||||
services provider or other service offering; (iii) alter or remove any proprietary notices in the Software; or (iv) make
|
||||
available to any third party any analysis of the results of operation of the Software, including benchmarking results,
|
||||
without the prior written consent of Elasticsearch.
|
||||
3.3 Warranty Disclaimer. TO THE MAXIMUM EXTENT PERMITTED UNDER APPLICABLE LAW, THE SOFTWARE IS PROVIDED “AS IS”
|
||||
WITHOUT WARRANTY OF ANY KIND, AND ELASTICSEARCH AND ITS LICENSORS MAKE NO WARRANTIES WHETHER EXPRESSED, IMPLIED OR
|
||||
STATUTORY REGARDING OR RELATING TO THE SOFTWARE OR DOCUMENTATION. TO THE MAXIMUM EXTENT PERMITTED UNDER APPLICABLE LAW,
|
||||
ELASTICSEARCH AND ITS LICENSORS SPECIFICALLY DISCLAIM ALL IMPLIED WARRANTIES OF FITNESS FOR A PARTICULAR PURPOSE WITH
|
||||
RESPECT TO THE SOFTWARE AND DOCUMENTATION, AND WITH RESPECT TO THE USE OF THE FOREGOING. FURTHER, ELASTICSEARCH DOES
|
||||
NOT WARRANT RESULTS OF USE OR THAT THE SOFTWARE WILL BE ERROR FREE OR THAT THE USE OF THE SOFTWARE WILL BE
|
||||
UNINTERRUPTED.
|
||||
4.1 Disclaimer of Certain Damages. IN NO EVENT SHALL YOU OR ELASTICSEARCH OR ITS LICENSORS BE LIABLE FOR ANY LOSS OF
|
||||
PROFITS, LOSS OF USE, BUSINESS INTERRUPTION, LOSS OF DATA, COST OF SUBSTITUTE GOODS OR SERVICES, OR FOR ANY INDIRECT OR
|
||||
UNFORESEEABLE DAMAGES OF ANY KIND IN CONNECTION WITH OR ARISING OUT OF THE USE OR INABILITY TO USE THE SOFTWARE, OR THE
|
||||
PERFORMANCE OF OR FAILURE TO PERFORM THIS AGREEMENT, WHETHER ALLEGED AS A BREACH OF CONTRACT OR TORTIOUS CONDUCT,
|
||||
INCLUDING NEGLIGENCE. THE LIMITATIONS OF LIABILITY SET FORTH IN THIS SECTION 4.1 SHALL NOT APPLY TO A BREACH, THROUGH
|
||||
GROSS NEGLIGENCE OR INTENTIONAL MISCONDUCT BY YOU, OF THE SCOPE OF THE LICENSE GRANTED IN SECTION 1.1, OR IN CASE OF
|
||||
DEATH OR PERSONAL INJURY.
|
||||
(6) In addition, for Customers with principal offices within Australia, Sections 4.1, 4.2 and 4.3 of the Agreement
|
||||
are deleted and replaced with the following new Sections 4.1, 4.2 and 4.3:
|
||||
4.1 Disclaimer of Certain Damages. Subject to clause 4.3, a party is not liable for Consequential Loss however
|
||||
caused (including by the negligence of that party) suffered or incurred by the other party in connection with this
|
||||
agreement. “Consequential Loss” means loss of revenues, loss of reputation, indirect loss, loss of profits,
|
||||
consequential loss, loss of actual or anticipated savings, indirect loss, lost opportunities, including opportunities to
|
||||
enter into arrangements with third parties, loss or damage in connection with claims against by third parties, or loss
|
||||
or corruption or data.
|
||||
4.2 Damages Cap. SUBJECT TO CLAUSES 4.1 AND 4.3, ANY LIABILITY OF ELASTICSEARCH FOR ANY LOSS OR DAMAGE, HOWEVER
|
||||
CAUSED (INCLUDING BY THE NEGLIGENCE OF ELASTICSEARCH), SUFFERED BY YOU IN CONNECTION WITH THIS AGREEMENT IS LIMITED TO
|
||||
THE AMOUNT YOU PAID, IN THE TWELVE (12) MONTHS IMMEDIATELY PRIOR TO THE EVENT GIVING RISE TO LIABILITY, UNDER THE
|
||||
ELASTICSEARCH SUPPORT SERVICES AGREEMENT IN CONNECTION WITH WHICH YOU OBTAINED THE LICENSE TO USE THE SOFTWARE. THE
|
||||
LIMITATION SET OUT IN THIS SECTION 4.2 IS AN AGGREGATE LIMIT FOR ALL CLAIMS, WHENEVER MADE.
|
||||
4.3 Limitation and Disclaimer Exceptions. If the Competition and Consumer Act 2010 (Cth) or any other legislation or
|
||||
any other legislation states that there is a guarantee in relation to any good or service supplied by Elasticsearch in
|
||||
connection with this agreement, and Elasticsearch’s liability for failing to comply with that guarantee cannot be
|
||||
excluded but may be limited, Sections 4.1 and 4.2 do not apply to that liability and instead Elasticsearch’s liability
|
||||
for such failure is limited (at Elasticsearch’s election) to, in the case of a supply of goods, the Elasticsearch
|
||||
replacing the goods or supplying equivalent goods or repairing the goods, or in the case of a supply of services,
|
||||
Elasticsearch supplying the services again or paying the cost of having the services supplied again.
|
||||
(7) In addition, for Customers with principal offices within Japan, Sections 1.2, 3 and 4.1 of the Agreement are
|
||||
deleted and replaced with the following new Sections 1.2, 3.3 and 4.1:
|
||||
1.2 Reservation of Rights; Restrictions. As between Elasticsearch and You, Elasticsearch owns all right title and
|
||||
interest in and to the Software and any derivative works thereof, and except as expressly set forth in Section 1.1
|
||||
above, no other license to the Software is granted to You by implication or otherwise. You agree not to: (i) prepare
|
||||
derivative works from, modify, copy or use the Software in any manner except as expressly permitted in this Agreement or
|
||||
applicable law; (ii) transfer, sell, rent, lease, distribute, sublicense, loan or otherwise transfer the Software in
|
||||
whole or in part to any third party; (iii) use the Software for providing time-sharing services, any
|
||||
software-as-a-service offering (“SaaS”), service bureau services or as part of an application services provider or other
|
||||
service offering; (iv) alter or remove any proprietary notices in the Software; or (v) make available to any third party
|
||||
any analysis of the results of operation of the Software, including benchmarking results, without the prior written
|
||||
consent of Elasticsearch.
|
||||
3.3 Warranty Disclaimer. TO THE MAXIMUM EXTENT PERMITTED UNDER APPLICABLE LAW, THE SOFTWARE IS PROVIDED “AS IS”
|
||||
WITHOUT WARRANTY OF ANY KIND, AND ELASTICSEARCH AND ITS LICENSORS MAKE NO WARRANTIES WHETHER EXPRESSED, IMPLIED OR
|
||||
STATUTORY REGARDING OR RELATING TO THE SOFTWARE OR DOCUMENTATION. TO THE MAXIMUM EXTENT PERMITTED UNDER APPLICABLE LAW,
|
||||
ELASTICSEARCH AND ITS LICENSORS SPECIFICALLY DISCLAIM ALL IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
|
||||
PARTICULAR PURPOSE AND NON-INFRINGEMENT WITH RESPECT TO THE SOFTWARE AND DOCUMENTATION, AND WITH RESPECT TO THE USE OF
|
||||
THE FOREGOING. FURTHER, ELASTICSEARCH DOES NOT WARRANT RESULTS OF USE OR THAT THE SOFTWARE WILL BE ERROR FREE OR THAT
|
||||
THE USE OF THE SOFTWARE WILL BE UNINTERRUPTED.
|
||||
4.1 Disclaimer of Certain Damages. IN NO EVENT SHALL YOU OR ELASTICSEARCH OR ITS LICENSORS BE LIABLE FOR ANY LOSS OF
|
||||
PROFITS, LOSS OF USE, BUSINESS INTERRUPTION, LOSS OF DATA, COST OF SUBSTITUTE GOODS OR SERVICES, OR FOR ANY
|
||||
SPECIALINDIRECT, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES OF ANY KIND IN CONNECTION WITH OR ARISING OUT OF THE USE
|
||||
OR INABILITY TO USE THE SOFTWARE, OR THE PERFORMANCE OF OR FAILURE TO PERFORM THIS AGREEMENT, WHETHER ALLEGED AS A
|
||||
BREACH OF CONTRACT OR TORTIOUS CONDUCT, INCLUDING NEGLIGENCE, EVEN IF THE RESPONSIBLE PARTY HAS BEEN ADVISED OF THE
|
||||
POSSIBILITY OF SUCH DAMAGES. THE LIMITATIONS OF LIABILITY SET FORTH IN THIS SECTION 4.1 SHALL NOT APPLY TO A BREACH
|
||||
THROUGH GROSS NEGLIGENCE OR INTENTIONAL MISCONDUCT BY YOU OF THE SCOPE OF THE LICENSE GRANTED IN SECTION 1.1 OR TO ANY
|
||||
OTHER LIABILITY THAT CANNOT BE EXCLUDED OR LIMITED UNDER APPLICABLE LAW.
|
|
@ -1,6 +0,0 @@
|
|||
Elasticsearch License
|
||||
Copyright 2009-2015 Elastic
|
||||
|
||||
---
|
||||
This product includes software developed by The Apache Software
|
||||
Foundation (http://www.apache.org/).
|
|
@ -0,0 +1,22 @@
|
|||
/*
|
||||
* 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.common.network;
|
||||
|
||||
import java.net.InetAddress;
|
||||
import java.net.SocketException;
|
||||
|
||||
/**
|
||||
* We use this class to access the package private method in NetworkUtils to resolve anyLocalAddress InetAddresses for certificate
|
||||
* generation
|
||||
*/
|
||||
public class InetAddressHelper {
|
||||
|
||||
private InetAddressHelper() {}
|
||||
|
||||
public static InetAddress[] getAllAddresses() throws SocketException {
|
||||
return NetworkUtils.getAllAddresses();
|
||||
}
|
||||
}
|
|
@ -74,8 +74,8 @@ import org.elasticsearch.shield.rest.action.user.RestDeleteUserAction;
|
|||
import org.elasticsearch.shield.rest.action.user.RestGetUsersAction;
|
||||
import org.elasticsearch.shield.rest.action.user.RestPutUserAction;
|
||||
import org.elasticsearch.shield.ssl.SSLModule;
|
||||
import org.elasticsearch.shield.ssl.SSLSettings;
|
||||
import org.elasticsearch.shield.support.OptionalStringSetting;
|
||||
import org.elasticsearch.shield.ssl.SSLConfiguration;
|
||||
import org.elasticsearch.shield.support.OptionalSettings;
|
||||
import org.elasticsearch.shield.transport.ShieldClientTransportService;
|
||||
import org.elasticsearch.shield.transport.ShieldServerTransportService;
|
||||
import org.elasticsearch.shield.transport.ShieldTransportModule;
|
||||
|
@ -106,7 +106,7 @@ public class Security {
|
|||
public static final String NAME = "security";
|
||||
public static final String DLS_FLS_FEATURE = "security.dls_fls";
|
||||
public static final String OPT_OUT_QUERY_CACHE = "opt_out_cache";
|
||||
public static final Setting<Optional<String>> USER_SETTING = OptionalStringSetting.create(setting("user"), Property.NodeScope);
|
||||
public static final Setting<Optional<String>> USER_SETTING = OptionalSettings.createString(setting("user"), Property.NodeScope);
|
||||
|
||||
private final Settings settings;
|
||||
private final boolean enabled;
|
||||
|
@ -170,7 +170,6 @@ public class Security {
|
|||
list.add(FileRolesStore.class);
|
||||
list.add(Realms.class);
|
||||
return list;
|
||||
|
||||
}
|
||||
|
||||
public Settings additionalSettings() {
|
||||
|
@ -193,7 +192,7 @@ public class Security {
|
|||
settingsModule.registerSetting(USER_SETTING);
|
||||
|
||||
// SSL settings
|
||||
SSLSettings.registerSettings(settingsModule);
|
||||
SSLConfiguration.Global.registerSettings(settingsModule);
|
||||
|
||||
// transport settings
|
||||
ShieldNettyTransport.registerSettings(settingsModule);
|
||||
|
|
|
@ -147,7 +147,7 @@ public abstract class SessionFactory {
|
|||
protected ServerSet serverSet(Settings settings, ClientSSLService clientSSLService, LDAPServers ldapServers) {
|
||||
SocketFactory socketFactory = null;
|
||||
if (ldapServers.ssl()) {
|
||||
socketFactory = clientSSLService.sslSocketFactory();
|
||||
socketFactory = clientSSLService.sslSocketFactory(settings.getByPrefix("ssl."));
|
||||
if (settings.getAsBoolean(HOSTNAME_VERIFICATION_SETTING, true)) {
|
||||
logger.debug("using encryption for LDAP connections with hostname verification");
|
||||
} else {
|
||||
|
|
|
@ -11,24 +11,24 @@ import org.elasticsearch.common.component.AbstractComponent;
|
|||
import org.elasticsearch.common.settings.Settings;
|
||||
import org.elasticsearch.common.unit.TimeValue;
|
||||
import org.elasticsearch.env.Environment;
|
||||
import org.elasticsearch.shield.ssl.SSLConfiguration.Custom;
|
||||
import org.elasticsearch.shield.ssl.SSLConfiguration.Global;
|
||||
import org.elasticsearch.shield.ssl.TrustConfig.Reloadable.Listener;
|
||||
import org.elasticsearch.watcher.ResourceWatcherService;
|
||||
|
||||
import javax.net.ssl.KeyManager;
|
||||
import javax.net.ssl.KeyManagerFactory;
|
||||
import javax.net.ssl.SSLContext;
|
||||
import javax.net.ssl.SSLEngine;
|
||||
import javax.net.ssl.SSLSessionContext;
|
||||
import javax.net.ssl.SSLSocket;
|
||||
import javax.net.ssl.SSLSocketFactory;
|
||||
import javax.net.ssl.TrustManager;
|
||||
import javax.net.ssl.TrustManagerFactory;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.net.InetAddress;
|
||||
import java.net.Socket;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.security.KeyStore;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Enumeration;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
@ -39,34 +39,41 @@ import java.util.concurrent.ConcurrentHashMap;
|
|||
*/
|
||||
public abstract class AbstractSSLService extends AbstractComponent {
|
||||
|
||||
private final ConcurrentHashMap<SSLSettings, SSLContext> sslContexts = new ConcurrentHashMap<>();
|
||||
private final ConcurrentHashMap<SSLConfiguration, SSLContext> sslContexts = new ConcurrentHashMap<>();
|
||||
private final SSLContextCacheLoader cacheLoader = new SSLContextCacheLoader();
|
||||
protected Environment env;
|
||||
|
||||
public AbstractSSLService(Settings settings, Environment environment) {
|
||||
protected SSLConfiguration globalSSLConfiguration;
|
||||
protected Environment env;
|
||||
protected ResourceWatcherService resourceWatcherService;
|
||||
|
||||
public AbstractSSLService(Settings settings, Environment environment, Global globalSSLConfiguration,
|
||||
ResourceWatcherService resourceWatcherService) {
|
||||
super(settings);
|
||||
this.env = environment;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return A SSLSocketFactory (for client-side SSL handshaking)
|
||||
*/
|
||||
public SSLSocketFactory sslSocketFactory() {
|
||||
SSLSocketFactory socketFactory = sslContext().getSocketFactory();
|
||||
return new ShieldSSLSocketFactory(socketFactory, supportedProtocols(), supportedCiphers(socketFactory.getSupportedCipherSuites(),
|
||||
ciphers()));
|
||||
this.globalSSLConfiguration = globalSSLConfiguration;
|
||||
this.resourceWatcherService = resourceWatcherService;
|
||||
}
|
||||
|
||||
public String[] supportedProtocols() {
|
||||
return SSLSettings.Globals.SUPPORTED_PROTOCOLS_SETTING.get(settings).toArray(Strings.EMPTY_ARRAY);
|
||||
return globalSSLConfiguration.supportedProtocols().toArray(Strings.EMPTY_ARRAY);
|
||||
}
|
||||
|
||||
public String[] ciphers() {
|
||||
return SSLSettings.Globals.CIPHERS_SETTING.get(settings).toArray(Strings.EMPTY_ARRAY);
|
||||
return globalSSLConfiguration.ciphers().toArray(Strings.EMPTY_ARRAY);
|
||||
}
|
||||
|
||||
public SSLSocketFactory sslSocketFactory(Settings settings) {
|
||||
return sslSocketFactory(sslContext(settings));
|
||||
}
|
||||
|
||||
protected SSLSocketFactory sslSocketFactory(SSLContext sslContext) {
|
||||
SSLSocketFactory socketFactory = sslContext.getSocketFactory();
|
||||
return new ShieldSSLSocketFactory(socketFactory, supportedProtocols(),
|
||||
supportedCiphers(socketFactory.getSupportedCipherSuites(), ciphers(), false));
|
||||
}
|
||||
|
||||
public SSLEngine createSSLEngine() {
|
||||
return createSSLEngine(Settings.EMPTY);
|
||||
return createSSLEngine(globalSSLConfiguration, null, -1);
|
||||
}
|
||||
|
||||
public SSLEngine createSSLEngine(Settings settings) {
|
||||
|
@ -74,28 +81,46 @@ public abstract class AbstractSSLService extends AbstractComponent {
|
|||
}
|
||||
|
||||
public SSLEngine createSSLEngine(Settings settings, String host, int port) {
|
||||
String[] ciphers = SSLSettings.Globals.CIPHERS_SETTING.get(settings, this.settings).toArray(Strings.EMPTY_ARRAY);
|
||||
String[] supportedProtocols = SSLSettings.Globals.SUPPORTED_PROTOCOLS_SETTING.get(settings, this.settings)
|
||||
.toArray(Strings.EMPTY_ARRAY);
|
||||
return createSSLEngine(sslContext(settings), ciphers, supportedProtocols, host, port);
|
||||
if (settings.isEmpty()) {
|
||||
return createSSLEngine(globalSSLConfiguration, host, port);
|
||||
}
|
||||
return createSSLEngine(sslConfiguration(settings), host, port);
|
||||
}
|
||||
|
||||
public SSLEngine createSSLEngine(SSLConfiguration configuration, String host, int port) {
|
||||
return createSSLEngine(sslContext(configuration),
|
||||
configuration.ciphers().toArray(Strings.EMPTY_ARRAY),
|
||||
configuration.supportedProtocols().toArray(Strings.EMPTY_ARRAY),
|
||||
host, port);
|
||||
}
|
||||
|
||||
public SSLContext sslContext() {
|
||||
return sslContext(Settings.EMPTY);
|
||||
return sslContext(globalSSLConfiguration);
|
||||
}
|
||||
|
||||
protected SSLContext sslContext(Settings settings) {
|
||||
SSLSettings sslSettings = sslSettings(settings);
|
||||
return sslContexts.computeIfAbsent(sslSettings, (theSettings) ->
|
||||
cacheLoader.load(theSettings));
|
||||
public SSLContext sslContext(Settings settings) {
|
||||
if (settings.isEmpty()) {
|
||||
return sslContext();
|
||||
}
|
||||
|
||||
SSLConfiguration sslConfiguration = sslConfiguration(settings);
|
||||
return sslContext(sslConfiguration);
|
||||
}
|
||||
|
||||
protected abstract SSLSettings sslSettings(Settings customSettings);
|
||||
protected SSLContext sslContext(SSLConfiguration sslConfiguration) {
|
||||
return sslContexts.computeIfAbsent(sslConfiguration, cacheLoader::load);
|
||||
}
|
||||
|
||||
protected SSLConfiguration sslConfiguration(Settings customSettings) {
|
||||
return new Custom(customSettings, globalSSLConfiguration);
|
||||
}
|
||||
|
||||
protected abstract void validateSSLConfiguration(SSLConfiguration configuration);
|
||||
|
||||
SSLEngine createSSLEngine(SSLContext sslContext, String[] ciphers, String[] supportedProtocols, String host, int port) {
|
||||
SSLEngine sslEngine = sslContext.createSSLEngine(host, port);
|
||||
try {
|
||||
sslEngine.setEnabledCipherSuites(supportedCiphers(sslEngine.getSupportedCipherSuites(), ciphers));
|
||||
sslEngine.setEnabledCipherSuites(supportedCiphers(sslEngine.getSupportedCipherSuites(), ciphers, false));
|
||||
} catch (ElasticsearchException e) {
|
||||
throw e;
|
||||
} catch (Throwable t) {
|
||||
|
@ -110,7 +135,7 @@ public abstract class AbstractSSLService extends AbstractComponent {
|
|||
return sslEngine;
|
||||
}
|
||||
|
||||
String[] supportedCiphers(String[] supportedCiphers, String[] requestedCiphers) {
|
||||
String[] supportedCiphers(String[] supportedCiphers, String[] requestedCiphers, boolean log) {
|
||||
List<String> requestedCiphersList = new ArrayList<>(requestedCiphers.length);
|
||||
List<String> unsupportedCiphers = new LinkedList<>();
|
||||
boolean found;
|
||||
|
@ -130,58 +155,36 @@ public abstract class AbstractSSLService extends AbstractComponent {
|
|||
}
|
||||
|
||||
if (requestedCiphersList.isEmpty()) {
|
||||
throw new IllegalArgumentException("none of the ciphers [" + Arrays.asList(requestedCiphers) + "] are supported by this JVM");
|
||||
throw new IllegalArgumentException("none of the ciphers " + Arrays.asList(requestedCiphers) + " are supported by this JVM");
|
||||
}
|
||||
|
||||
if (!unsupportedCiphers.isEmpty()) {
|
||||
logger.error("unsupported ciphers [{}] were requested but cannot be used in this JVM. If you are trying to use ciphers\n" +
|
||||
"with a key length greater than 128 bits on an Oracle JVM, you will need to install the unlimited strength\n" +
|
||||
"JCE policy files. Additionally, please ensure the PKCS11 provider is enabled for your JVM.", unsupportedCiphers);
|
||||
if (log && !unsupportedCiphers.isEmpty()) {
|
||||
logger.error("unsupported ciphers [{}] were requested but cannot be used in this JVM, however there are supported ciphers " +
|
||||
"that will be used [{}]. If you are trying to use ciphers with a key length greater than 128 bits on an Oracle JVM, " +
|
||||
"you will need to install the unlimited strength JCE policy files.", unsupportedCiphers, requestedCiphersList);
|
||||
}
|
||||
|
||||
return requestedCiphersList.toArray(new String[requestedCiphersList.size()]);
|
||||
}
|
||||
|
||||
protected Path resolvePath(String location) {
|
||||
return env.configFile().resolve(location);
|
||||
}
|
||||
|
||||
private class SSLContextCacheLoader {
|
||||
|
||||
public SSLContext load(SSLSettings sslSettings) {
|
||||
public SSLContext load(SSLConfiguration sslConfiguration) {
|
||||
validateSSLConfiguration(sslConfiguration);
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("using keystore[{}], key_algorithm[{}], truststore[{}], truststore_algorithm[{}], tls_protocol[{}], " +
|
||||
"session_cache_size[{}], session_cache_timeout[{}]",
|
||||
sslSettings.keyStorePath, sslSettings.keyStoreAlgorithm, sslSettings.trustStorePath,
|
||||
sslSettings.trustStoreAlgorithm, sslSettings.sslProtocol, sslSettings.sessionCacheSize,
|
||||
sslSettings.sessionCacheTimeout);
|
||||
logger.debug("using ssl settings [{}]", sslConfiguration);
|
||||
}
|
||||
|
||||
TrustManager[] trustManagers = trustManagers(sslSettings.trustStorePath, sslSettings.trustStorePassword,
|
||||
sslSettings.trustStoreAlgorithm);
|
||||
KeyManager[] keyManagers = keyManagers(sslSettings.keyStorePath, sslSettings.keyStorePassword, sslSettings.keyStoreAlgorithm,
|
||||
sslSettings.keyPassword);
|
||||
return createSslContext(keyManagers, trustManagers, sslSettings.sslProtocol, sslSettings.sessionCacheSize,
|
||||
sslSettings.sessionCacheTimeout);
|
||||
}
|
||||
ConfigRefreshListener configRefreshListener = new ConfigRefreshListener(sslConfiguration);
|
||||
TrustManager[] trustManagers = sslConfiguration.trustConfig().trustManagers(env, resourceWatcherService, configRefreshListener);
|
||||
KeyManager[] keyManagers = sslConfiguration.keyConfig().keyManagers(env, resourceWatcherService, configRefreshListener);
|
||||
SSLContext sslContext = createSslContext(keyManagers, trustManagers, sslConfiguration.protocol(),
|
||||
sslConfiguration.sessionCacheSize(), sslConfiguration.sessionCacheTimeout());
|
||||
|
||||
|
||||
private KeyManager[] keyManagers(String keyStore, String keyStorePassword, String keyStoreAlgorithm, String keyPassword) {
|
||||
if (keyStore == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
try {
|
||||
// Load KeyStore
|
||||
KeyStore ks = readKeystore(keyStore, keyStorePassword);
|
||||
|
||||
// Initialize KeyManagerFactory
|
||||
KeyManagerFactory kmf = KeyManagerFactory.getInstance(keyStoreAlgorithm);
|
||||
kmf.init(ks, keyPassword.toCharArray());
|
||||
return kmf.getKeyManagers();
|
||||
} catch (Exception e) {
|
||||
throw new ElasticsearchException("failed to initialize a KeyManagerFactory", e);
|
||||
}
|
||||
// check the supported ciphers and log them here
|
||||
supportedCiphers(sslContext.getSupportedSSLParameters().getCipherSuites(),
|
||||
sslConfiguration.ciphers().toArray(Strings.EMPTY_ARRAY), true);
|
||||
return sslContext;
|
||||
}
|
||||
|
||||
private SSLContext createSslContext(KeyManager[] keyManagers, TrustManager[] trustManagers, String sslProtocol,
|
||||
|
@ -197,34 +200,37 @@ public abstract class AbstractSSLService extends AbstractComponent {
|
|||
throw new ElasticsearchException("failed to initialize the SSLContext", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private TrustManager[] trustManagers(String trustStorePath, String trustStorePassword, String trustStoreAlgorithm) {
|
||||
try {
|
||||
// Load TrustStore
|
||||
KeyStore ks = null;
|
||||
if (trustStorePath != null) {
|
||||
ks = readKeystore(trustStorePath, trustStorePassword);
|
||||
}
|
||||
class ConfigRefreshListener implements Listener {
|
||||
|
||||
// Initialize a trust manager factory with the trusted store
|
||||
TrustManagerFactory trustFactory = TrustManagerFactory.getInstance(trustStoreAlgorithm);
|
||||
trustFactory.init(ks);
|
||||
return trustFactory.getTrustManagers();
|
||||
} catch (Exception e) {
|
||||
throw new ElasticsearchException("failed to initialize a TrustManagerFactory", e);
|
||||
private final SSLConfiguration sslConfiguration;
|
||||
|
||||
ConfigRefreshListener(SSLConfiguration sslConfiguration) {
|
||||
this.sslConfiguration = sslConfiguration;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onReload() {
|
||||
SSLContext context = sslContexts.get(sslConfiguration);
|
||||
if (context != null) {
|
||||
invalidateSessions(context.getClientSessionContext());
|
||||
invalidateSessions(context.getServerSessionContext());
|
||||
}
|
||||
}
|
||||
|
||||
private KeyStore readKeystore(String path, String password) throws Exception {
|
||||
try (InputStream in = Files.newInputStream(resolvePath(path))) {
|
||||
// Load TrustStore
|
||||
KeyStore ks = KeyStore.getInstance("jks");
|
||||
assert password != null;
|
||||
ks.load(in, password.toCharArray());
|
||||
return ks;
|
||||
void invalidateSessions(SSLSessionContext sslSessionContext) {
|
||||
Enumeration<byte[]> sessionIds = sslSessionContext.getIds();
|
||||
while (sessionIds.hasMoreElements()) {
|
||||
byte[] sessionId = sessionIds.nextElement();
|
||||
sslSessionContext.getSession(sessionId).invalidate();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onFailure(Exception e) {
|
||||
logger.error("failed to load updated ssl context for [{}]", e, sslConfiguration);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -0,0 +1,222 @@
|
|||
/*
|
||||
* 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.shield.ssl;
|
||||
|
||||
import org.elasticsearch.ElasticsearchException;
|
||||
import org.elasticsearch.common.Nullable;
|
||||
import org.elasticsearch.common.logging.ESLogger;
|
||||
import org.elasticsearch.common.util.set.Sets;
|
||||
import org.elasticsearch.env.Environment;
|
||||
|
||||
import javax.net.ssl.SSLEngine;
|
||||
import javax.net.ssl.X509ExtendedKeyManager;
|
||||
import javax.net.ssl.X509ExtendedTrustManager;
|
||||
import java.io.InputStream;
|
||||
import java.io.InputStreamReader;
|
||||
import java.io.Reader;
|
||||
import java.net.InetAddress;
|
||||
import java.net.Socket;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.nio.file.Path;
|
||||
import java.security.KeyPair;
|
||||
import java.security.Principal;
|
||||
import java.security.PrivateKey;
|
||||
import java.security.cert.Certificate;
|
||||
import java.security.cert.CertificateException;
|
||||
import java.security.cert.CertificateFactory;
|
||||
import java.security.cert.X509Certificate;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
*/
|
||||
class AutoGeneratedKeyConfig extends KeyConfig {
|
||||
|
||||
private static final char[] PASSWORD = "changeme".toCharArray();
|
||||
|
||||
private final Set<InetAddress> certificateAddresses = new HashSet<>();
|
||||
private final X509ExtendedKeyManager[] keyManagers;
|
||||
private final X509ExtendedTrustManager[] trustManagers;
|
||||
private final KeyPair keyPair;
|
||||
private final Certificate caCert;
|
||||
private final Exception failure;
|
||||
|
||||
private boolean certGenerated = false;
|
||||
|
||||
AutoGeneratedKeyConfig(boolean includeSystem) {
|
||||
super(includeSystem, false);
|
||||
Exception thrown = null;
|
||||
X509ExtendedTrustManager trustManager;
|
||||
Certificate caCert = null;
|
||||
KeyPair keyPair = null;
|
||||
try {
|
||||
keyPair = CertUtils.generateKeyPair();
|
||||
caCert = readCACert();
|
||||
X509ExtendedTrustManager[] managers = CertUtils.trustManagers(new Certificate[] { caCert });
|
||||
trustManager = managers[0];
|
||||
} catch (Exception e) {
|
||||
thrown = e;
|
||||
trustManager = new EmptyX509TrustManager();
|
||||
}
|
||||
|
||||
this.failure = thrown;
|
||||
this.caCert = caCert;
|
||||
this.keyPair = keyPair;
|
||||
this.keyManagers = new X509ExtendedKeyManager[] { new ReloadableX509KeyManager(new EmptyX509KeyManager(), null) };
|
||||
this.trustManagers = new X509ExtendedTrustManager[] { new ReloadableTrustManager(trustManager, null) };
|
||||
}
|
||||
|
||||
@Override
|
||||
X509ExtendedKeyManager[] loadKeyManagers(@Nullable Environment environment) {
|
||||
return keyManagers;
|
||||
}
|
||||
|
||||
@Override
|
||||
X509ExtendedTrustManager[] nonSystemTrustManagers(@Nullable Environment environment) {
|
||||
return trustManagers;
|
||||
}
|
||||
|
||||
@Override
|
||||
void validate() {
|
||||
if (failure != null) {
|
||||
throw new ElasticsearchException("failed to auto generate keypair and read CA cert", failure);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
List<Path> filesToMonitor(@Nullable Environment environment) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "AutoGeneratedKeyConfig";
|
||||
}
|
||||
|
||||
synchronized void generateCertIfNecessary(boolean resolveHostnames, String nodeName, Set<InetAddress> addresses, ESLogger logger)
|
||||
throws Exception {
|
||||
if (failure != null) {
|
||||
throw new ElasticsearchException("failed to auto generate keypair and read CA cert", failure);
|
||||
}
|
||||
|
||||
// we shouldn't regenerate if we have no new addresses
|
||||
if (certGenerated && Sets.difference(addresses, certificateAddresses).isEmpty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.certificateAddresses.addAll(addresses);
|
||||
final PrivateKey caPrivateKey = readCAPrivateKey();
|
||||
final X509Certificate signedCert =
|
||||
CertUtils.generateSignedCertificate(resolveHostnames, nodeName, certificateAddresses, keyPair, caCert, caPrivateKey);
|
||||
Certificate[] certChain = new Certificate[] { signedCert, caCert };
|
||||
X509ExtendedKeyManager[] keyManagers = CertUtils.keyManagers(certChain, keyPair.getPrivate(), PASSWORD);
|
||||
X509ExtendedTrustManager[] trustManagers = CertUtils.trustManagers(certChain);
|
||||
((ReloadableX509KeyManager) this.keyManagers[0]).setKeyManager(keyManagers[0]);
|
||||
((ReloadableTrustManager) this.trustManagers[0]).setTrustManager(trustManagers[0]);
|
||||
this.certGenerated = true;
|
||||
logMessages(signedCert, logger);
|
||||
}
|
||||
|
||||
static Certificate readCACert() throws Exception {
|
||||
try (InputStream inputStream = AutoGeneratedKeyConfig.class.getResourceAsStream("/cacert.pem");
|
||||
Reader reader = new InputStreamReader(inputStream, StandardCharsets.UTF_8)) {
|
||||
CertificateFactory certificateFactory = CertificateFactory.getInstance("X.509");
|
||||
List<Certificate> certificateList = new ArrayList<>(1);
|
||||
CertUtils.readCertificates(reader, certificateList, certificateFactory);
|
||||
if (certificateList.size() != 1) {
|
||||
throw new IllegalStateException("expected [1] default CA certificate but found [" + certificateList.size() + "]");
|
||||
}
|
||||
return certificateList.get(0);
|
||||
}
|
||||
}
|
||||
|
||||
static PrivateKey readCAPrivateKey() throws Exception {
|
||||
try (InputStream inputStream = AutoGeneratedKeyConfig.class.getResourceAsStream("/cakey.pem");
|
||||
Reader reader = new InputStreamReader(inputStream, StandardCharsets.UTF_8)) {
|
||||
return CertUtils.readPrivateKey(reader, PASSWORD);
|
||||
}
|
||||
}
|
||||
|
||||
static void logMessages(X509Certificate signedCert, ESLogger logger) {
|
||||
logger.info("auto generated a X.509 certificate and private/public key pair for SSL use. this should never be used in production " +
|
||||
"as the signing certificate authority is the same for every installation of X-Pack.{}generated certificate:{}{}",
|
||||
System.lineSeparator(), System.lineSeparator(), signedCert.toString());
|
||||
}
|
||||
|
||||
private static class EmptyX509KeyManager extends X509ExtendedKeyManager {
|
||||
|
||||
@Override
|
||||
public String[] getClientAliases(String s, Principal[] principals) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String chooseClientAlias(String[] strings, Principal[] principals, Socket socket) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String[] getServerAliases(String s, Principal[] principals) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String chooseServerAlias(String s, Principal[] principals, Socket socket) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public X509Certificate[] getCertificateChain(String s) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public PrivateKey getPrivateKey(String s) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
private static class EmptyX509TrustManager extends X509ExtendedTrustManager {
|
||||
|
||||
@Override
|
||||
public void checkClientTrusted(X509Certificate[] x509Certificates, String s, Socket socket) throws CertificateException {
|
||||
throw new CertificateException("trust nothing");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void checkServerTrusted(X509Certificate[] x509Certificates, String s, Socket socket) throws CertificateException {
|
||||
throw new CertificateException("trust nothing");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void checkClientTrusted(X509Certificate[] x509Certificates, String s, SSLEngine sslEngine) throws CertificateException {
|
||||
throw new CertificateException("trust nothing");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void checkServerTrusted(X509Certificate[] x509Certificates, String s, SSLEngine sslEngine) throws CertificateException {
|
||||
throw new CertificateException("trust nothing");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void checkClientTrusted(X509Certificate[] x509Certificates, String s) throws CertificateException {
|
||||
throw new CertificateException("trust nothing");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void checkServerTrusted(X509Certificate[] x509Certificates, String s) throws CertificateException {
|
||||
throw new CertificateException("trust nothing");
|
||||
}
|
||||
|
||||
@Override
|
||||
public X509Certificate[] getAcceptedIssuers() {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,263 @@
|
|||
/*
|
||||
* 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.shield.ssl;
|
||||
|
||||
import org.bouncycastle.asn1.pkcs.PrivateKeyInfo;
|
||||
import org.bouncycastle.asn1.x500.X500Name;
|
||||
import org.bouncycastle.asn1.x509.Extension;
|
||||
import org.bouncycastle.asn1.x509.GeneralName;
|
||||
import org.bouncycastle.asn1.x509.GeneralNames;
|
||||
import org.bouncycastle.asn1.x509.Time;
|
||||
import org.bouncycastle.cert.X509CertificateHolder;
|
||||
import org.bouncycastle.cert.jcajce.JcaX509CertificateConverter;
|
||||
import org.bouncycastle.cert.jcajce.JcaX509ExtensionUtils;
|
||||
import org.bouncycastle.cert.jcajce.JcaX509v3CertificateBuilder;
|
||||
import org.bouncycastle.jce.provider.BouncyCastleProvider;
|
||||
import org.bouncycastle.openssl.PEMEncryptedKeyPair;
|
||||
import org.bouncycastle.openssl.PEMKeyPair;
|
||||
import org.bouncycastle.openssl.PEMParser;
|
||||
import org.bouncycastle.openssl.X509TrustedCertificateBlock;
|
||||
import org.bouncycastle.openssl.jcajce.JcaPEMKeyConverter;
|
||||
import org.bouncycastle.openssl.jcajce.JcePEMDecryptorProviderBuilder;
|
||||
import org.bouncycastle.operator.ContentSigner;
|
||||
import org.bouncycastle.operator.jcajce.JcaContentSignerBuilder;
|
||||
import org.elasticsearch.common.Nullable;
|
||||
import org.elasticsearch.common.Strings;
|
||||
import org.elasticsearch.common.SuppressForbidden;
|
||||
import org.elasticsearch.common.io.PathUtils;
|
||||
import org.elasticsearch.common.network.InetAddressHelper;
|
||||
import org.elasticsearch.common.network.NetworkAddress;
|
||||
import org.elasticsearch.env.Environment;
|
||||
import org.joda.time.DateTime;
|
||||
import org.joda.time.DateTimeZone;
|
||||
|
||||
import javax.net.ssl.KeyManager;
|
||||
import javax.net.ssl.KeyManagerFactory;
|
||||
import javax.net.ssl.TrustManager;
|
||||
import javax.net.ssl.TrustManagerFactory;
|
||||
import javax.net.ssl.X509ExtendedKeyManager;
|
||||
import javax.net.ssl.X509ExtendedTrustManager;
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.Reader;
|
||||
import java.math.BigInteger;
|
||||
import java.net.InetAddress;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.security.KeyPair;
|
||||
import java.security.KeyPairGenerator;
|
||||
import java.security.KeyStore;
|
||||
import java.security.PrivateKey;
|
||||
import java.security.SecureRandom;
|
||||
import java.security.cert.Certificate;
|
||||
import java.security.cert.CertificateFactory;
|
||||
import java.security.cert.X509Certificate;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.Set;
|
||||
|
||||
class CertUtils {
|
||||
|
||||
private static final int SERIAL_BIT_LENGTH = 20 * 8;
|
||||
static final BouncyCastleProvider BC_PROV = new BouncyCastleProvider();
|
||||
|
||||
private CertUtils() {}
|
||||
|
||||
@SuppressForbidden(reason = "we don't have the environment to resolve files from when running in a transport client")
|
||||
static Path resolvePath(String path, @Nullable Environment environment) {
|
||||
if (environment != null) {
|
||||
return environment.configFile().resolve(path);
|
||||
}
|
||||
return PathUtils.get(Strings.cleanPath(path));
|
||||
}
|
||||
|
||||
static X509ExtendedKeyManager[] keyManagers(Certificate[] certificateChain, PrivateKey privateKey, char[] password) throws Exception {
|
||||
KeyStore keyStore = KeyStore.getInstance("jks");
|
||||
keyStore.load(null, null);
|
||||
// password must be non-null for keystore...
|
||||
keyStore.setKeyEntry("key", privateKey, password, certificateChain);
|
||||
return keyManagers(keyStore, password, KeyManagerFactory.getDefaultAlgorithm());
|
||||
}
|
||||
|
||||
static X509ExtendedKeyManager[] keyManagers(KeyStore keyStore, char[] password, String algorithm) throws Exception {
|
||||
KeyManagerFactory kmf = KeyManagerFactory.getInstance(algorithm);
|
||||
kmf.init(keyStore, password);
|
||||
KeyManager[] keyManagers = kmf.getKeyManagers();
|
||||
for (KeyManager keyManager : keyManagers) {
|
||||
if (keyManager instanceof X509ExtendedKeyManager) {
|
||||
return new X509ExtendedKeyManager[] { (X509ExtendedKeyManager) keyManager };
|
||||
}
|
||||
}
|
||||
throw new IllegalStateException("failed to find a X509ExtendedKeyManager");
|
||||
}
|
||||
|
||||
static X509ExtendedTrustManager[] trustManagers(Certificate[] certificates) throws Exception {
|
||||
KeyStore store = KeyStore.getInstance("jks");
|
||||
store.load(null, null);
|
||||
int counter = 0;
|
||||
for (Certificate certificate : certificates) {
|
||||
store.setCertificateEntry("cert" + counter, certificate);
|
||||
counter++;
|
||||
}
|
||||
return trustManagers(store, TrustManagerFactory.getDefaultAlgorithm());
|
||||
}
|
||||
|
||||
static X509ExtendedTrustManager[] trustManagers(KeyStore keyStore, String algorithm) throws Exception {
|
||||
TrustManagerFactory tmf = TrustManagerFactory.getInstance(algorithm);
|
||||
tmf.init(keyStore);
|
||||
TrustManager[] trustManagers = tmf.getTrustManagers();
|
||||
for (TrustManager trustManager : trustManagers) {
|
||||
if (trustManager instanceof X509ExtendedTrustManager) {
|
||||
return new X509ExtendedTrustManager[] { (X509ExtendedTrustManager) trustManager };
|
||||
}
|
||||
}
|
||||
throw new IllegalStateException("failed to find a X509ExtendedTrustManager");
|
||||
}
|
||||
|
||||
static Certificate[] readCertificates(List<String> certPaths, Environment environment) throws Exception {
|
||||
List<Certificate> certificates = new ArrayList<>(certPaths.size());
|
||||
CertificateFactory certFactory = CertificateFactory.getInstance("X.509");
|
||||
for (String path : certPaths) {
|
||||
try (Reader reader = Files.newBufferedReader(resolvePath(path, environment), StandardCharsets.UTF_8)) {
|
||||
readCertificates(reader, certificates, certFactory);
|
||||
}
|
||||
}
|
||||
return certificates.toArray(new Certificate[certificates.size()]);
|
||||
}
|
||||
|
||||
static void readCertificates(Reader reader, List<Certificate> certificates, CertificateFactory certFactory) throws Exception {
|
||||
try (PEMParser pemParser = new PEMParser(reader)) {
|
||||
|
||||
Object parsed = pemParser.readObject();
|
||||
if (parsed == null) {
|
||||
throw new IllegalArgumentException("could not parse pem certificate");
|
||||
}
|
||||
|
||||
while (parsed != null) {
|
||||
X509CertificateHolder holder;
|
||||
if (parsed instanceof X509CertificateHolder) {
|
||||
holder = (X509CertificateHolder) parsed;
|
||||
} else if (parsed instanceof X509TrustedCertificateBlock) {
|
||||
X509TrustedCertificateBlock certificateBlock = (X509TrustedCertificateBlock) parsed;
|
||||
holder = certificateBlock.getCertificateHolder();
|
||||
} else {
|
||||
throw new IllegalArgumentException("parsed an unsupported object [" +
|
||||
parsed.getClass().getSimpleName() + "]");
|
||||
}
|
||||
certificates.add(certFactory.generateCertificate(new ByteArrayInputStream(holder.getEncoded())));
|
||||
parsed = pemParser.readObject();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static PrivateKey readPrivateKey(Reader reader, char[] keyPassword) throws Exception {
|
||||
try (PEMParser parser = new PEMParser(reader)) {
|
||||
Object parsed;
|
||||
List<Object> list = new ArrayList<>(1);
|
||||
do {
|
||||
parsed = parser.readObject();
|
||||
if (parsed != null) {
|
||||
list.add(parsed);
|
||||
}
|
||||
} while (parsed != null);
|
||||
|
||||
if (list.size() != 1) {
|
||||
throw new IllegalStateException("key file contained [" + list.size() + "] entries, expected one");
|
||||
}
|
||||
|
||||
PrivateKeyInfo privateKeyInfo;
|
||||
Object parsedObject = list.get(0);
|
||||
if (parsedObject instanceof PEMEncryptedKeyPair) {
|
||||
if (keyPassword == null) {
|
||||
throw new IllegalArgumentException("cannot read encrypted key without a password");
|
||||
}
|
||||
// we have an encrypted key pair so we need to decrypt it
|
||||
PEMEncryptedKeyPair encryptedKeyPair = (PEMEncryptedKeyPair) parsedObject;
|
||||
privateKeyInfo = encryptedKeyPair
|
||||
.decryptKeyPair(new JcePEMDecryptorProviderBuilder().setProvider(BC_PROV).build(keyPassword))
|
||||
.getPrivateKeyInfo();
|
||||
} else if (parsedObject instanceof PEMKeyPair) {
|
||||
privateKeyInfo = ((PEMKeyPair) parsedObject).getPrivateKeyInfo();
|
||||
} else if (parsedObject instanceof PrivateKeyInfo) {
|
||||
privateKeyInfo = (PrivateKeyInfo) parsedObject;
|
||||
} else {
|
||||
throw new IllegalArgumentException("parsed an unsupported object [" +
|
||||
parsedObject.getClass().getSimpleName() + "]");
|
||||
}
|
||||
|
||||
JcaPEMKeyConverter converter = new JcaPEMKeyConverter();
|
||||
return converter.getPrivateKey(privateKeyInfo);
|
||||
}
|
||||
}
|
||||
|
||||
static X509Certificate generateSignedCertificate(boolean resolveHostname, String nodeName, Set<InetAddress> addresses, KeyPair keyPair,
|
||||
Certificate caCert, PrivateKey caPrivKey) throws Exception {
|
||||
final DateTime notBefore = new DateTime(DateTimeZone.UTC);
|
||||
final DateTime notAfter = notBefore.plusYears(1);
|
||||
final BigInteger serial = getSerial();
|
||||
|
||||
X509Certificate x509CACert = (X509Certificate) caCert;
|
||||
X500Name subject = new X500Name("CN=" + nodeName);
|
||||
JcaX509v3CertificateBuilder builder =
|
||||
new JcaX509v3CertificateBuilder(X500Name.getInstance(x509CACert.getIssuerX500Principal().getEncoded()), serial,
|
||||
new Time(notBefore.toDate(), Locale.ROOT), new Time(notAfter.toDate(), Locale.ROOT), subject, keyPair.getPublic());
|
||||
|
||||
JcaX509ExtensionUtils extUtils = new JcaX509ExtensionUtils();
|
||||
builder.addExtension(Extension.subjectKeyIdentifier, false, extUtils.createSubjectKeyIdentifier(keyPair.getPublic()));
|
||||
builder.addExtension(Extension.authorityKeyIdentifier, false, extUtils.createAuthorityKeyIdentifier(x509CACert));
|
||||
if (addresses.isEmpty() == false) {
|
||||
builder.addExtension(Extension.subjectAlternativeName, false, getSubjectAlternativeNames(resolveHostname, addresses));
|
||||
}
|
||||
|
||||
ContentSigner signer = new JcaContentSignerBuilder("SHA256withRSA").build(caPrivKey);
|
||||
X509CertificateHolder certificateHolder = builder.build(signer);
|
||||
return new JcaX509CertificateConverter().getCertificate(certificateHolder);
|
||||
}
|
||||
|
||||
static BigInteger getSerial() {
|
||||
SecureRandom random = new SecureRandom();
|
||||
BigInteger serial = new BigInteger(SERIAL_BIT_LENGTH, random);
|
||||
assert serial.compareTo(BigInteger.valueOf(0L)) >= 0;
|
||||
return serial;
|
||||
}
|
||||
|
||||
static KeyPair generateKeyPair() throws Exception {
|
||||
// generate a private key
|
||||
KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("RSA");
|
||||
keyPairGenerator.initialize(2048);
|
||||
return keyPairGenerator.generateKeyPair();
|
||||
}
|
||||
|
||||
static GeneralNames getSubjectAlternativeNames(boolean resolveName, Set<InetAddress> addresses) throws Exception {
|
||||
Set<GeneralName> generalNameList = new HashSet<>();
|
||||
for (InetAddress address : addresses) {
|
||||
if (address.isAnyLocalAddress()) {
|
||||
// it is a wildcard address
|
||||
for (InetAddress inetAddress : InetAddressHelper.getAllAddresses()) {
|
||||
addSubjectAlternativeNames(resolveName, inetAddress, generalNameList);
|
||||
}
|
||||
} else {
|
||||
addSubjectAlternativeNames(resolveName, address, generalNameList);
|
||||
}
|
||||
}
|
||||
return new GeneralNames(generalNameList.toArray(new GeneralName[generalNameList.size()]));
|
||||
}
|
||||
|
||||
@SuppressForbidden(reason = "need to use getHostName to resolve DNS name and getHostAddress to ensure we resolved the name")
|
||||
static void addSubjectAlternativeNames(boolean resolveName, InetAddress inetAddress, Set<GeneralName> list) {
|
||||
String hostaddress = inetAddress.getHostAddress();
|
||||
String ip = NetworkAddress.format(inetAddress);
|
||||
list.add(new GeneralName(GeneralName.iPAddress, ip));
|
||||
if (resolveName && (inetAddress.isLinkLocalAddress() == false)) {
|
||||
String possibleHostName = inetAddress.getHostName();
|
||||
if (possibleHostName.equals(hostaddress) == false) {
|
||||
list.add(new GeneralName(GeneralName.dNSName, possibleHostName));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -5,21 +5,17 @@
|
|||
*/
|
||||
package org.elasticsearch.shield.ssl;
|
||||
|
||||
import org.elasticsearch.common.Strings;
|
||||
import org.elasticsearch.common.SuppressForbidden;
|
||||
import org.elasticsearch.common.inject.Inject;
|
||||
import org.elasticsearch.common.io.PathUtils;
|
||||
import org.elasticsearch.common.settings.Settings;
|
||||
import org.elasticsearch.env.Environment;
|
||||
import org.elasticsearch.shield.ssl.SSLConfiguration.Global;
|
||||
import org.elasticsearch.watcher.ResourceWatcherService;
|
||||
|
||||
import java.nio.file.Path;
|
||||
|
||||
@SuppressForbidden(reason = "we don't have the environment to resolve files from when running in a transport client")
|
||||
public class ClientSSLService extends AbstractSSLService {
|
||||
|
||||
@Inject
|
||||
public ClientSSLService(Settings settings) {
|
||||
super(settings, null);
|
||||
public ClientSSLService(Settings settings, Global globalSSLConfiguration) {
|
||||
super(settings, null, globalSSLConfiguration, null);
|
||||
}
|
||||
|
||||
@Inject(optional = true)
|
||||
|
@ -27,31 +23,14 @@ public class ClientSSLService extends AbstractSSLService {
|
|||
this.env = environment;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected SSLSettings sslSettings(Settings customSettings) {
|
||||
SSLSettings sslSettings = new SSLSettings(customSettings, settings);
|
||||
|
||||
if (sslSettings.keyStorePath != null) {
|
||||
if (sslSettings.keyStorePassword == null) {
|
||||
throw new IllegalArgumentException("no keystore password configured");
|
||||
}
|
||||
assert sslSettings.keyPassword != null;
|
||||
}
|
||||
|
||||
if (sslSettings.trustStorePath != null) {
|
||||
if (sslSettings.trustStorePassword == null) {
|
||||
throw new IllegalArgumentException("no truststore password configured");
|
||||
}
|
||||
}
|
||||
|
||||
return sslSettings;
|
||||
@Inject(optional = true)
|
||||
public void setResourceWatcherService(ResourceWatcherService resourceWatcherService) {
|
||||
this.resourceWatcherService = resourceWatcherService;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Path resolvePath(String location) {
|
||||
if (env == null) {
|
||||
return PathUtils.get(Strings.cleanPath(location));
|
||||
}
|
||||
return super.resolvePath(location);
|
||||
protected void validateSSLConfiguration(SSLConfiguration sslConfiguration) {
|
||||
sslConfiguration.keyConfig().validate();
|
||||
sslConfiguration.trustConfig().validate();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,143 @@
|
|||
/*
|
||||
* 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.shield.ssl;
|
||||
|
||||
import org.elasticsearch.ElasticsearchException;
|
||||
import org.elasticsearch.common.Nullable;
|
||||
import org.elasticsearch.env.Environment;
|
||||
import org.elasticsearch.shield.ssl.TrustConfig.Reloadable.Listener;
|
||||
import org.elasticsearch.watcher.FileWatcher;
|
||||
import org.elasticsearch.watcher.ResourceWatcherService;
|
||||
import org.elasticsearch.watcher.ResourceWatcherService.Frequency;
|
||||
|
||||
import javax.net.ssl.KeyManager;
|
||||
import javax.net.ssl.SSLEngine;
|
||||
import javax.net.ssl.X509ExtendedKeyManager;
|
||||
import javax.net.ssl.X509ExtendedTrustManager;
|
||||
import java.io.IOException;
|
||||
import java.net.Socket;
|
||||
import java.nio.file.Path;
|
||||
import java.security.Principal;
|
||||
import java.security.PrivateKey;
|
||||
import java.security.cert.X509Certificate;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
abstract class KeyConfig extends TrustConfig {
|
||||
|
||||
KeyConfig(boolean includeSystem, boolean reloadEnabled) {
|
||||
super(includeSystem, reloadEnabled);
|
||||
}
|
||||
|
||||
static final KeyConfig NONE = new KeyConfig(false, false) {
|
||||
@Override
|
||||
X509ExtendedKeyManager[] loadKeyManagers(@Nullable Environment environment) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
X509ExtendedTrustManager[] nonSystemTrustManagers(@Nullable Environment environment) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
void validate() {
|
||||
}
|
||||
|
||||
@Override
|
||||
List<Path> filesToMonitor(@Nullable Environment environment) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "NONE";
|
||||
}
|
||||
};
|
||||
|
||||
final KeyManager[] keyManagers(@Nullable Environment environment, @Nullable ResourceWatcherService resourceWatcherService,
|
||||
@Nullable Listener listener) {
|
||||
X509ExtendedKeyManager[] keyManagers = loadKeyManagers(environment);
|
||||
if (reloadEnabled && resourceWatcherService != null && listener != null) {
|
||||
ReloadableX509KeyManager reloadableX509KeyManager = new ReloadableX509KeyManager(keyManagers[0], environment);
|
||||
List<Path> filesToMonitor = filesToMonitor(environment);
|
||||
ChangeListener changeListener = new ChangeListener(filesToMonitor, reloadableX509KeyManager, listener);
|
||||
try {
|
||||
for (Path dir : directoriesToMonitor(filesToMonitor)) {
|
||||
FileWatcher fileWatcher = new FileWatcher(dir);
|
||||
fileWatcher.addListener(changeListener);
|
||||
resourceWatcherService.add(fileWatcher, Frequency.HIGH);
|
||||
}
|
||||
return new X509ExtendedKeyManager[] { reloadableX509KeyManager };
|
||||
} catch (IOException e) {
|
||||
throw new ElasticsearchException("failed to add file watcher", e);
|
||||
}
|
||||
}
|
||||
return keyManagers;
|
||||
}
|
||||
|
||||
abstract X509ExtendedKeyManager[] loadKeyManagers(@Nullable Environment environment);
|
||||
|
||||
final class ReloadableX509KeyManager extends X509ExtendedKeyManager implements Reloadable {
|
||||
|
||||
private final Environment environment;
|
||||
private volatile X509ExtendedKeyManager keyManager;
|
||||
|
||||
ReloadableX509KeyManager(X509ExtendedKeyManager keyManager, @Nullable Environment environment) {
|
||||
this.keyManager = keyManager;
|
||||
this.environment = environment;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String[] getClientAliases(String s, Principal[] principals) {
|
||||
return keyManager.getClientAliases(s, principals);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String chooseClientAlias(String[] strings, Principal[] principals, Socket socket) {
|
||||
return keyManager.chooseClientAlias(strings, principals, socket);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String[] getServerAliases(String s, Principal[] principals) {
|
||||
return keyManager.getServerAliases(s, principals);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String chooseServerAlias(String s, Principal[] principals, Socket socket) {
|
||||
return keyManager.chooseServerAlias(s, principals, socket);
|
||||
}
|
||||
|
||||
@Override
|
||||
public X509Certificate[] getCertificateChain(String s) {
|
||||
return keyManager.getCertificateChain(s);
|
||||
}
|
||||
|
||||
@Override
|
||||
public PrivateKey getPrivateKey(String s) {
|
||||
return keyManager.getPrivateKey(s);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String chooseEngineClientAlias(String[] strings, Principal[] principals, SSLEngine engine) {
|
||||
return keyManager.chooseEngineClientAlias(strings, principals, engine);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String chooseEngineServerAlias(String s, Principal[] principals, SSLEngine engine) {
|
||||
return keyManager.chooseEngineServerAlias(s, principals, engine);
|
||||
}
|
||||
|
||||
public synchronized void reload() {
|
||||
X509ExtendedKeyManager[] keyManagers = loadKeyManagers(environment);
|
||||
this.keyManager = keyManagers[0];
|
||||
}
|
||||
|
||||
synchronized void setKeyManager(X509ExtendedKeyManager x509ExtendedKeyManager) {
|
||||
this.keyManager = x509ExtendedKeyManager;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,113 @@
|
|||
/*
|
||||
* 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.shield.ssl;
|
||||
|
||||
import org.elasticsearch.ElasticsearchException;
|
||||
import org.elasticsearch.common.Nullable;
|
||||
import org.elasticsearch.common.Strings;
|
||||
import org.elasticsearch.env.Environment;
|
||||
|
||||
import javax.net.ssl.X509ExtendedKeyManager;
|
||||
import javax.net.ssl.X509ExtendedTrustManager;
|
||||
import java.io.Reader;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.security.PrivateKey;
|
||||
import java.security.cert.Certificate;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
class PEMKeyConfig extends KeyConfig {
|
||||
|
||||
final String keyPath;
|
||||
final String keyPassword;
|
||||
final List<String> certPaths;
|
||||
|
||||
PEMKeyConfig(boolean includeSystem, boolean reloadEnabled, String keyPath, String keyPassword, List<String> certPaths) {
|
||||
super(includeSystem, reloadEnabled);
|
||||
this.keyPath = keyPath;
|
||||
this.keyPassword = keyPassword;
|
||||
this.certPaths = certPaths;
|
||||
}
|
||||
|
||||
@Override
|
||||
X509ExtendedKeyManager[] loadKeyManagers(@Nullable Environment environment) {
|
||||
try {
|
||||
PrivateKey privateKey = readPrivateKey(CertUtils.resolvePath(keyPath, environment));
|
||||
Certificate[] certificateChain = CertUtils.readCertificates(certPaths, environment);
|
||||
// password must be non-null for keystore...
|
||||
char[] password = keyPassword == null ? new char[0] : keyPassword.toCharArray();
|
||||
return CertUtils.keyManagers(certificateChain, privateKey, password);
|
||||
} catch (Exception e) {
|
||||
throw new ElasticsearchException("failed to initialize a KeyManagerFactory", e);
|
||||
}
|
||||
}
|
||||
|
||||
PrivateKey readPrivateKey(Path keyPath) throws Exception {
|
||||
try (Reader reader = Files.newBufferedReader(keyPath, StandardCharsets.UTF_8)) {
|
||||
char[] password = keyPassword == null ? null : keyPassword.toCharArray();
|
||||
return CertUtils.readPrivateKey(reader, password);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
X509ExtendedTrustManager[] nonSystemTrustManagers(@Nullable Environment environment) {
|
||||
try {
|
||||
Certificate[] certificates = CertUtils.readCertificates(certPaths, environment);
|
||||
return CertUtils.trustManagers(certificates);
|
||||
} catch (Exception e) {
|
||||
throw new ElasticsearchException("failed to initialize a TrustManagerFactory", e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
void validate() {
|
||||
if (keyPath == null) {
|
||||
throw new IllegalArgumentException("no key file configured");
|
||||
} else if (certPaths == null || certPaths.isEmpty()) {
|
||||
throw new IllegalArgumentException("no certificate provided");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
List<Path> filesToMonitor(@Nullable Environment environment) {
|
||||
List<Path> paths = new ArrayList<>(1 + certPaths.size());
|
||||
paths.add(CertUtils.resolvePath(keyPath, environment));
|
||||
for (String certPath : certPaths) {
|
||||
paths.add(CertUtils.resolvePath(certPath, environment));
|
||||
}
|
||||
return paths;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) return true;
|
||||
if (o == null || getClass() != o.getClass()) return false;
|
||||
|
||||
PEMKeyConfig that = (PEMKeyConfig) o;
|
||||
|
||||
if (keyPath != null ? !keyPath.equals(that.keyPath) : that.keyPath != null) return false;
|
||||
if (keyPassword != null ? !keyPassword.equals(that.keyPassword) : that.keyPassword != null) return false;
|
||||
return certPaths != null ? certPaths.equals(that.certPaths) : that.certPaths == null;
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
int result = keyPath != null ? keyPath.hashCode() : 0;
|
||||
result = 31 * result + (keyPassword != null ? keyPassword.hashCode() : 0);
|
||||
result = 31 * result + (certPaths != null ? certPaths.hashCode() : 0);
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "keyPath=[" + keyPath +
|
||||
"], certPaths=[" + Strings.collectionToCommaDelimitedString(certPaths) +
|
||||
"]";
|
||||
}
|
||||
}
|
|
@ -0,0 +1,74 @@
|
|||
/*
|
||||
* 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.shield.ssl;
|
||||
|
||||
import org.elasticsearch.ElasticsearchException;
|
||||
import org.elasticsearch.common.Nullable;
|
||||
import org.elasticsearch.common.Strings;
|
||||
import org.elasticsearch.env.Environment;
|
||||
|
||||
import javax.net.ssl.X509ExtendedTrustManager;
|
||||
import java.nio.file.Path;
|
||||
import java.security.cert.Certificate;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
class PEMTrustConfig extends TrustConfig {
|
||||
|
||||
final List<String> caPaths;
|
||||
|
||||
PEMTrustConfig(boolean includeSystem, boolean reloadEnabled, List<String> caPaths) {
|
||||
super(includeSystem, reloadEnabled);
|
||||
this.caPaths = caPaths;
|
||||
}
|
||||
|
||||
@Override
|
||||
X509ExtendedTrustManager[] nonSystemTrustManagers(@Nullable Environment environment) {
|
||||
try {
|
||||
Certificate[] certificates = CertUtils.readCertificates(caPaths, environment);
|
||||
return CertUtils.trustManagers(certificates);
|
||||
} catch (Exception e) {
|
||||
throw new ElasticsearchException("failed to initialize a TrustManagerFactory", e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
void validate() {
|
||||
if (caPaths == null) {
|
||||
throw new IllegalArgumentException("no ca paths have been configured");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
List<Path> filesToMonitor(@Nullable Environment environment) {
|
||||
List<Path> paths = new ArrayList<>(caPaths.size());
|
||||
for (String path : caPaths) {
|
||||
paths.add(CertUtils.resolvePath(path, environment));
|
||||
}
|
||||
return paths;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) return true;
|
||||
if (o == null || getClass() != o.getClass()) return false;
|
||||
|
||||
PEMTrustConfig that = (PEMTrustConfig) o;
|
||||
|
||||
return caPaths != null ? caPaths.equals(that.caPaths) : that.caPaths == null;
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return caPaths != null ? caPaths.hashCode() : 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "ca=[" + Strings.collectionToCommaDelimitedString(caPaths) + "]";
|
||||
}
|
||||
}
|
|
@ -0,0 +1,560 @@
|
|||
/*
|
||||
* 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.shield.ssl;
|
||||
|
||||
import org.elasticsearch.ElasticsearchException;
|
||||
import org.elasticsearch.common.inject.Inject;
|
||||
import org.elasticsearch.common.logging.ESLogger;
|
||||
import org.elasticsearch.common.logging.Loggers;
|
||||
import org.elasticsearch.common.settings.Setting;
|
||||
import org.elasticsearch.common.settings.Setting.Property;
|
||||
import org.elasticsearch.common.settings.Settings;
|
||||
import org.elasticsearch.common.settings.SettingsModule;
|
||||
import org.elasticsearch.common.transport.BoundTransportAddress;
|
||||
import org.elasticsearch.common.transport.InetSocketTransportAddress;
|
||||
import org.elasticsearch.common.transport.TransportAddress;
|
||||
import org.elasticsearch.common.unit.TimeValue;
|
||||
import org.elasticsearch.node.Node;
|
||||
import org.elasticsearch.shield.transport.netty.ShieldNettyHttpServerTransport;
|
||||
import org.elasticsearch.shield.transport.netty.ShieldNettyTransport;
|
||||
import org.elasticsearch.transport.TransportSettings;
|
||||
|
||||
import javax.net.ssl.KeyManagerFactory;
|
||||
import javax.net.ssl.TrustManagerFactory;
|
||||
import java.net.InetAddress;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.Optional;
|
||||
import java.util.Set;
|
||||
import java.util.function.Function;
|
||||
|
||||
import static org.elasticsearch.shield.Security.featureEnabledSetting;
|
||||
import static org.elasticsearch.shield.Security.setting;
|
||||
import static org.elasticsearch.shield.support.OptionalSettings.createInt;
|
||||
import static org.elasticsearch.shield.support.OptionalSettings.createString;
|
||||
import static org.elasticsearch.shield.support.OptionalSettings.createTimeValue;
|
||||
|
||||
/**
|
||||
* Class that contains all configuration related to SSL use within x-pack
|
||||
*/
|
||||
public abstract class SSLConfiguration {
|
||||
|
||||
public abstract KeyConfig keyConfig();
|
||||
|
||||
public abstract TrustConfig trustConfig();
|
||||
|
||||
public abstract String protocol();
|
||||
|
||||
public abstract int sessionCacheSize();
|
||||
|
||||
public abstract TimeValue sessionCacheTimeout();
|
||||
|
||||
public abstract List<String> ciphers();
|
||||
|
||||
public abstract List<String> supportedProtocols();
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) return true;
|
||||
if (!(o instanceof SSLConfiguration)) return false;
|
||||
|
||||
SSLConfiguration that = (SSLConfiguration) o;
|
||||
|
||||
if (this.sessionCacheSize() != that.sessionCacheSize()) {
|
||||
return false;
|
||||
}
|
||||
if (this.keyConfig() != null ? !this.keyConfig().equals(that.keyConfig()) : that.keyConfig() != null) {
|
||||
return false;
|
||||
}
|
||||
if (this.trustConfig() != null ? !this.trustConfig().equals(that.trustConfig()) : that.trustConfig() != null) {
|
||||
return false;
|
||||
}
|
||||
if (this.protocol() != null ? !this.protocol().equals(that.protocol()) : that.protocol() != null) {
|
||||
return false;
|
||||
}
|
||||
if (this.sessionCacheTimeout() != null ?
|
||||
!this.sessionCacheTimeout().equals(that.sessionCacheTimeout()) : that.sessionCacheTimeout() != null) {
|
||||
return false;
|
||||
}
|
||||
if (this.ciphers() != null ? !this.ciphers().equals(that.ciphers()) : that.ciphers() != null) {
|
||||
return false;
|
||||
}
|
||||
return this.supportedProtocols() != null ?
|
||||
this.supportedProtocols().equals(that.supportedProtocols()) : that.supportedProtocols() == null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
int result = this.keyConfig() != null ? this.keyConfig().hashCode() : 0;
|
||||
result = 31 * result + (this.trustConfig() != null ? this.trustConfig().hashCode() : 0);
|
||||
result = 31 * result + (this.protocol() != null ? this.protocol().hashCode() : 0);
|
||||
result = 31 * result + this.sessionCacheSize();
|
||||
result = 31 * result + (this.sessionCacheTimeout() != null ? this.sessionCacheTimeout().hashCode() : 0);
|
||||
result = 31 * result + (this.ciphers() != null ? this.ciphers().hashCode() : 0);
|
||||
result = 31 * result + (this.supportedProtocols() != null ? this.supportedProtocols().hashCode() : 0);
|
||||
return result;
|
||||
}
|
||||
|
||||
public static class Global extends SSLConfiguration {
|
||||
|
||||
public static final List<String> DEFAULT_SUPPORTED_PROTOCOLS = Arrays.asList("TLSv1", "TLSv1.1", "TLSv1.2");
|
||||
public static final List<String> DEFAULT_CIPHERS =
|
||||
Arrays.asList("TLS_RSA_WITH_AES_128_CBC_SHA256", "TLS_RSA_WITH_AES_128_CBC_SHA", "TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA");
|
||||
public static final TimeValue DEFAULT_SESSION_CACHE_TIMEOUT = TimeValue.timeValueHours(24);
|
||||
public static final int DEFAULT_SESSION_CACHE_SIZE = 1000;
|
||||
public static final String DEFAULT_PROTOCOL = "TLSv1.2";
|
||||
|
||||
public static final Setting<Boolean> AUTO_GENERATE_SSL_SETTING =
|
||||
Setting.boolSetting(featureEnabledSetting("ssl.auto_generate"), true, Property.NodeScope, Property.Filtered);
|
||||
static final Setting<Boolean> AUTO_GEN_RESOLVE_HOST_SETTING =
|
||||
Setting.boolSetting(setting("ssl.auto_generate.resolve_name"), true, Property.NodeScope, Property.Filtered);
|
||||
|
||||
// common settings
|
||||
static final Setting<List<String>> CIPHERS_SETTING = Setting.listSetting(globalKey(Custom.CIPHERS_SETTING), DEFAULT_CIPHERS,
|
||||
Function.identity(), Property.NodeScope, Property.Filtered);
|
||||
static final Setting<List<String>> SUPPORTED_PROTOCOLS_SETTING = Setting.listSetting(globalKey(Custom.SUPPORTED_PROTOCOLS_SETTING),
|
||||
DEFAULT_SUPPORTED_PROTOCOLS, Function.identity(), Property.NodeScope, Property.Filtered);
|
||||
static final Setting<String> PROTOCOL_SETTING = new Setting<>(globalKey(Custom.PROTOCOL_SETTING), DEFAULT_PROTOCOL,
|
||||
Function.identity(), Property.NodeScope, Property.Filtered);
|
||||
static final Setting<Integer> SESSION_CACHE_SIZE_SETTING = Setting.intSetting(globalKey(Custom.CACHE_SIZE_SETTING),
|
||||
DEFAULT_SESSION_CACHE_SIZE, Property.NodeScope, Property.Filtered);
|
||||
static final Setting<TimeValue> SESSION_CACHE_TIMEOUT_SETTING = Setting.timeSetting(globalKey(Custom.CACHE_TIMEOUT_SETTING),
|
||||
DEFAULT_SESSION_CACHE_TIMEOUT, Property.NodeScope, Property.Filtered);
|
||||
static final Setting<Boolean> RELOAD_ENABLED_SETTING =
|
||||
Setting.boolSetting(globalKey(Custom.RELOAD_ENABLED_SETTING), true, Property.NodeScope, Property.Filtered);
|
||||
|
||||
// keystore settings
|
||||
static final Setting<Optional<String>> KEYSTORE_PATH_SETTING = createString(globalKey(Custom.KEYSTORE_PATH_SETTING),
|
||||
s -> System.getProperty("javax.net.ssl.keyStore"), Property.NodeScope, Property.Filtered);
|
||||
static final Setting<Optional<String>> KEYSTORE_PASSWORD_SETTING = createString(globalKey(Custom.KEYSTORE_PASSWORD_SETTING),
|
||||
s -> System.getProperty("javax.net.ssl.keyStorePassword"), Property.NodeScope, Property.Filtered);
|
||||
static final Setting<String> KEYSTORE_ALGORITHM_SETTING = new Setting<>(globalKey(Custom.KEYSTORE_ALGORITHM_SETTING),
|
||||
s -> System.getProperty("ssl.KeyManagerFactory.algorithm", KeyManagerFactory.getDefaultAlgorithm()),
|
||||
Function.identity(), Property.NodeScope, Property.Filtered);
|
||||
static final Setting<Optional<String>> KEYSTORE_KEY_PASSWORD_SETTING =
|
||||
createString(globalKey(Custom.KEYSTORE_KEY_PASSWORD_SETTING), KEYSTORE_PASSWORD_SETTING,
|
||||
Property.NodeScope, Property.Filtered);
|
||||
|
||||
// truststore settings
|
||||
static final Setting<Optional<String>> TRUSTSTORE_PATH_SETTING = createString(globalKey(Custom.TRUSTSTORE_PATH_SETTING),
|
||||
s -> System.getProperty("javax.net.ssl.trustStore"), Property.NodeScope, Property.Filtered);
|
||||
static final Setting<Optional<String>> TRUSTSTORE_PASSWORD_SETTING = createString(globalKey(Custom.TRUSTSTORE_PASSWORD_SETTING),
|
||||
s -> System.getProperty("javax.net.ssl.trustStorePassword"), Property.NodeScope, Property.Filtered);
|
||||
static final Setting<String> TRUSTSTORE_ALGORITHM_SETTING = new Setting<>(globalKey(Custom.TRUSTSTORE_ALGORITHM_SETTING),
|
||||
s -> System.getProperty("ssl.TrustManagerFactory.algorithm", TrustManagerFactory.getDefaultAlgorithm()),
|
||||
Function.identity(), Property.NodeScope, Property.Filtered);
|
||||
|
||||
// PEM key and cert settings
|
||||
static final Setting<Optional<String>> KEY_PATH_SETTING = createString(globalKey(Custom.KEY_PATH_SETTING),
|
||||
Property.NodeScope, Property.Filtered);
|
||||
static final Setting<Optional<String>> KEY_PASSWORD_SETTING = createString(globalKey(Custom.KEY_PASSWORD_SETTING),
|
||||
Property.NodeScope, Property.Filtered);
|
||||
static final Setting<List<String>> CERT_SETTING = Setting.listSetting(globalKey(Custom.CERT_SETTING), Collections.emptyList(),
|
||||
s -> s, Property.NodeScope, Property.Filtered);
|
||||
|
||||
// PEM trusted certs
|
||||
static final Setting<List<String>> CA_PATHS_SETTING = Setting.listSetting(globalKey(Custom.CA_PATHS_SETTING),
|
||||
Collections.emptyList(), s -> s, Property.NodeScope, Property.Filtered);
|
||||
|
||||
// Default system trusted certs
|
||||
static final Setting<Boolean> INCLUDE_JDK_CERTS_SETTING = Setting.boolSetting(globalKey(Custom.INCLUDE_JDK_CERTS_SETTING), true,
|
||||
Property.NodeScope, Property.Filtered);
|
||||
|
||||
public static void registerSettings(SettingsModule settingsModule) {
|
||||
settingsModule.registerSetting(Global.CIPHERS_SETTING);
|
||||
settingsModule.registerSetting(Global.SUPPORTED_PROTOCOLS_SETTING);
|
||||
settingsModule.registerSetting(Global.KEYSTORE_PATH_SETTING);
|
||||
settingsModule.registerSetting(Global.KEYSTORE_PASSWORD_SETTING);
|
||||
settingsModule.registerSetting(Global.KEYSTORE_ALGORITHM_SETTING);
|
||||
settingsModule.registerSetting(Global.KEYSTORE_KEY_PASSWORD_SETTING);
|
||||
settingsModule.registerSetting(Global.KEY_PATH_SETTING);
|
||||
settingsModule.registerSetting(Global.KEY_PASSWORD_SETTING);
|
||||
settingsModule.registerSetting(Global.CERT_SETTING);
|
||||
settingsModule.registerSetting(Global.TRUSTSTORE_PATH_SETTING);
|
||||
settingsModule.registerSetting(Global.TRUSTSTORE_PASSWORD_SETTING);
|
||||
settingsModule.registerSetting(Global.TRUSTSTORE_ALGORITHM_SETTING);
|
||||
settingsModule.registerSetting(Global.PROTOCOL_SETTING);
|
||||
settingsModule.registerSetting(Global.SESSION_CACHE_SIZE_SETTING);
|
||||
settingsModule.registerSetting(Global.SESSION_CACHE_TIMEOUT_SETTING);
|
||||
settingsModule.registerSetting(Global.CA_PATHS_SETTING);
|
||||
settingsModule.registerSetting(Global.AUTO_GENERATE_SSL_SETTING);
|
||||
settingsModule.registerSetting(Global.AUTO_GEN_RESOLVE_HOST_SETTING);
|
||||
settingsModule.registerSetting(Global.INCLUDE_JDK_CERTS_SETTING);
|
||||
settingsModule.registerSetting(Global.RELOAD_ENABLED_SETTING);
|
||||
}
|
||||
|
||||
private final ESLogger logger;
|
||||
private final Settings settings;
|
||||
private final KeyConfig keyConfig;
|
||||
private final TrustConfig trustConfig;
|
||||
private final String sslProtocol;
|
||||
private final int sessionCacheSize;
|
||||
private final TimeValue sessionCacheTimeout;
|
||||
private final List<String> ciphers;
|
||||
private final List<String> supportedProtocols;
|
||||
|
||||
/**
|
||||
* This constructor should be used with the global settings of the service
|
||||
*
|
||||
* @param settings the global settings to build the SSL configuration from
|
||||
*/
|
||||
@Inject
|
||||
public Global(Settings settings) {
|
||||
this.settings = settings;
|
||||
this.logger = Loggers.getLogger(getClass(), settings);
|
||||
this.keyConfig = createGlobalKeyConfig(settings);
|
||||
this.trustConfig = createGlobalTrustConfig(settings, keyConfig);
|
||||
this.sslProtocol = PROTOCOL_SETTING.get(settings);
|
||||
this.sessionCacheSize = SESSION_CACHE_SIZE_SETTING.get(settings);
|
||||
this.sessionCacheTimeout = SESSION_CACHE_TIMEOUT_SETTING.get(settings);
|
||||
this.ciphers = CIPHERS_SETTING.get(settings);
|
||||
this.supportedProtocols = SUPPORTED_PROTOCOLS_SETTING.get(settings);
|
||||
}
|
||||
|
||||
@Override
|
||||
public KeyConfig keyConfig() {
|
||||
return keyConfig;
|
||||
}
|
||||
|
||||
@Override
|
||||
public TrustConfig trustConfig() {
|
||||
return trustConfig;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String protocol() {
|
||||
return sslProtocol;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int sessionCacheSize() {
|
||||
return sessionCacheSize;
|
||||
}
|
||||
|
||||
@Override
|
||||
public TimeValue sessionCacheTimeout() {
|
||||
return sessionCacheTimeout;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<String> ciphers() {
|
||||
return ciphers;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<String> supportedProtocols() {
|
||||
return supportedProtocols;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "SSLConfiguration{" +
|
||||
", keyConfig=[" + keyConfig +
|
||||
"], trustConfig=" + trustConfig +
|
||||
"], sslProtocol=['" + sslProtocol + '\'' +
|
||||
"], sessionCacheSize=[" + sessionCacheSize +
|
||||
"], sessionCacheTimeout=[" + sessionCacheTimeout +
|
||||
"], ciphers=[" + ciphers +
|
||||
"], supportedProtocols=[" + supportedProtocols +
|
||||
"]}";
|
||||
}
|
||||
|
||||
public void onTransportStart(BoundTransportAddress boundAddress, Map<String, BoundTransportAddress> profileBoundAddresses) {
|
||||
if (shouldAutoGenerateKeyAndCertificate(settings) == false) {
|
||||
return;
|
||||
}
|
||||
|
||||
Set<InetAddress> uniqueAddresses = new HashSet<>();
|
||||
if (boundAddress != null) {
|
||||
// this could be null if we came from a transport client
|
||||
addInetAddresses(uniqueAddresses, boundAddress.boundAddresses());
|
||||
addInetAddresses(uniqueAddresses, boundAddress.publishAddress());
|
||||
}
|
||||
|
||||
for (BoundTransportAddress profileAddress : profileBoundAddresses.values()) {
|
||||
addInetAddresses(uniqueAddresses, profileAddress.boundAddresses());
|
||||
addInetAddresses(uniqueAddresses, profileAddress.publishAddress());
|
||||
}
|
||||
|
||||
try {
|
||||
((AutoGeneratedKeyConfig) keyConfig).generateCertIfNecessary(AUTO_GEN_RESOLVE_HOST_SETTING.get(settings),
|
||||
Node.NODE_NAME_SETTING.get(settings), uniqueAddresses, logger);
|
||||
} catch (Exception e) {
|
||||
throw new ElasticsearchException("failed to initialize auto generated certificate and key");
|
||||
}
|
||||
}
|
||||
|
||||
private static String globalKey(Setting setting) {
|
||||
return setting("ssl." + setting.getKey());
|
||||
}
|
||||
|
||||
static void addInetAddresses(Set<InetAddress> addresses, TransportAddress... transportAddresses) {
|
||||
for (TransportAddress transportAddress : transportAddresses) {
|
||||
addresses.add(((InetSocketTransportAddress)transportAddress).address().getAddress());
|
||||
}
|
||||
}
|
||||
|
||||
static boolean shouldAutoGenerateKeyAndCertificate(Settings settings) {
|
||||
if (AUTO_GENERATE_SSL_SETTING.get(settings) == false) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// did they configure some SSL settings other than auto generate
|
||||
Settings.Builder builder = Settings.builder().put(settings);
|
||||
builder.remove(AUTO_GEN_RESOLVE_HOST_SETTING.getKey());
|
||||
builder.remove(AUTO_GENERATE_SSL_SETTING.getKey());
|
||||
builder.remove(INCLUDE_JDK_CERTS_SETTING.getKey());
|
||||
Settings nonAutoGen = builder.build();
|
||||
if (nonAutoGen.getByPrefix(setting("ssl.")).isEmpty() == false) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// SSL needs to be enabled somewhere
|
||||
final boolean transportEnabled = ShieldNettyTransport.SSL_SETTING.get(settings);
|
||||
final boolean httpEnabled = ShieldNettyHttpServerTransport.SSL_SETTING.get(settings);
|
||||
if (transportEnabled || httpEnabled) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// check the profiles... maybe disabled SSL on default transport and enabled on a profile
|
||||
Map<String, Settings> profiles = TransportSettings.TRANSPORT_PROFILES_SETTING.get(settings).getAsGroups(true);
|
||||
for (Settings profileSettings : profiles.values()) {
|
||||
if (ShieldNettyTransport.profileSsl(profileSettings, settings)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static KeyConfig createGlobalKeyConfig(Settings settings) {
|
||||
if (shouldAutoGenerateKeyAndCertificate(settings)) {
|
||||
return new AutoGeneratedKeyConfig(INCLUDE_JDK_CERTS_SETTING.get(settings));
|
||||
}
|
||||
|
||||
String keyStorePath = KEYSTORE_PATH_SETTING.get(settings).orElse(null);
|
||||
String keyPath = KEY_PATH_SETTING.get(settings).orElse(null);
|
||||
if (keyPath != null && keyStorePath != null) {
|
||||
throw new IllegalArgumentException("you cannot specify a keystore and key file");
|
||||
} else if (keyStorePath == null && keyPath == null) {
|
||||
return KeyConfig.NONE;
|
||||
}
|
||||
|
||||
boolean includeSystem = INCLUDE_JDK_CERTS_SETTING.get(settings);
|
||||
boolean reloadEnabled = RELOAD_ENABLED_SETTING.get(settings);
|
||||
if (keyPath != null) {
|
||||
String keyPassword = KEY_PASSWORD_SETTING.get(settings).orElse(null);
|
||||
List<String> certPaths = getListOrNull(CERT_SETTING, settings);
|
||||
if (certPaths == null) {
|
||||
throw new IllegalArgumentException("you must specify the certificates to use with the key");
|
||||
}
|
||||
return new PEMKeyConfig(includeSystem, reloadEnabled, keyPath, keyPassword, certPaths);
|
||||
} else {
|
||||
assert keyStorePath != null;
|
||||
String keyStorePassword = KEYSTORE_PASSWORD_SETTING.get(settings).orElse(null);
|
||||
String keyStoreAlgorithm = KEYSTORE_ALGORITHM_SETTING.get(settings);
|
||||
String keyStoreKeyPassword = KEYSTORE_KEY_PASSWORD_SETTING.get(settings).orElse(keyStorePassword);
|
||||
String trustStoreAlgorithm = TRUSTSTORE_ALGORITHM_SETTING.get(settings);
|
||||
return new StoreKeyConfig(includeSystem, reloadEnabled, keyStorePath, keyStorePassword, keyStoreKeyPassword,
|
||||
keyStoreAlgorithm, trustStoreAlgorithm);
|
||||
}
|
||||
}
|
||||
|
||||
static TrustConfig createGlobalTrustConfig(Settings settings, KeyConfig keyInfo) {
|
||||
if (keyInfo instanceof AutoGeneratedKeyConfig) {
|
||||
assert shouldAutoGenerateKeyAndCertificate(settings);
|
||||
return keyInfo;
|
||||
}
|
||||
|
||||
String trustStorePath = TRUSTSTORE_PATH_SETTING.get(settings).orElse(null);
|
||||
List<String> caPaths = getListOrNull(CA_PATHS_SETTING, settings);
|
||||
boolean includeSystem = INCLUDE_JDK_CERTS_SETTING.get(settings);
|
||||
boolean reloadEnabled = RELOAD_ENABLED_SETTING.get(settings);
|
||||
if (trustStorePath != null && caPaths != null) {
|
||||
throw new IllegalArgumentException("you cannot specify a truststore and ca files");
|
||||
} else if (caPaths != null) {
|
||||
return new PEMTrustConfig(includeSystem, reloadEnabled, caPaths);
|
||||
} else if (trustStorePath != null) {
|
||||
String trustStorePassword = TRUSTSTORE_PASSWORD_SETTING.get(settings).orElse(null);
|
||||
String trustStoreAlgorithm = TRUSTSTORE_ALGORITHM_SETTING.get(settings);
|
||||
return new StoreTrustConfig(includeSystem, reloadEnabled, trustStorePath, trustStorePassword, trustStoreAlgorithm);
|
||||
} else if (keyInfo != KeyConfig.NONE) {
|
||||
return keyInfo;
|
||||
} else {
|
||||
return new StoreTrustConfig(includeSystem, reloadEnabled, null, null, null);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static class Custom extends SSLConfiguration {
|
||||
|
||||
static final Setting<Optional<String>> PROTOCOL_SETTING = createString("protocol");
|
||||
static final Setting<Optional<Integer>> CACHE_SIZE_SETTING = createInt("session.cache_size");
|
||||
static final Setting<Optional<TimeValue>> CACHE_TIMEOUT_SETTING = createTimeValue("session.cache_timeout");
|
||||
static final Setting<List<String>> CIPHERS_SETTING = Setting.listSetting("ciphers", Collections.emptyList(), s -> s);
|
||||
static final Setting<List<String>> SUPPORTED_PROTOCOLS_SETTING =
|
||||
Setting.listSetting("supported_protocols", Collections.emptyList(), s -> s);
|
||||
|
||||
static final Setting<Optional<String>> KEYSTORE_PATH_SETTING = createString("keystore.path");
|
||||
static final Setting<Optional<String>> KEYSTORE_PASSWORD_SETTING = createString("keystore.password");
|
||||
static final Setting<String> KEYSTORE_ALGORITHM_SETTING = new Setting<>("keystore.algorithm",
|
||||
s -> System.getProperty("ssl.KeyManagerFactory.algorithm", KeyManagerFactory.getDefaultAlgorithm()), Function.identity());
|
||||
static final Setting<Optional<String>> KEYSTORE_KEY_PASSWORD_FALLBACK = createString("keystore.password");
|
||||
static final Setting<Optional<String>> KEYSTORE_KEY_PASSWORD_SETTING =
|
||||
createString("keystore.key_password", KEYSTORE_KEY_PASSWORD_FALLBACK);
|
||||
|
||||
|
||||
static final Setting<Optional<String>> TRUSTSTORE_PATH_SETTING = createString("truststore.path");
|
||||
static final Setting<Optional<String>> TRUSTSTORE_PASSWORD_SETTING = createString("truststore.password");
|
||||
static final Setting<String> TRUSTSTORE_ALGORITHM_SETTING = new Setting<>("truststore.algorithm",
|
||||
s -> System.getProperty("ssl.TrustManagerFactory.algorithm",
|
||||
TrustManagerFactory.getDefaultAlgorithm()), Function.identity());
|
||||
|
||||
static final Setting<Optional<String>> KEY_PATH_SETTING = createString("key.path");
|
||||
static final Setting<Optional<String>> KEY_PASSWORD_SETTING = createString("key.password");
|
||||
static final Setting<List<String>> CERT_SETTING = Setting.listSetting("cert", Collections.emptyList(), s -> s);
|
||||
|
||||
static final Setting<List<String>> CA_PATHS_SETTING = Setting.listSetting("ca", Collections.emptyList(), s -> s);
|
||||
static final Setting<Boolean> INCLUDE_JDK_CERTS_SETTING = Setting.boolSetting("trust_cacerts", true);
|
||||
static final Setting<Boolean> RELOAD_ENABLED_SETTING = Setting.boolSetting("reload.enabled", true);
|
||||
|
||||
private final KeyConfig keyConfig;
|
||||
private final TrustConfig trustConfig;
|
||||
private final String sslProtocol;
|
||||
private final int sessionCacheSize;
|
||||
private final TimeValue sessionCacheTimeout;
|
||||
private final List<String> ciphers;
|
||||
private final List<String> supportedProtocols;
|
||||
|
||||
/**
|
||||
* The settings passed in should be the group settings under ssl, like xpack.security.ssl
|
||||
*
|
||||
* @param settings the profile settings to get the SSL configuration for
|
||||
* @param defaultConfig the default SSL configuration
|
||||
*/
|
||||
public Custom(Settings settings, SSLConfiguration defaultConfig) {
|
||||
Objects.requireNonNull(settings);
|
||||
this.keyConfig = createKeyConfig(settings, defaultConfig);
|
||||
this.trustConfig = createTrustConfig(settings, keyConfig, defaultConfig);
|
||||
this.sslProtocol = PROTOCOL_SETTING.get(settings).orElse(defaultConfig.protocol());
|
||||
this.sessionCacheSize = CACHE_SIZE_SETTING.get(settings).orElse(defaultConfig.sessionCacheSize());
|
||||
this.sessionCacheTimeout = CACHE_TIMEOUT_SETTING.get(settings).orElse(defaultConfig.sessionCacheTimeout());
|
||||
this.ciphers = getListOrDefault(CIPHERS_SETTING, settings, defaultConfig.ciphers());
|
||||
this.supportedProtocols = getListOrDefault(SUPPORTED_PROTOCOLS_SETTING, settings, defaultConfig.supportedProtocols());
|
||||
}
|
||||
|
||||
@Override
|
||||
public KeyConfig keyConfig() {
|
||||
return keyConfig;
|
||||
}
|
||||
|
||||
@Override
|
||||
public TrustConfig trustConfig() {
|
||||
return trustConfig;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String protocol() {
|
||||
return sslProtocol;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int sessionCacheSize() {
|
||||
return sessionCacheSize;
|
||||
}
|
||||
|
||||
@Override
|
||||
public TimeValue sessionCacheTimeout() {
|
||||
return sessionCacheTimeout;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<String> ciphers() {
|
||||
return ciphers;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<String> supportedProtocols() {
|
||||
return supportedProtocols;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "SSLConfiguration{" +
|
||||
", keyConfig=[" + keyConfig +
|
||||
"], trustConfig=" + trustConfig +
|
||||
"], sslProtocol=['" + sslProtocol + '\'' +
|
||||
"], sessionCacheSize=[" + sessionCacheSize +
|
||||
"], sessionCacheTimeout=[" + sessionCacheTimeout +
|
||||
"], ciphers=[" + ciphers +
|
||||
"], supportedProtocols=[" + supportedProtocols +
|
||||
'}';
|
||||
}
|
||||
|
||||
static KeyConfig createKeyConfig(Settings settings, SSLConfiguration global) {
|
||||
String keyStorePath = KEYSTORE_PATH_SETTING.get(settings).orElse(null);
|
||||
String keyPath = KEY_PATH_SETTING.get(settings).orElse(null);
|
||||
if (keyPath != null && keyStorePath != null) {
|
||||
throw new IllegalArgumentException("you cannot specify a keystore and key file");
|
||||
} else if (keyStorePath == null && keyPath == null) {
|
||||
return global.keyConfig();
|
||||
}
|
||||
|
||||
boolean includeSystem = INCLUDE_JDK_CERTS_SETTING.get(settings);
|
||||
boolean reloadEnabled = RELOAD_ENABLED_SETTING.get(settings);
|
||||
if (keyPath != null) {
|
||||
String keyPassword = KEY_PASSWORD_SETTING.get(settings).orElse(null);
|
||||
List<String> certPaths = getListOrNull(CERT_SETTING, settings);
|
||||
if (certPaths == null) {
|
||||
throw new IllegalArgumentException("you must specify the certificates to use with the key");
|
||||
}
|
||||
return new PEMKeyConfig(includeSystem, reloadEnabled, keyPath, keyPassword, certPaths);
|
||||
} else {
|
||||
assert keyStorePath != null;
|
||||
String keyStorePassword = KEYSTORE_PASSWORD_SETTING.get(settings).orElse(null);
|
||||
String keyStoreAlgorithm = KEYSTORE_ALGORITHM_SETTING.get(settings);
|
||||
String keyStoreKeyPassword = KEYSTORE_KEY_PASSWORD_SETTING.get(settings).orElse(keyStorePassword);
|
||||
String trustStoreAlgorithm = TRUSTSTORE_ALGORITHM_SETTING.get(settings);
|
||||
return new StoreKeyConfig(includeSystem, reloadEnabled, keyStorePath, keyStorePassword, keyStoreKeyPassword,
|
||||
keyStoreAlgorithm, trustStoreAlgorithm);
|
||||
}
|
||||
}
|
||||
|
||||
static TrustConfig createTrustConfig(Settings settings, KeyConfig keyConfig, SSLConfiguration global) {
|
||||
String trustStorePath = TRUSTSTORE_PATH_SETTING.get(settings).orElse(null);
|
||||
List<String> caPaths = getListOrNull(CA_PATHS_SETTING, settings);
|
||||
if (trustStorePath != null && caPaths != null) {
|
||||
throw new IllegalArgumentException("you cannot specify a truststore and ca files");
|
||||
} else if (caPaths != null) {
|
||||
return new PEMTrustConfig(INCLUDE_JDK_CERTS_SETTING.get(settings), RELOAD_ENABLED_SETTING.get(settings), caPaths);
|
||||
} else if (trustStorePath != null) {
|
||||
String trustStorePassword = TRUSTSTORE_PASSWORD_SETTING.get(settings).orElse(null);
|
||||
String trustStoreAlgorithm = TRUSTSTORE_ALGORITHM_SETTING.get(settings);
|
||||
return new StoreTrustConfig(INCLUDE_JDK_CERTS_SETTING.get(settings), RELOAD_ENABLED_SETTING.get(settings),
|
||||
trustStorePath, trustStorePassword, trustStoreAlgorithm);
|
||||
} else if (keyConfig == global.keyConfig()) {
|
||||
return global.trustConfig();
|
||||
} else {
|
||||
return keyConfig;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static List<String> getListOrNull(Setting<List<String>> listSetting, Settings settings) {
|
||||
return getListOrDefault(listSetting, settings, null);
|
||||
}
|
||||
|
||||
static List<String> getListOrDefault(Setting<List<String>> listSetting, Settings settings, List<String> defaultValue) {
|
||||
if (listSetting.exists(settings)) {
|
||||
return listSetting.get(settings);
|
||||
}
|
||||
return defaultValue;
|
||||
}
|
||||
}
|
|
@ -7,6 +7,7 @@ package org.elasticsearch.shield.ssl;
|
|||
|
||||
import org.elasticsearch.common.inject.util.Providers;
|
||||
import org.elasticsearch.common.settings.Settings;
|
||||
import org.elasticsearch.shield.ssl.SSLConfiguration.Global;
|
||||
import org.elasticsearch.shield.support.AbstractShieldModule;
|
||||
|
||||
/**
|
||||
|
@ -20,6 +21,7 @@ public class SSLModule extends AbstractShieldModule {
|
|||
|
||||
@Override
|
||||
protected void configure(boolean clientMode) {
|
||||
bind(Global.class).asEagerSingleton();
|
||||
bind(ClientSSLService.class).asEagerSingleton();
|
||||
if (clientMode) {
|
||||
bind(ServerSSLService.class).toProvider(Providers.<ServerSSLService>of(null));
|
||||
|
|
|
@ -1,180 +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.shield.ssl;
|
||||
|
||||
import org.elasticsearch.common.logging.ESLogger;
|
||||
import org.elasticsearch.common.logging.Loggers;
|
||||
import org.elasticsearch.common.settings.Setting;
|
||||
import org.elasticsearch.common.settings.Setting.Property;
|
||||
import org.elasticsearch.common.settings.Settings;
|
||||
import org.elasticsearch.common.settings.SettingsModule;
|
||||
import org.elasticsearch.common.unit.TimeValue;
|
||||
|
||||
import javax.net.ssl.KeyManagerFactory;
|
||||
import javax.net.ssl.TrustManagerFactory;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
import java.util.function.Function;
|
||||
|
||||
import static org.elasticsearch.shield.Security.setting;
|
||||
import static org.elasticsearch.shield.support.OptionalStringSetting.create;
|
||||
|
||||
/**
|
||||
* Class that contains all settings related to SSL
|
||||
*/
|
||||
public class SSLSettings {
|
||||
|
||||
public interface Globals {
|
||||
List<String> DEFAULT_SUPPORTED_PROTOCOLS = Arrays.asList("TLSv1", "TLSv1.1", "TLSv1.2");
|
||||
List<String> DEFAULT_CIPHERS =
|
||||
Arrays.asList("TLS_RSA_WITH_AES_128_CBC_SHA256", "TLS_RSA_WITH_AES_128_CBC_SHA", "TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA");
|
||||
TimeValue DEFAULT_SESSION_CACHE_TIMEOUT = TimeValue.timeValueHours(24);
|
||||
int DEFAULT_SESSION_CACHE_SIZE = 1000;
|
||||
String DEFAULT_PROTOCOL = "TLSv1.2";
|
||||
|
||||
Setting<List<String>> CIPHERS_SETTING =
|
||||
Setting.listSetting(setting("ssl.ciphers"), DEFAULT_CIPHERS, Function.identity(), Property.NodeScope, Property.Filtered);
|
||||
Setting<List<String>> SUPPORTED_PROTOCOLS_SETTING =
|
||||
Setting.listSetting(setting("ssl.supported_protocols"), DEFAULT_SUPPORTED_PROTOCOLS,
|
||||
Function.identity(), Property.NodeScope, Property.Filtered);
|
||||
Setting<Optional<String>> KEYSTORE_PATH_SETTING = create(setting("ssl.keystore.path"),
|
||||
s -> System.getProperty("javax.net.ssl.keyStore"), Property.NodeScope, Property.Filtered);
|
||||
Setting<Optional<String>> KEYSTORE_PASSWORD_SETTING = create(setting("ssl.keystore.password"),
|
||||
s -> System.getProperty("javax.net.ssl.keyStorePassword"), Property.NodeScope, Property.Filtered);
|
||||
Setting<String> KEYSTORE_ALGORITHM_SETTING =
|
||||
new Setting<>(setting("ssl.keystore.algorithm"),
|
||||
s -> System.getProperty("ssl.KeyManagerFactory.algorithm", KeyManagerFactory.getDefaultAlgorithm()),
|
||||
Function.identity(), Property.NodeScope, Property.Filtered);
|
||||
Setting<Optional<String>> KEYSTORE_KEY_PASSWORD_SETTING = create(setting("ssl.keystore.key_password"), KEYSTORE_PASSWORD_SETTING,
|
||||
Property.NodeScope, Property.Filtered);
|
||||
Setting<Optional<String>> TRUSTSTORE_PATH_SETTING = create(setting("ssl.truststore.path"),
|
||||
s -> System.getProperty("javax.net.ssl.trustStore"), Property.NodeScope, Property.Filtered);
|
||||
Setting<Optional<String>> TRUSTSTORE_PASSWORD_SETTING = create(setting("ssl.truststore.password"),
|
||||
s -> System.getProperty("javax.net.ssl.trustStorePassword"), Property.NodeScope, Property.Filtered);
|
||||
Setting<String> TRUSTSTORE_ALGORITHM_SETTING =
|
||||
new Setting<>(setting("ssl.truststore.algorithm"),
|
||||
s -> System.getProperty("ssl.TrustManagerFactory.algorithm", TrustManagerFactory.getDefaultAlgorithm()),
|
||||
Function.identity(), Property.NodeScope, Property.Filtered);
|
||||
Setting<String> PROTOCOL_SETTING =
|
||||
new Setting<>(setting("ssl.protocol"), DEFAULT_PROTOCOL, Function.identity(), Property.NodeScope, Property.Filtered);
|
||||
Setting<Integer> SESSION_CACHE_SIZE_SETTING =
|
||||
Setting.intSetting(setting("ssl.session.cache_size"), DEFAULT_SESSION_CACHE_SIZE, Property.NodeScope, Property.Filtered);
|
||||
Setting<TimeValue> SESSION_CACHE_TIMEOUT_SETTING =
|
||||
Setting.timeSetting(setting("ssl.session.cache_timeout"), DEFAULT_SESSION_CACHE_TIMEOUT,
|
||||
Property.NodeScope, Property.Filtered);
|
||||
}
|
||||
|
||||
private static final ESLogger logger = Loggers.getLogger(SSLSettings.class);
|
||||
|
||||
static Setting<Optional<String>> KEYSTORE_PATH_SETTING = create("keystore.path", Globals.KEYSTORE_PATH_SETTING);
|
||||
static Setting<Optional<String>> KEYSTORE_PASSWORD_SETTING = create("keystore.password", Globals.KEYSTORE_PASSWORD_SETTING);
|
||||
static Setting<String> KEYSTORE_ALGORITHM_SETTING =
|
||||
new Setting<>("keystore.algorithm", Globals.KEYSTORE_ALGORITHM_SETTING, s -> s);
|
||||
|
||||
//key password fallback should be keystore.key_password -> keystore.password -> global keystore.key_pasword -> global keystore.password
|
||||
static Setting<Optional<String>> KEY_PASSWORD_FALLBACK = create("keystore.password", Globals.KEYSTORE_KEY_PASSWORD_SETTING);
|
||||
static Setting<Optional<String>> KEY_PASSWORD_SETTING = create("keystore.key_password", KEY_PASSWORD_FALLBACK);
|
||||
|
||||
static Setting<Optional<String>> TRUSTSTORE_PATH_SETTING = create("truststore.path", Globals.TRUSTSTORE_PATH_SETTING);
|
||||
static Setting<Optional<String>> TRUSTSTORE_PASSWORD_SETTING = create("truststore.password", Globals.TRUSTSTORE_PASSWORD_SETTING);
|
||||
static Setting<String> TRUSTSTORE_ALGORITHM_SETTING =
|
||||
new Setting<>("truststore.algorithm", Globals.TRUSTSTORE_ALGORITHM_SETTING, s -> s);
|
||||
static Setting<String> PROTOCOL_SETTING =
|
||||
new Setting<>("protocol", Globals.PROTOCOL_SETTING, s -> s);
|
||||
static Setting<Integer> CACHE_SIZE_SETTING =
|
||||
new Setting<>("session.cache_size", Globals.SESSION_CACHE_SIZE_SETTING, Integer::parseInt);
|
||||
static Setting<TimeValue> CACHE_TIMEOUT_SETTING =
|
||||
Setting.timeSetting("session.cache_timeout", Globals.SESSION_CACHE_TIMEOUT_SETTING);
|
||||
|
||||
String keyStorePath;
|
||||
String keyStorePassword;
|
||||
String keyStoreAlgorithm;
|
||||
String keyPassword;
|
||||
String trustStorePath;
|
||||
String trustStorePassword;
|
||||
String trustStoreAlgorithm;
|
||||
String sslProtocol;
|
||||
int sessionCacheSize;
|
||||
TimeValue sessionCacheTimeout;
|
||||
|
||||
SSLSettings(Settings settings, Settings sslServiceSettings) {
|
||||
keyStorePath = getStringOrNull(KEYSTORE_PATH_SETTING, settings, sslServiceSettings);
|
||||
keyStorePassword = getStringOrNull(KEYSTORE_PASSWORD_SETTING, settings, sslServiceSettings);
|
||||
keyStoreAlgorithm = KEYSTORE_ALGORITHM_SETTING.get(settings, sslServiceSettings);
|
||||
keyPassword = getStringOrNull(KEY_PASSWORD_SETTING, settings, sslServiceSettings);
|
||||
|
||||
// Truststore settings
|
||||
trustStorePath = getStringOrNull(TRUSTSTORE_PATH_SETTING, settings, sslServiceSettings);
|
||||
trustStorePassword = getStringOrNull(TRUSTSTORE_PASSWORD_SETTING, settings, sslServiceSettings);
|
||||
trustStoreAlgorithm = TRUSTSTORE_ALGORITHM_SETTING.get(settings, sslServiceSettings);
|
||||
|
||||
sslProtocol = PROTOCOL_SETTING.get(settings, sslServiceSettings);
|
||||
sessionCacheSize = CACHE_SIZE_SETTING.get(settings, sslServiceSettings);
|
||||
sessionCacheTimeout = CACHE_TIMEOUT_SETTING.get(settings, sslServiceSettings);
|
||||
|
||||
if (trustStorePath == null) {
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("no truststore defined. using keystore [{}] as truststore", keyStorePath);
|
||||
}
|
||||
trustStorePath = keyStorePath;
|
||||
trustStorePassword = keyStorePassword;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) {
|
||||
return true;
|
||||
}
|
||||
if (o == null || getClass() != o.getClass()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
SSLSettings that = (SSLSettings) o;
|
||||
|
||||
if (keyStorePath != null ? !keyStorePath.equals(that.keyStorePath) : that.keyStorePath != null) {
|
||||
return false;
|
||||
}
|
||||
if (sslProtocol != null ? !sslProtocol.equals(that.sslProtocol) : that.sslProtocol != null) {
|
||||
return false;
|
||||
}
|
||||
if (trustStorePath != null ? !trustStorePath.equals(that.trustStorePath) : that.trustStorePath != null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
int result = keyStorePath != null ? keyStorePath.hashCode() : 0;
|
||||
result = 31 * result + (trustStorePath != null ? trustStorePath.hashCode() : 0);
|
||||
result = 31 * result + (sslProtocol != null ? sslProtocol.hashCode() : 0);
|
||||
return result;
|
||||
}
|
||||
|
||||
public static void registerSettings(SettingsModule settingsModule) {
|
||||
settingsModule.registerSetting(Globals.CIPHERS_SETTING);
|
||||
settingsModule.registerSetting(Globals.SUPPORTED_PROTOCOLS_SETTING);
|
||||
settingsModule.registerSetting(Globals.KEYSTORE_PATH_SETTING);
|
||||
settingsModule.registerSetting(Globals.KEYSTORE_PASSWORD_SETTING);
|
||||
settingsModule.registerSetting(Globals.KEYSTORE_ALGORITHM_SETTING);
|
||||
settingsModule.registerSetting(Globals.KEYSTORE_KEY_PASSWORD_SETTING);
|
||||
settingsModule.registerSetting(Globals.TRUSTSTORE_PATH_SETTING);
|
||||
settingsModule.registerSetting(Globals.TRUSTSTORE_PASSWORD_SETTING);
|
||||
settingsModule.registerSetting(Globals.TRUSTSTORE_ALGORITHM_SETTING);
|
||||
settingsModule.registerSetting(Globals.PROTOCOL_SETTING);
|
||||
settingsModule.registerSetting(Globals.SESSION_CACHE_SIZE_SETTING);
|
||||
settingsModule.registerSetting(Globals.SESSION_CACHE_TIMEOUT_SETTING);
|
||||
}
|
||||
|
||||
private static String getStringOrNull(Setting<Optional<String>> setting, Settings settings, Settings fallbackSettings) {
|
||||
// for settings with complicated fallback we need to try to get it first, if not then try the fallback settings
|
||||
Optional<String> optional = setting.get(settings);
|
||||
return optional.orElse(setting.get(fallbackSettings).orElse(null));
|
||||
}
|
||||
}
|
|
@ -8,30 +8,23 @@ package org.elasticsearch.shield.ssl;
|
|||
import org.elasticsearch.common.inject.Inject;
|
||||
import org.elasticsearch.common.settings.Settings;
|
||||
import org.elasticsearch.env.Environment;
|
||||
import org.elasticsearch.shield.ssl.SSLConfiguration.Global;
|
||||
import org.elasticsearch.watcher.ResourceWatcherService;
|
||||
|
||||
public class ServerSSLService extends AbstractSSLService {
|
||||
|
||||
@Inject
|
||||
public ServerSSLService(Settings settings, Environment environment) {
|
||||
super(settings, environment);
|
||||
public ServerSSLService(Settings settings, Environment environment, Global globalSSLConfiguration,
|
||||
ResourceWatcherService resourceWatcherService) {
|
||||
super(settings, environment, globalSSLConfiguration, resourceWatcherService);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected SSLSettings sslSettings(Settings customSettings) {
|
||||
SSLSettings sslSettings = new SSLSettings(customSettings, settings);
|
||||
|
||||
if (sslSettings.keyStorePath == null) {
|
||||
throw new IllegalArgumentException("no keystore configured");
|
||||
protected void validateSSLConfiguration(SSLConfiguration sslConfiguration) {
|
||||
if (sslConfiguration.keyConfig() == KeyConfig.NONE) {
|
||||
throw new IllegalArgumentException("a key must be configured to act as a server");
|
||||
}
|
||||
if (sslSettings.keyStorePassword == null) {
|
||||
throw new IllegalArgumentException("no keystore password configured");
|
||||
}
|
||||
assert sslSettings.keyPassword != null;
|
||||
|
||||
assert sslSettings.trustStorePath != null;
|
||||
if (sslSettings.trustStorePassword == null) {
|
||||
throw new IllegalArgumentException("no truststore password configured");
|
||||
}
|
||||
return sslSettings;
|
||||
sslConfiguration.keyConfig().validate();
|
||||
sslConfiguration.trustConfig().validate();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,113 @@
|
|||
/*
|
||||
* 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.shield.ssl;
|
||||
|
||||
import org.elasticsearch.ElasticsearchException;
|
||||
import org.elasticsearch.common.Nullable;
|
||||
import org.elasticsearch.env.Environment;
|
||||
|
||||
import javax.net.ssl.X509ExtendedKeyManager;
|
||||
import javax.net.ssl.X509ExtendedTrustManager;
|
||||
import java.io.InputStream;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.security.KeyStore;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
class StoreKeyConfig extends KeyConfig {
|
||||
|
||||
final String keyStorePath;
|
||||
final String keyStorePassword;
|
||||
final String keyStoreAlgorithm;
|
||||
final String keyPassword;
|
||||
final String trustStoreAlgorithm;
|
||||
|
||||
StoreKeyConfig(boolean includeSystem, boolean reloadEnabled, String keyStorePath, String keyStorePassword, String keyPassword,
|
||||
String keyStoreAlgorithm, String trustStoreAlgorithm) {
|
||||
super(includeSystem, reloadEnabled);
|
||||
this.keyStorePath = keyStorePath;
|
||||
this.keyStorePassword = keyStorePassword;
|
||||
this.keyPassword = keyPassword;
|
||||
this.keyStoreAlgorithm = keyStoreAlgorithm;
|
||||
this.trustStoreAlgorithm = trustStoreAlgorithm;
|
||||
}
|
||||
|
||||
@Override
|
||||
X509ExtendedKeyManager[] loadKeyManagers(@Nullable Environment environment) {
|
||||
try (InputStream in = Files.newInputStream(CertUtils.resolvePath(keyStorePath, environment))) {
|
||||
// TODO remove reliance on JKS since we can PKCS12 stores...
|
||||
KeyStore ks = KeyStore.getInstance("jks");
|
||||
assert keyStorePassword != null;
|
||||
ks.load(in, keyStorePassword.toCharArray());
|
||||
return CertUtils.keyManagers(ks, keyPassword.toCharArray(), keyStoreAlgorithm);
|
||||
} catch (Exception e) {
|
||||
throw new ElasticsearchException("failed to initialize a KeyManagerFactory", e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
X509ExtendedTrustManager[] nonSystemTrustManagers(@Nullable Environment environment) {
|
||||
try (InputStream in = Files.newInputStream(CertUtils.resolvePath(keyStorePath, environment))) {
|
||||
// TODO remove reliance on JKS since we can PKCS12 stores...
|
||||
KeyStore ks = KeyStore.getInstance("jks");
|
||||
assert keyStorePassword != null;
|
||||
ks.load(in, keyStorePassword.toCharArray());
|
||||
|
||||
return CertUtils.trustManagers(ks, trustStoreAlgorithm);
|
||||
} catch (Exception e) {
|
||||
throw new ElasticsearchException("failed to initialize a TrustManagerFactory", e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
void validate() {
|
||||
if (keyStorePath == null) {
|
||||
throw new IllegalArgumentException("keystore path must be specified");
|
||||
} else if (keyStorePassword == null) {
|
||||
throw new IllegalArgumentException("no keystore password configured");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
List<Path> filesToMonitor(@Nullable Environment environment) {
|
||||
return Collections.singletonList(CertUtils.resolvePath(keyStorePath, environment));
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) return true;
|
||||
if (o == null || getClass() != o.getClass()) return false;
|
||||
|
||||
StoreKeyConfig that = (StoreKeyConfig) o;
|
||||
|
||||
if (keyStorePath != null ? !keyStorePath.equals(that.keyStorePath) : that.keyStorePath != null) return false;
|
||||
if (keyStorePassword != null ? !keyStorePassword.equals(that.keyStorePassword) : that.keyStorePassword != null)
|
||||
return false;
|
||||
if (keyStoreAlgorithm != null ? !keyStoreAlgorithm.equals(that.keyStoreAlgorithm) : that.keyStoreAlgorithm != null)
|
||||
return false;
|
||||
if (keyPassword != null ? !keyPassword.equals(that.keyPassword) : that.keyPassword != null) return false;
|
||||
return trustStoreAlgorithm != null ? trustStoreAlgorithm.equals(that.trustStoreAlgorithm) : that.trustStoreAlgorithm == null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
int result = keyStorePath != null ? keyStorePath.hashCode() : 0;
|
||||
result = 31 * result + (keyStorePassword != null ? keyStorePassword.hashCode() : 0);
|
||||
result = 31 * result + (keyStoreAlgorithm != null ? keyStoreAlgorithm.hashCode() : 0);
|
||||
result = 31 * result + (keyPassword != null ? keyPassword.hashCode() : 0);
|
||||
result = 31 * result + (trustStoreAlgorithm != null ? trustStoreAlgorithm.hashCode() : 0);
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "keyStorePath=[" + keyStorePath +
|
||||
"], keyStoreAlgorithm=[" + keyStoreAlgorithm +
|
||||
"], trustStoreAlgorithm=[" + trustStoreAlgorithm +
|
||||
"]";
|
||||
}
|
||||
}
|
|
@ -0,0 +1,93 @@
|
|||
/*
|
||||
* 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.shield.ssl;
|
||||
|
||||
import org.elasticsearch.ElasticsearchException;
|
||||
import org.elasticsearch.common.Nullable;
|
||||
import org.elasticsearch.env.Environment;
|
||||
|
||||
import javax.net.ssl.X509ExtendedTrustManager;
|
||||
import java.io.InputStream;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.security.KeyStore;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
class StoreTrustConfig extends TrustConfig {
|
||||
|
||||
final String trustStorePath;
|
||||
final String trustStorePassword;
|
||||
final String trustStoreAlgorithm;
|
||||
|
||||
StoreTrustConfig(boolean includeSystem, boolean reloadEnabled, String trustStorePath, String trustStorePassword,
|
||||
String trustStoreAlgorithm) {
|
||||
super(includeSystem, reloadEnabled);
|
||||
this.trustStorePath = trustStorePath;
|
||||
this.trustStorePassword = trustStorePassword;
|
||||
this.trustStoreAlgorithm = trustStoreAlgorithm;
|
||||
}
|
||||
|
||||
@Override
|
||||
X509ExtendedTrustManager[] nonSystemTrustManagers(@Nullable Environment environment) {
|
||||
if (trustStorePath == null) {
|
||||
return null;
|
||||
}
|
||||
try (InputStream in = Files.newInputStream(CertUtils.resolvePath(trustStorePath, environment))) {
|
||||
// TODO remove reliance on JKS since we can PKCS12 stores...
|
||||
KeyStore trustStore = KeyStore.getInstance("jks");
|
||||
assert trustStorePassword != null;
|
||||
trustStore.load(in, trustStorePassword.toCharArray());
|
||||
return CertUtils.trustManagers(trustStore, trustStoreAlgorithm);
|
||||
} catch (Exception e) {
|
||||
throw new ElasticsearchException("failed to initialize a TrustManagerFactory", e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
void validate() {
|
||||
if (trustStorePath != null) {
|
||||
if (trustStorePassword == null) {
|
||||
throw new IllegalArgumentException("no truststore password configured");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
List<Path> filesToMonitor(@Nullable Environment environment) {
|
||||
return Collections.singletonList(CertUtils.resolvePath(trustStorePath, environment));
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) return true;
|
||||
if (o == null || getClass() != o.getClass()) return false;
|
||||
|
||||
StoreTrustConfig that = (StoreTrustConfig) o;
|
||||
|
||||
if (trustStorePath != null ? !trustStorePath.equals(that.trustStorePath) : that.trustStorePath != null) return false;
|
||||
if (trustStorePassword != null ? !trustStorePassword.equals(that.trustStorePassword) : that.trustStorePassword != null)
|
||||
return false;
|
||||
return trustStoreAlgorithm != null ? trustStoreAlgorithm.equals(that.trustStoreAlgorithm) : that.trustStoreAlgorithm ==
|
||||
null;
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
int result = trustStorePath != null ? trustStorePath.hashCode() : 0;
|
||||
result = 31 * result + (trustStorePassword != null ? trustStorePassword.hashCode() : 0);
|
||||
result = 31 * result + (trustStoreAlgorithm != null ? trustStoreAlgorithm.hashCode() : 0);
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "trustStorePath=[" + trustStorePath +
|
||||
"], trustStoreAlgorithm=[" + trustStoreAlgorithm +
|
||||
"]";
|
||||
}
|
||||
}
|
|
@ -0,0 +1,299 @@
|
|||
/*
|
||||
* 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.shield.ssl;
|
||||
|
||||
import org.elasticsearch.ElasticsearchException;
|
||||
import org.elasticsearch.common.Nullable;
|
||||
import org.elasticsearch.env.Environment;
|
||||
import org.elasticsearch.shield.ssl.TrustConfig.Reloadable.Listener;
|
||||
import org.elasticsearch.watcher.FileChangesListener;
|
||||
import org.elasticsearch.watcher.FileWatcher;
|
||||
import org.elasticsearch.watcher.ResourceWatcherService;
|
||||
import org.elasticsearch.watcher.ResourceWatcherService.Frequency;
|
||||
|
||||
import javax.net.ssl.SSLEngine;
|
||||
import javax.net.ssl.TrustManager;
|
||||
import javax.net.ssl.TrustManagerFactory;
|
||||
import javax.net.ssl.X509ExtendedTrustManager;
|
||||
import javax.net.ssl.X509TrustManager;
|
||||
import java.io.IOException;
|
||||
import java.net.Socket;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.security.KeyStore;
|
||||
import java.security.cert.CertificateException;
|
||||
import java.security.cert.X509Certificate;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
abstract class TrustConfig {
|
||||
|
||||
protected final boolean includeSystem;
|
||||
protected final boolean reloadEnabled;
|
||||
|
||||
TrustConfig(boolean includeSystem, boolean reloadEnabled) {
|
||||
this.includeSystem = includeSystem;
|
||||
this.reloadEnabled = reloadEnabled;
|
||||
}
|
||||
|
||||
final TrustManager[] trustManagers(@Nullable Environment environment, @Nullable ResourceWatcherService resourceWatcherService,
|
||||
@Nullable Listener listener) {
|
||||
X509ExtendedTrustManager[] trustManagers = loadAndMergeIfNecessary(environment);
|
||||
if (reloadEnabled && resourceWatcherService != null && listener != null) {
|
||||
ReloadableTrustManager reloadableTrustManager = new ReloadableTrustManager(trustManagers[0], environment);
|
||||
try {
|
||||
List<Path> filesToMonitor = filesToMonitor(environment);
|
||||
ChangeListener changeListener = new ChangeListener(filesToMonitor, reloadableTrustManager, listener);
|
||||
for (Path path : directoriesToMonitor(filesToMonitor)) {
|
||||
FileWatcher fileWatcher = new FileWatcher(path);
|
||||
fileWatcher.addListener(changeListener);
|
||||
resourceWatcherService.add(fileWatcher, Frequency.HIGH);
|
||||
}
|
||||
return new X509ExtendedTrustManager[] { reloadableTrustManager };
|
||||
} catch (IOException e) {
|
||||
throw new ElasticsearchException("failed to add file watcher", e);
|
||||
}
|
||||
}
|
||||
return trustManagers;
|
||||
}
|
||||
|
||||
abstract X509ExtendedTrustManager[] nonSystemTrustManagers(@Nullable Environment environment);
|
||||
|
||||
abstract void validate();
|
||||
|
||||
abstract List<Path> filesToMonitor(@Nullable Environment environment);
|
||||
|
||||
public abstract String toString();
|
||||
|
||||
private X509ExtendedTrustManager[] loadAndMergeIfNecessary(@Nullable Environment environment) {
|
||||
X509ExtendedTrustManager[] nonSystemTrustManagers = nonSystemTrustManagers(environment);
|
||||
if (includeSystem) {
|
||||
return mergeWithSystem(nonSystemTrustManagers);
|
||||
} else if (nonSystemTrustManagers == null || nonSystemTrustManagers.length == 0) {
|
||||
return new X509ExtendedTrustManager[0];
|
||||
}
|
||||
return nonSystemTrustManagers;
|
||||
}
|
||||
|
||||
private X509ExtendedTrustManager[] mergeWithSystem(X509ExtendedTrustManager[] nonSystemTrustManagers) {
|
||||
try {
|
||||
TrustManagerFactory tmf = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
|
||||
tmf.init((KeyStore) null);
|
||||
TrustManager[] systemTrustManagers = tmf.getTrustManagers();
|
||||
X509ExtendedTrustManager system = findFirstX509TrustManager(systemTrustManagers);
|
||||
if (nonSystemTrustManagers == null || nonSystemTrustManagers.length == 0) {
|
||||
return new X509ExtendedTrustManager[] { system };
|
||||
}
|
||||
|
||||
return new X509ExtendedTrustManager[] { new CombiningX509TrustManager(nonSystemTrustManagers[0], system) };
|
||||
} catch (Exception e) {
|
||||
throw new ElasticsearchException("failed to initialize a trust managers", e);
|
||||
}
|
||||
}
|
||||
|
||||
private static X509ExtendedTrustManager findFirstX509TrustManager(TrustManager[] trustManagers) {
|
||||
X509ExtendedTrustManager x509TrustManager = null;
|
||||
for (TrustManager trustManager : trustManagers) {
|
||||
if (trustManager instanceof X509TrustManager) {
|
||||
// first one wins like in the JDK
|
||||
x509TrustManager = (X509ExtendedTrustManager) trustManager;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (x509TrustManager == null) {
|
||||
throw new IllegalArgumentException("did not find a X509TrustManager");
|
||||
}
|
||||
return x509TrustManager;
|
||||
}
|
||||
|
||||
static Set<Path> directoriesToMonitor(List<Path> filePaths) {
|
||||
Set<Path> paths = new HashSet<>();
|
||||
for (Path path : filePaths) {
|
||||
assert Files.isDirectory(path) == false;
|
||||
paths.add(path.getParent());
|
||||
}
|
||||
return paths;
|
||||
}
|
||||
|
||||
private static class CombiningX509TrustManager extends X509ExtendedTrustManager {
|
||||
|
||||
private final X509ExtendedTrustManager first;
|
||||
private final X509ExtendedTrustManager second;
|
||||
|
||||
private final X509Certificate[] acceptedIssuers;
|
||||
|
||||
CombiningX509TrustManager(X509ExtendedTrustManager first, X509ExtendedTrustManager second) {
|
||||
this.first = first;
|
||||
this.second = second;
|
||||
X509Certificate[] firstIssuers = first.getAcceptedIssuers();
|
||||
X509Certificate[] secondIssuers = second.getAcceptedIssuers();
|
||||
this.acceptedIssuers = new X509Certificate[firstIssuers.length + secondIssuers.length];
|
||||
System.arraycopy(firstIssuers, 0, acceptedIssuers, 0, firstIssuers.length);
|
||||
System.arraycopy(secondIssuers, 0, acceptedIssuers, firstIssuers.length, secondIssuers.length);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void checkClientTrusted(X509Certificate[] x509Certificates, String s, Socket socket) throws CertificateException {
|
||||
try {
|
||||
first.checkClientTrusted(x509Certificates, s, socket);
|
||||
} catch (CertificateException e) {
|
||||
second.checkClientTrusted(x509Certificates, s, socket);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void checkServerTrusted(X509Certificate[] x509Certificates, String s, Socket socket) throws CertificateException {
|
||||
try {
|
||||
first.checkServerTrusted(x509Certificates, s, socket);
|
||||
} catch (CertificateException e) {
|
||||
second.checkServerTrusted(x509Certificates, s, socket);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void checkClientTrusted(X509Certificate[] x509Certificates, String s, SSLEngine sslEngine) throws CertificateException {
|
||||
try {
|
||||
first.checkClientTrusted(x509Certificates, s, sslEngine);
|
||||
} catch (CertificateException e) {
|
||||
second.checkClientTrusted(x509Certificates, s, sslEngine);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void checkServerTrusted(X509Certificate[] x509Certificates, String s, SSLEngine sslEngine) throws CertificateException {
|
||||
try {
|
||||
first.checkServerTrusted(x509Certificates, s, sslEngine);
|
||||
} catch (CertificateException e) {
|
||||
second.checkServerTrusted(x509Certificates, s, sslEngine);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void checkClientTrusted(X509Certificate[] x509Certificates, String s) throws CertificateException {
|
||||
try {
|
||||
first.checkClientTrusted(x509Certificates, s);
|
||||
} catch (CertificateException e) {
|
||||
second.checkClientTrusted(x509Certificates, s);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void checkServerTrusted(X509Certificate[] x509Certificates, String s) throws CertificateException {
|
||||
try {
|
||||
first.checkServerTrusted(x509Certificates, s);
|
||||
} catch (CertificateException e) {
|
||||
second.checkServerTrusted(x509Certificates, s);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public X509Certificate[] getAcceptedIssuers() {
|
||||
return acceptedIssuers;
|
||||
}
|
||||
}
|
||||
|
||||
final class ReloadableTrustManager extends X509ExtendedTrustManager implements Reloadable {
|
||||
|
||||
private final Environment environment;
|
||||
private volatile X509ExtendedTrustManager trustManager;
|
||||
|
||||
ReloadableTrustManager(X509ExtendedTrustManager trustManager, @Nullable Environment environment) {
|
||||
this.trustManager = trustManager;
|
||||
this.environment = environment;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void checkClientTrusted(X509Certificate[] x509Certificates, String s, Socket socket) throws CertificateException {
|
||||
trustManager.checkClientTrusted(x509Certificates, s, socket);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void checkServerTrusted(X509Certificate[] x509Certificates, String s, Socket socket) throws CertificateException {
|
||||
trustManager.checkServerTrusted(x509Certificates, s, socket);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void checkClientTrusted(X509Certificate[] x509Certificates, String s, SSLEngine sslEngine) throws CertificateException {
|
||||
trustManager.checkClientTrusted(x509Certificates, s, sslEngine);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void checkServerTrusted(X509Certificate[] x509Certificates, String s, SSLEngine sslEngine) throws CertificateException {
|
||||
trustManager.checkServerTrusted(x509Certificates, s, sslEngine);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void checkClientTrusted(X509Certificate[] x509Certificates, String s) throws CertificateException {
|
||||
trustManager.checkClientTrusted(x509Certificates, s);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void checkServerTrusted(X509Certificate[] x509Certificates, String s) throws CertificateException {
|
||||
trustManager.checkServerTrusted(x509Certificates, s);
|
||||
}
|
||||
|
||||
@Override
|
||||
public X509Certificate[] getAcceptedIssuers() {
|
||||
return trustManager.getAcceptedIssuers();
|
||||
}
|
||||
|
||||
public synchronized void reload() {
|
||||
X509ExtendedTrustManager[] array = loadAndMergeIfNecessary(environment);
|
||||
this.trustManager = array[0];
|
||||
}
|
||||
|
||||
synchronized void setTrustManager(X509ExtendedTrustManager trustManager) {
|
||||
this.trustManager = trustManager;
|
||||
}
|
||||
}
|
||||
|
||||
interface Reloadable {
|
||||
|
||||
void reload();
|
||||
|
||||
interface Listener {
|
||||
|
||||
void onReload();
|
||||
|
||||
void onFailure(Exception e);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
protected static class ChangeListener extends FileChangesListener {
|
||||
|
||||
private final List<Path> paths;
|
||||
private final Reloadable reloadable;
|
||||
private final Listener listener;
|
||||
|
||||
protected ChangeListener(List<Path> paths, Reloadable reloadable, Listener listener) {
|
||||
this.paths = paths;
|
||||
this.reloadable = reloadable;
|
||||
this.listener = listener;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onFileDeleted(Path file) {
|
||||
onFileChanged(file);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onFileChanged(Path file) {
|
||||
for (Path path : paths) {
|
||||
if (file.equals(path)) {
|
||||
try {
|
||||
reloadable.reload();
|
||||
listener.onReload();
|
||||
} catch (Exception e) {
|
||||
listener.onFailure(e);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,51 @@
|
|||
/*
|
||||
* 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.shield.support;
|
||||
|
||||
import org.elasticsearch.common.settings.Setting;
|
||||
import org.elasticsearch.common.settings.Setting.Property;
|
||||
import org.elasticsearch.common.settings.Settings;
|
||||
import org.elasticsearch.common.unit.TimeValue;
|
||||
|
||||
import java.util.Optional;
|
||||
import java.util.function.Function;
|
||||
|
||||
public class OptionalSettings {
|
||||
|
||||
private OptionalSettings() {}
|
||||
|
||||
public static Setting<Optional<Integer>> createInt(String key, Property... properties) {
|
||||
return new Setting<>(key, s -> null, s -> {
|
||||
if (s != null) {
|
||||
return Optional.of(Integer.parseInt(s));
|
||||
} else {
|
||||
return Optional.<Integer>ofNullable(null);
|
||||
}
|
||||
}, properties);
|
||||
}
|
||||
|
||||
public static Setting<Optional<String>> createString(String key, Property... properties) {
|
||||
return createString(key, s -> null, properties);
|
||||
}
|
||||
|
||||
public static Setting<Optional<String>> createString(String key, Function<Settings, String> defaultValue, Property... properties) {
|
||||
return new Setting<>(key, defaultValue, Optional::ofNullable, properties);
|
||||
}
|
||||
|
||||
public static Setting<Optional<String>> createString(String key, Setting<Optional<String>> fallback, Property... properties) {
|
||||
return new Setting<>(key, fallback, Optional::ofNullable, properties);
|
||||
}
|
||||
|
||||
public static Setting<Optional<TimeValue>> createTimeValue(String key, Property... properties) {
|
||||
return new Setting<>(key, s-> null, s -> {
|
||||
if (s != null) {
|
||||
return Optional.of(TimeValue.parseTimeValue(s, key));
|
||||
} else {
|
||||
return Optional.<TimeValue>ofNullable(null);
|
||||
}
|
||||
}, properties);
|
||||
}
|
||||
}
|
|
@ -1,30 +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.shield.support;
|
||||
|
||||
import org.elasticsearch.common.settings.Setting;
|
||||
import org.elasticsearch.common.settings.Setting.Property;
|
||||
import org.elasticsearch.common.settings.Settings;
|
||||
|
||||
import java.util.Optional;
|
||||
import java.util.function.Function;
|
||||
|
||||
public class OptionalStringSetting {
|
||||
|
||||
private OptionalStringSetting() {}
|
||||
|
||||
public static Setting<Optional<String>> create(String key, Property... properties) {
|
||||
return create(key, s -> null, properties);
|
||||
}
|
||||
|
||||
public static Setting<Optional<String>> create(String key, Function<Settings, String> defaultValue, Property... properties) {
|
||||
return new Setting<>(key, defaultValue, Optional::ofNullable, properties);
|
||||
}
|
||||
|
||||
public static Setting<Optional<String>> create(String key, Setting<Optional<String>> fallback, Property... properties) {
|
||||
return new Setting<>(key, fallback, Optional::ofNullable, properties);
|
||||
}
|
||||
}
|
|
@ -13,6 +13,7 @@ import org.elasticsearch.common.settings.Settings;
|
|||
import org.elasticsearch.common.settings.SettingsModule;
|
||||
import org.elasticsearch.common.util.BigArrays;
|
||||
import org.elasticsearch.http.netty.NettyHttpServerTransport;
|
||||
import org.elasticsearch.shield.ssl.SSLConfiguration.Global;
|
||||
import org.elasticsearch.shield.ssl.ServerSSLService;
|
||||
import org.elasticsearch.shield.transport.SSLClientAuth;
|
||||
import org.elasticsearch.shield.transport.filter.IPFilter;
|
||||
|
@ -25,6 +26,8 @@ import org.jboss.netty.handler.ssl.SslHandler;
|
|||
|
||||
import javax.net.ssl.SSLEngine;
|
||||
|
||||
import java.util.Collections;
|
||||
|
||||
import static org.elasticsearch.shield.Security.setting;
|
||||
import static org.elasticsearch.shield.transport.SSLExceptionHelper.isCloseDuringHandshakeException;
|
||||
import static org.elasticsearch.shield.transport.SSLExceptionHelper.isNotSslRecordException;
|
||||
|
@ -44,18 +47,28 @@ public class ShieldNettyHttpServerTransport extends NettyHttpServerTransport {
|
|||
public static final Setting<SSLClientAuth> CLIENT_AUTH_SETTING =
|
||||
new Setting<>(setting("http.ssl.client.auth"), CLIENT_AUTH_DEFAULT, SSLClientAuth::parse, Property.NodeScope);
|
||||
|
||||
|
||||
private final IPFilter ipFilter;
|
||||
private final ServerSSLService sslService;
|
||||
private final boolean ssl;
|
||||
private final Settings sslSettings;
|
||||
private final Global globalSSLConfiguration;
|
||||
|
||||
@Inject
|
||||
public ShieldNettyHttpServerTransport(Settings settings, NetworkService networkService, BigArrays bigArrays, IPFilter ipFilter,
|
||||
ServerSSLService sslService, ThreadPool threadPool) {
|
||||
ServerSSLService sslService, ThreadPool threadPool, Global sslConfig) {
|
||||
super(settings, networkService, bigArrays, threadPool);
|
||||
this.ipFilter = ipFilter;
|
||||
this.ssl = SSL_SETTING.get(settings);
|
||||
this.sslService = sslService;
|
||||
this.globalSSLConfiguration = sslConfig;
|
||||
if (ssl) {
|
||||
Settings.Builder builder = Settings.builder().put(settings.getByPrefix(setting("http.ssl.")));
|
||||
builder.remove("client.auth");
|
||||
builder.remove("enabled");
|
||||
sslSettings = builder.build();
|
||||
} else {
|
||||
sslSettings = Settings.EMPTY;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -87,6 +100,7 @@ public class ShieldNettyHttpServerTransport extends NettyHttpServerTransport {
|
|||
@Override
|
||||
protected void doStart() {
|
||||
super.doStart();
|
||||
globalSSLConfiguration.onTransportStart(this.boundAddress(), Collections.emptyMap());
|
||||
ipFilter.setBoundHttpTransportAddress(this.boundAddress());
|
||||
}
|
||||
|
||||
|
@ -108,7 +122,7 @@ public class ShieldNettyHttpServerTransport extends NettyHttpServerTransport {
|
|||
public ChannelPipeline getPipeline() throws Exception {
|
||||
ChannelPipeline pipeline = super.getPipeline();
|
||||
if (ssl) {
|
||||
SSLEngine engine = sslService.createSSLEngine();
|
||||
SSLEngine engine = sslService.createSSLEngine(sslSettings);
|
||||
engine.setUseClientMode(false);
|
||||
clientAuth.configure(engine);
|
||||
|
||||
|
|
|
@ -18,6 +18,7 @@ import org.elasticsearch.common.settings.SettingsModule;
|
|||
import org.elasticsearch.common.util.BigArrays;
|
||||
import org.elasticsearch.indices.breaker.CircuitBreakerService;
|
||||
import org.elasticsearch.shield.ssl.ClientSSLService;
|
||||
import org.elasticsearch.shield.ssl.SSLConfiguration.Global;
|
||||
import org.elasticsearch.shield.ssl.ServerSSLService;
|
||||
import org.elasticsearch.shield.transport.SSLClientAuth;
|
||||
import org.elasticsearch.shield.transport.filter.IPFilter;
|
||||
|
@ -35,6 +36,7 @@ import javax.net.ssl.SSLEngine;
|
|||
import javax.net.ssl.SSLParameters;
|
||||
import java.net.InetSocketAddress;
|
||||
|
||||
import static org.elasticsearch.shield.Security.featureEnabledSetting;
|
||||
import static org.elasticsearch.shield.Security.setting;
|
||||
import static org.elasticsearch.shield.Security.settingPrefix;
|
||||
import static org.elasticsearch.shield.transport.SSLExceptionHelper.isCloseDuringHandshakeException;
|
||||
|
@ -46,10 +48,13 @@ import static org.elasticsearch.shield.transport.SSLExceptionHelper.isNotSslReco
|
|||
public class ShieldNettyTransport extends NettyTransport {
|
||||
|
||||
public static final String CLIENT_AUTH_DEFAULT = SSLClientAuth.REQUIRED.name();
|
||||
public static final boolean SSL_DEFAULT = false;
|
||||
public static final boolean SSL_DEFAULT = true;
|
||||
|
||||
public static final Setting<Boolean> DEPRECATED_HOSTNAME_VERIFICATION_SETTING =
|
||||
Setting.boolSetting(setting("ssl.hostname_verification"), true, Property.NodeScope, Property.Filtered, Property.Deprecated);
|
||||
public static final Setting<Boolean> HOSTNAME_VERIFICATION_SETTING =
|
||||
Setting.boolSetting(setting("ssl.hostname_verification"), true, Property.NodeScope, Property.Filtered);
|
||||
Setting.boolSetting(featureEnabledSetting("ssl.hostname_verification"), DEPRECATED_HOSTNAME_VERIFICATION_SETTING,
|
||||
Property.NodeScope, Property.Filtered);
|
||||
public static final Setting<Boolean> HOSTNAME_VERIFICATION_RESOLVE_NAME_SETTING =
|
||||
Setting.boolSetting(setting("ssl.hostname_verification.resolve_name"), true, Property.NodeScope, Property.Filtered);
|
||||
|
||||
|
@ -74,6 +79,7 @@ public class ShieldNettyTransport extends NettyTransport {
|
|||
|
||||
private final ServerSSLService serverSslService;
|
||||
private final ClientSSLService clientSSLService;
|
||||
private final Global globalSSLConfiguration;
|
||||
private final @Nullable IPFilter authenticator;
|
||||
private final boolean ssl;
|
||||
|
||||
|
@ -81,17 +87,19 @@ public class ShieldNettyTransport extends NettyTransport {
|
|||
public ShieldNettyTransport(Settings settings, ThreadPool threadPool, NetworkService networkService, BigArrays bigArrays,
|
||||
Version version, @Nullable IPFilter authenticator, @Nullable ServerSSLService serverSSLService,
|
||||
ClientSSLService clientSSLService, NamedWriteableRegistry namedWriteableRegistry,
|
||||
CircuitBreakerService circuitBreakerService) {
|
||||
CircuitBreakerService circuitBreakerService, Global globalSSLConfiguration) {
|
||||
super(settings, threadPool, networkService, bigArrays, version, namedWriteableRegistry, circuitBreakerService);
|
||||
this.authenticator = authenticator;
|
||||
this.ssl = SSL_SETTING.get(settings);
|
||||
this.serverSslService = serverSSLService;
|
||||
this.clientSSLService = clientSSLService;
|
||||
this.globalSSLConfiguration = globalSSLConfiguration;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void doStart() {
|
||||
super.doStart();
|
||||
globalSSLConfiguration.onTransportStart(boundAddress, profileBoundAddresses);
|
||||
if (authenticator != null) {
|
||||
authenticator.setBoundTransportAddress(this.boundAddress(), profileBoundAddresses());
|
||||
}
|
||||
|
@ -139,7 +147,7 @@ public class ShieldNettyTransport extends NettyTransport {
|
|||
// we can't use the fallback mechanism here since it may not exist in the profile settings and we get the wrong value
|
||||
// for the profile if they use the old setting
|
||||
if (PROFILE_SSL_SETTING.exists(profileSettings)) {
|
||||
return SSL_SETTING.get(profileSettings);
|
||||
return PROFILE_SSL_SETTING.get(profileSettings);
|
||||
} else if (DEPRECATED_PROFILE_SSL_SETTING.exists(profileSettings)) {
|
||||
return DEPRECATED_PROFILE_SSL_SETTING.get(profileSettings);
|
||||
} else {
|
||||
|
@ -256,5 +264,6 @@ public class ShieldNettyTransport extends NettyTransport {
|
|||
// deprecated transport settings
|
||||
settingsModule.registerSetting(DEPRECATED_SSL_SETTING);
|
||||
settingsModule.registerSetting(DEPRECATED_PROFILE_SSL_SETTING);
|
||||
settingsModule.registerSetting(DEPRECATED_HOSTNAME_VERIFICATION_SETTING);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,22 @@
|
|||
-----BEGIN CERTIFICATE-----
|
||||
MIIDsjCCApqgAwIBAgIJAKGDffMf8r51MA0GCSqGSIb3DQEBCwUAMEQxGTAXBgNV
|
||||
BAoTEEVsYXN0aWNzZWFyY2ggQlYxCzAJBgNVBAYTAk5MMRowGAYDVQQDExFYLVBh
|
||||
Y2sgRGVmYXVsdCBDQTAeFw0xNjA0MTkxNDQ1NDdaFw0yMTA0MTgxNDQ1NDdaMEQx
|
||||
GTAXBgNVBAoTEEVsYXN0aWNzZWFyY2ggQlYxCzAJBgNVBAYTAk5MMRowGAYDVQQD
|
||||
ExFYLVBhY2sgRGVmYXVsdCBDQTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoC
|
||||
ggEBAMEtxhGU9TNgfaYFYFTehSkI1tCxPoe9WdvLd6Ag1DggN2Sp65xhDuWLNX4R
|
||||
mAo7PyXvic+shqfLDjca6R7OgisubldFN3qiw8IwXzjMey/MC0pThsPJS9TQFc6i
|
||||
a4oNmd4QpvoctqAW8qCOqB+PEUNMx6B54sjqX1/CBGuCB4HZJud//RRbANAf8WKN
|
||||
nf4z9vM4nk4m6UF0hShCuKdlU+zlDp0/LdkuYn+fn6JmWVNmwMR4Ym9M1i0RKaBI
|
||||
OE0pgPVIYTRhuU+VyCRGg4ue7tdPlWpps25EihgwEWoieS0lLSGPqEVPC7Msk+HA
|
||||
kOs4DwJahs0RAep+PJNNrcdSB/0CAwEAAaOBpjCBozAMBgNVHRMEBTADAQH/MB0G
|
||||
A1UdDgQWBBR5tSUNfOVoB2DrCDjFIauzzxsP+DB0BgNVHSMEbTBrgBR5tSUNfOVo
|
||||
B2DrCDjFIauzzxsP+KFIpEYwRDEZMBcGA1UEChMQRWxhc3RpY3NlYXJjaCBCVjEL
|
||||
MAkGA1UEBhMCTkwxGjAYBgNVBAMTEVgtUGFjayBEZWZhdWx0IENBggkAoYN98x/y
|
||||
vnUwDQYJKoZIhvcNAQELBQADggEBAIv6mt9qW93Y8ZKD7neiYvS6lzN6/yTCRDZ0
|
||||
sPMYX1BV4dgwIfa3Nc5Iz7fl9MJRQMUaQg1yDmQzoavtRtw8K2Rd1GHtF1pRBwz6
|
||||
y2th20gVGKXtIyaS5l8oxJ5nlV+GX439In8ovM8Q0CqRN/3X36v77OTTt/FCt24w
|
||||
8cA6igo9DMfLylfhIU6R3rcImMMPPE/cgXSE6lPCBX0zK2m1h3Bsp9cNAgndUsI6
|
||||
1xSfnDoO+DuOrze6NX9gzFvy6IwgcTF9vlQ55eXAgy263+k7IhBQydFscNrIFpM5
|
||||
enqQIqgzcEs5FZcq/V1RWlI5phxsOYaImoN9MJMSO9D3avWOtcE=
|
||||
-----END CERTIFICATE-----
|
|
@ -0,0 +1,30 @@
|
|||
-----BEGIN RSA PRIVATE KEY-----
|
||||
Proc-Type: 4,ENCRYPTED
|
||||
DEK-Info: DES-EDE3-CBC,BF10B2B7AF64C239
|
||||
|
||||
xWhoEPwuO8I2qXRG5nSVSPXLltxmzmTxK3VvZPxaf++PTMt+r3F414px763NWigr
|
||||
Wka3f6p2EJI3huafk47mth02OS268A6hCx3wrp9pq0SrzZVTHqML0OqyNyLJNK8j
|
||||
azu6IdCFNaFsh6Z5y2PSJ8SWAX11QcYF6g8IRBwGcGr4pmMdJmKEoliuxJ0oGJIy
|
||||
0hEdeeqiiwEMP2I97CH3g+CtD8eh3+XyNapzSWe7j2Y3wU9lrVUdicUPDOibLVbU
|
||||
xiLz+HJ0BmNbHF3ND8JiDAZUAYQVjvENHP3VIqm68kzRiHcxsHzVhW6iNz1QTwmR
|
||||
vugODGkOoYCV0Yfap1Fjawt7bT0emGU7Lbv/E80X43t4kgoeIOGxX96XYIfwJT9C
|
||||
VVYwtmn85Fr8FmmPRIUYJlMlqm+mvwcRdBxYXKyaamvN7cj8G5pj5A7dgXlSAz7z
|
||||
JaywteP3GzXdzXAS+ehYrZCkBkdIaMbtNIBFV9ZChDvKWJidGkpajDQtSTNixEnS
|
||||
42+qMmg4b0AWEcPtlJJJuYZmgl3XXLkfgiyiQ6dnATyq5tE5PxSzHorUCBIv4Bp3
|
||||
sJCcgsP7TTy3dhr+dyQdsWCVyM9HxUeUzxVj4ULfB6wTAd6duMNHxiIkh3bsxdni
|
||||
xRm2vNQraW64K/xDTsccbp2emhKpJT3KAU2+ZFAEQUJDMejoQv0b1klOcGZGFKh3
|
||||
IMmwaSdZfRfh3pIDyRJARHkQ5fPv19SKwtUmwL1ygqR0iRcK7kN9D+lvhzL7RYcP
|
||||
bKkndgr5jwHdqdGZvrFz2NshcqOwKzKr1tTkXRL8BN6s1s4Az1NQBWyK+bjotF+D
|
||||
zf3HDUGa94xYF5KFbZCKMUenL4OV+K4qqUvbwqBE/s4rsUkB6p9SSySFc9M8Obmm
|
||||
U6ZP4hr7/WZpO0AZr6OUX6HMXCeIex0tanINVijDR8Qq7zwa0Nt1t4bnfGbEqPo+
|
||||
ew5MWjxqEWOb7cJogIjTKokcLqlp4OyVYkP5XdXNqKrnNE23xQNeTeD+W1zZxuJo
|
||||
KdYQA82NC8vW1uHeEfCiJx4Giziqg6zEhNtF6t0wHebGfLORDICvNsb0Df2tYunj
|
||||
rtduSaQRVGTT8YRheJFl0B+n8xrLTOqtbFL6PPb/eU4O3C0La8h8VZNSmXBTY/0A
|
||||
UfeHsxmO7SoAdz8cSiXjvlwVwkt0gbPCbFBTSwALTS0vMas71xI62Dl53EsEup0K
|
||||
oV9agBfEZyVlse8VC/Js8sZi7cICmCrHcvhKWnju3QB47vPti00/aj6MgE0oLHC4
|
||||
8CicYeFCyREaxzF+HnOriuG3f82wUfJhtejwefE4xytvJTBTz+5f2j+FI2CL4OGp
|
||||
R6ix+r/JoygSSIssmxnpcUZQpCxbthfvfBQEvQKq6YDgwgSDfhWAFvLTx45HFDz5
|
||||
if/wgMDTlL9BP+PcNY4xY73qU9Za1AYdDdS9nWSD3pRz9SZc4gRrLLdLmRzUsCU+
|
||||
t2Lrvy0AAFVBzf1RZYN0kVArUdgFGiUQyvsyGyFu8FYww23VZuxglIniHVD5JBa+
|
||||
gymaHiWlKadGciVT552SuYFz89c8nkRFiSEwz/1aLNHP/fFqfVCD2A==
|
||||
-----END RSA PRIVATE KEY-----
|
|
@ -19,8 +19,7 @@ import org.elasticsearch.http.HttpServerTransport;
|
|||
import org.elasticsearch.plugins.Plugin;
|
||||
import org.elasticsearch.shield.authc.support.SecuredString;
|
||||
import org.elasticsearch.shield.authc.support.UsernamePasswordToken;
|
||||
import org.elasticsearch.shield.ssl.AbstractSSLService;
|
||||
import org.elasticsearch.shield.ssl.SSLSettings;
|
||||
import org.elasticsearch.shield.ssl.SSLConfiguration.Global;
|
||||
import org.elasticsearch.test.ESIntegTestCase.ClusterScope;
|
||||
import org.elasticsearch.test.ShieldIntegTestCase;
|
||||
import org.elasticsearch.test.ShieldSettingsSource;
|
||||
|
@ -112,7 +111,7 @@ public class SettingsFilterTests extends ShieldIntegTestCase {
|
|||
|
||||
.put("xpack.security.ssl.keystore.path", "/path/to/keystore")
|
||||
.put("xpack.security.ssl.ciphers", "_ciphers")
|
||||
.put("xpack.security.ssl.supported_protocols", randomFrom(SSLSettings.Globals.DEFAULT_SUPPORTED_PROTOCOLS))
|
||||
.put("xpack.security.ssl.supported_protocols", randomFrom(Global.DEFAULT_SUPPORTED_PROTOCOLS))
|
||||
.put("xpack.security.ssl.keystore.password", randomAsciiOfLength(5))
|
||||
.put("xpack.security.ssl.keystore.algorithm", "_algorithm")
|
||||
.put("xpack.security.ssl.keystore.key_password", randomAsciiOfLength(5))
|
||||
|
@ -124,7 +123,7 @@ public class SettingsFilterTests extends ShieldIntegTestCase {
|
|||
.put("transport.profiles.client.xpack.security.keystore.path", "/path/to/keystore")
|
||||
.put("transport.profiles.client.xpack.security.ciphers", "_ciphers")
|
||||
.put("transport.profiles.client.xpack.security.supported_protocols",
|
||||
randomFrom(SSLSettings.Globals.DEFAULT_SUPPORTED_PROTOCOLS))
|
||||
randomFrom(Global.DEFAULT_SUPPORTED_PROTOCOLS))
|
||||
.put("transport.profiles.client.xpack.security.keystore.password", randomAsciiOfLength(5))
|
||||
.put("transport.profiles.client.xpack.security.keystore.algorithm", "_algorithm")
|
||||
.put("transport.profiles.client.xpack.security.keystore.key_password", randomAsciiOfLength(5))
|
||||
|
|
|
@ -52,14 +52,12 @@ public class ShieldClearScrollTests extends ShieldIntegTestCase {
|
|||
@Override
|
||||
protected String configRoles() {
|
||||
return super.configRoles() +
|
||||
// note the new line here.. we need to fix this in another PR
|
||||
// as this throws another exception in the constructor and then we fuck up
|
||||
"\nallowed_role:\n" +
|
||||
" cluster:\n" +
|
||||
" - cluster:admin/indices/scroll/clear_all \n" +
|
||||
"denied_role:\n" +
|
||||
" indices:\n" +
|
||||
" - names: '*'" +
|
||||
" - names: '*'\n" +
|
||||
" privileges: [ALL]\n";
|
||||
}
|
||||
|
||||
|
|
|
@ -5,7 +5,6 @@
|
|||
*/
|
||||
package org.elasticsearch.integration.ldap;
|
||||
|
||||
import org.elasticsearch.ElasticsearchException;
|
||||
import org.elasticsearch.ElasticsearchSecurityException;
|
||||
import org.elasticsearch.action.get.GetResponse;
|
||||
import org.elasticsearch.action.index.IndexResponse;
|
||||
|
@ -22,7 +21,6 @@ import org.junit.AfterClass;
|
|||
import org.junit.BeforeClass;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.util.Collections;
|
||||
|
||||
|
@ -58,10 +56,14 @@ abstract public class AbstractAdLdapRealmTestCase extends ShieldIntegTestCase {
|
|||
"Philanthropists: [ \"cn=Philanthropists,ou=people,dc=oldap,dc=test,dc=elasticsearch,dc=com\" ] \n";
|
||||
|
||||
static protected RealmConfig realmConfig;
|
||||
static protected boolean useGlobalSSL;
|
||||
static protected boolean sslEnabled;
|
||||
|
||||
@BeforeClass
|
||||
public static void setupRealm() {
|
||||
realmConfig = randomFrom(RealmConfig.values());
|
||||
useGlobalSSL = randomBoolean();
|
||||
sslEnabled = randomBoolean();
|
||||
ESLoggerFactory.getLogger("test").info("running test with realm configuration [{}], with direct group to role mapping [{}]",
|
||||
realmConfig, realmConfig.mapGroupsAsRoles);
|
||||
}
|
||||
|
@ -74,13 +76,25 @@ abstract public class AbstractAdLdapRealmTestCase extends ShieldIntegTestCase {
|
|||
@Override
|
||||
protected Settings nodeSettings(int nodeOrdinal) {
|
||||
Path nodeFiles = createTempDir();
|
||||
return Settings.builder()
|
||||
Path store = getDataPath("/org/elasticsearch/shield/transport/ssl/certs/simple/testnode.jks");
|
||||
Settings.Builder builder = Settings.builder()
|
||||
.put(super.nodeSettings(nodeOrdinal))
|
||||
.put(realmConfig.buildSettings())
|
||||
//we need ssl to the LDAP server
|
||||
.put(sslSettingsForStore("/org/elasticsearch/shield/transport/ssl/certs/simple/testnode.jks", "testnode"))
|
||||
.put(SHIELD_AUTHC_REALMS_EXTERNAL + ".files.role_mapping", writeFile(nodeFiles, "role_mapping.yml", configRoleMappings()))
|
||||
.build();
|
||||
.put(realmConfig.buildSettings(store, "testnode"))
|
||||
.put(SHIELD_AUTHC_REALMS_EXTERNAL + ".files.role_mapping", writeFile(nodeFiles, "role_mapping.yml", configRoleMappings()));
|
||||
if (sslEnabled == false && useGlobalSSL) {
|
||||
builder.put(sslSettingsForStore(store, "testnode"));
|
||||
}
|
||||
return builder.build();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean sslTransportEnabled() {
|
||||
return sslEnabled;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean autoSSLEnabled() {
|
||||
return sslEnabled && (useGlobalSSL == false);
|
||||
}
|
||||
|
||||
protected String configRoleMappings() {
|
||||
|
@ -152,13 +166,7 @@ abstract public class AbstractAdLdapRealmTestCase extends ShieldIntegTestCase {
|
|||
return UsernamePasswordToken.basicAuthHeaderValue(username, new SecuredString(password.toCharArray()));
|
||||
}
|
||||
|
||||
private Settings sslSettingsForStore(String resourcePathToStore, String password) {
|
||||
Path store = getDataPath(resourcePathToStore);
|
||||
|
||||
if (Files.notExists(store)) {
|
||||
throw new ElasticsearchException("store path [" + store + "] doesn't exist");
|
||||
}
|
||||
|
||||
private Settings sslSettingsForStore(Path store, String password) {
|
||||
return Settings.builder()
|
||||
.put("xpack.security.ssl.keystore.path", store)
|
||||
.put("xpack.security.ssl.keystore.password", password)
|
||||
|
@ -230,13 +238,18 @@ abstract public class AbstractAdLdapRealmTestCase extends ShieldIntegTestCase {
|
|||
this.mapGroupsAsRoles = randomBoolean();
|
||||
}
|
||||
|
||||
public Settings buildSettings() {
|
||||
return Settings.builder()
|
||||
public Settings buildSettings(Path store, String password) {
|
||||
Settings.Builder builder = Settings.builder()
|
||||
.put(SHIELD_AUTHC_REALMS_EXTERNAL + ".order", 1)
|
||||
.put(SHIELD_AUTHC_REALMS_EXTERNAL + ".hostname_verification", false)
|
||||
.put(SHIELD_AUTHC_REALMS_EXTERNAL + ".unmapped_groups_as_roles", mapGroupsAsRoles)
|
||||
.put(this.settings)
|
||||
.build();
|
||||
.put(this.settings);
|
||||
if (useGlobalSSL == false) {
|
||||
builder.put(SHIELD_AUTHC_REALMS_EXTERNAL + ".ssl.truststore.path", store)
|
||||
.put(SHIELD_AUTHC_REALMS_EXTERNAL + ".ssl.truststore.password", password);
|
||||
}
|
||||
|
||||
return builder.build();
|
||||
}
|
||||
|
||||
//if mapGroupsAsRoles is turned on we don't write anything to the rolemapping file
|
||||
|
|
|
@ -27,6 +27,7 @@ import org.elasticsearch.common.transport.TransportAddress;
|
|||
import org.elasticsearch.rest.RestRequest;
|
||||
import org.elasticsearch.search.SearchHit;
|
||||
import org.elasticsearch.shield.Security;
|
||||
import org.elasticsearch.shield.transport.netty.ShieldNettyTransport;
|
||||
import org.elasticsearch.shield.user.SystemUser;
|
||||
import org.elasticsearch.shield.user.User;
|
||||
import org.elasticsearch.shield.authc.AuthenticationToken;
|
||||
|
@ -130,7 +131,7 @@ public class IndexAuditTrailTests extends ShieldIntegTestCase {
|
|||
final boolean useSSL = useShield && randomBoolean();
|
||||
logger.info("--> remote indexing enabled. shield enabled: [{}], SSL enabled: [{}], nodes: [{}]", useShield, useSSL, numNodes);
|
||||
ShieldSettingsSource cluster2SettingsSource =
|
||||
new ShieldSettingsSource(numNodes, useSSL, systemKey(), createTempDir(), Scope.SUITE) {
|
||||
new ShieldSettingsSource(numNodes, useSSL, randomBoolean(), systemKey(), createTempDir(), Scope.SUITE) {
|
||||
@Override
|
||||
public Settings nodeSettings(int nodeOrdinal) {
|
||||
Settings.Builder builder = Settings.builder()
|
||||
|
@ -158,6 +159,8 @@ public class IndexAuditTrailTests extends ShieldIntegTestCase {
|
|||
for (Map.Entry<String, String> entry : cluster2SettingsSource.getClientSSLSettings().getAsMap().entrySet()) {
|
||||
builder.put("xpack.security.audit.index.client." + entry.getKey(), entry.getValue());
|
||||
}
|
||||
} else {
|
||||
builder.put("xpack.security.audit.index.client." + ShieldNettyTransport.SSL_SETTING.getKey(), false);
|
||||
}
|
||||
remoteSettings = builder.build();
|
||||
}
|
||||
|
|
|
@ -42,6 +42,7 @@ public class RemoteIndexAuditTrailStartingTests extends ShieldIntegTestCase {
|
|||
private InternalTestCluster remoteCluster;
|
||||
|
||||
private final boolean useSSL = randomBoolean();
|
||||
private final boolean autoSSL = randomBoolean();
|
||||
private final boolean localAudit = randomBoolean();
|
||||
private final String outputs = randomFrom("index", "logfile", "index,logfile");
|
||||
|
||||
|
@ -50,6 +51,11 @@ public class RemoteIndexAuditTrailStartingTests extends ShieldIntegTestCase {
|
|||
return useSSL;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean autoSSLEnabled() {
|
||||
return autoSSL;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Settings nodeSettings(int nodeOrdinal) {
|
||||
return Settings.builder()
|
||||
|
@ -87,7 +93,8 @@ public class RemoteIndexAuditTrailStartingTests extends ShieldIntegTestCase {
|
|||
|
||||
// Setup a second test cluster with randomization for number of nodes, shield enabled, and SSL
|
||||
final int numNodes = randomIntBetween(2, 3);
|
||||
ShieldSettingsSource cluster2SettingsSource = new ShieldSettingsSource(numNodes, useSSL, systemKey(), createTempDir(), Scope.TEST) {
|
||||
ShieldSettingsSource cluster2SettingsSource = new ShieldSettingsSource(numNodes, useSSL, autoSSL, systemKey(), createTempDir(),
|
||||
Scope.TEST) {
|
||||
@Override
|
||||
public Settings nodeSettings(int nodeOrdinal) {
|
||||
Settings.Builder builder = Settings.builder()
|
||||
|
@ -98,10 +105,8 @@ public class RemoteIndexAuditTrailStartingTests extends ShieldIntegTestCase {
|
|||
.put("xpack.security.audit.index.client.cluster.name", clusterName)
|
||||
.put("xpack.security.audit.index.client.xpack.security.user", DEFAULT_USER_NAME + ":" + DEFAULT_PASSWORD);
|
||||
|
||||
if (useSSL) {
|
||||
for (Map.Entry<String, String> entry : getClientSSLSettings().getAsMap().entrySet()) {
|
||||
builder.put("xpack.security.audit.index.client." + entry.getKey(), entry.getValue());
|
||||
}
|
||||
for (Map.Entry<String, String> entry : getClientSSLSettings().getAsMap().entrySet()) {
|
||||
builder.put("xpack.security.audit.index.client." + entry.getKey(), entry.getValue());
|
||||
}
|
||||
return builder.build();
|
||||
}
|
||||
|
|
|
@ -17,6 +17,7 @@ import org.elasticsearch.shield.Security;
|
|||
import org.elasticsearch.shield.authc.support.SecuredString;
|
||||
import org.elasticsearch.shield.authc.support.SecuredStringTests;
|
||||
import org.elasticsearch.shield.authc.support.UsernamePasswordToken;
|
||||
import org.elasticsearch.shield.transport.netty.ShieldNettyTransport;
|
||||
import org.elasticsearch.test.ShieldIntegTestCase;
|
||||
import org.elasticsearch.test.ShieldSettingsSource;
|
||||
import org.elasticsearch.test.rest.client.http.HttpResponse;
|
||||
|
@ -214,6 +215,7 @@ public class RunAsIntegTests extends ShieldIntegTestCase {
|
|||
Settings settings = Settings.builder()
|
||||
.put(extraSettings)
|
||||
.put("cluster.name", clusterName)
|
||||
.put(ShieldNettyTransport.SSL_SETTING.getKey(), false)
|
||||
.build();
|
||||
|
||||
return TransportClient.builder()
|
||||
|
|
|
@ -6,22 +6,13 @@
|
|||
package org.elasticsearch.shield.authc.activedirectory;
|
||||
|
||||
import com.unboundid.ldap.sdk.Filter;
|
||||
import com.unboundid.ldap.sdk.LDAPConnection;
|
||||
import com.unboundid.ldap.sdk.LDAPConnectionOptions;
|
||||
import com.unboundid.ldap.sdk.LDAPURL;
|
||||
import org.elasticsearch.common.settings.Settings;
|
||||
import org.elasticsearch.common.unit.TimeValue;
|
||||
import org.elasticsearch.env.Environment;
|
||||
import org.elasticsearch.shield.authc.ldap.GroupsResolverTestCase;
|
||||
import org.elasticsearch.shield.authc.ldap.support.LdapSearchScope;
|
||||
import org.elasticsearch.shield.authc.ldap.support.SessionFactory;
|
||||
import org.elasticsearch.shield.ssl.ClientSSLService;
|
||||
import org.elasticsearch.shield.support.NoOpLogger;
|
||||
import org.elasticsearch.test.ESTestCase;
|
||||
import org.elasticsearch.test.junit.annotations.Network;
|
||||
import org.junit.After;
|
||||
import org.junit.Before;
|
||||
|
||||
import java.nio.file.Path;
|
||||
import java.util.List;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
|
@ -31,39 +22,9 @@ import static org.hamcrest.Matchers.hasItem;
|
|||
import static org.hamcrest.Matchers.is;
|
||||
|
||||
@Network
|
||||
public class ActiveDirectoryGroupsResolverTests extends ESTestCase {
|
||||
public class ActiveDirectoryGroupsResolverTests extends GroupsResolverTestCase {
|
||||
|
||||
public static final String BRUCE_BANNER_DN = "cn=Bruce Banner,CN=Users,DC=ad,DC=test,DC=elasticsearch,DC=com";
|
||||
private LDAPConnection ldapConnection;
|
||||
|
||||
@Override
|
||||
@Before
|
||||
public void setUp() throws Exception {
|
||||
super.setUp();
|
||||
Path keystore = getDataPath("../ldap/support/ldaptrust.jks");
|
||||
Environment env = new Environment(Settings.builder().put("path.home", createTempDir()).build());
|
||||
ClientSSLService clientSSLService = new ClientSSLService(Settings.builder()
|
||||
.put("xpack.security.ssl.keystore.path", keystore)
|
||||
.put("xpack.security.ssl.keystore.password", "changeit")
|
||||
.build());
|
||||
clientSSLService.setEnvironment(env);
|
||||
|
||||
LDAPURL ldapurl = new LDAPURL(ActiveDirectorySessionFactoryTests.AD_LDAP_URL);
|
||||
LDAPConnectionOptions options = new LDAPConnectionOptions();
|
||||
options.setFollowReferrals(true);
|
||||
options.setAutoReconnect(true);
|
||||
options.setAllowConcurrentSocketFactoryUse(true);
|
||||
options.setConnectTimeoutMillis(Math.toIntExact(SessionFactory.TIMEOUT_DEFAULT.millis()));
|
||||
options.setResponseTimeoutMillis(SessionFactory.TIMEOUT_DEFAULT.millis());
|
||||
ldapConnection = new LDAPConnection(clientSSLService.sslSocketFactory(), options, ldapurl.getHost(), ldapurl.getPort(),
|
||||
BRUCE_BANNER_DN, ActiveDirectorySessionFactoryTests.PASSWORD);
|
||||
}
|
||||
|
||||
@Override
|
||||
@After
|
||||
public void tearDown() throws Exception {
|
||||
super.tearDown();
|
||||
ldapConnection.close();
|
||||
}
|
||||
|
||||
public void testResolveSubTree() throws Exception {
|
||||
Settings settings = Settings.builder()
|
||||
|
@ -151,4 +112,18 @@ public class ActiveDirectoryGroupsResolverTests extends ESTestCase {
|
|||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String ldapUrl() {
|
||||
return ActiveDirectorySessionFactoryTests.AD_LDAP_URL;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String bindDN() {
|
||||
return BRUCE_BANNER_DN;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String bindPassword() {
|
||||
return ActiveDirectorySessionFactoryTests.PASSWORD;
|
||||
}
|
||||
}
|
|
@ -16,6 +16,7 @@ import org.elasticsearch.shield.authc.ldap.support.LdapTestCase;
|
|||
import org.elasticsearch.shield.authc.ldap.support.SessionFactory;
|
||||
import org.elasticsearch.shield.authc.support.SecuredStringTests;
|
||||
import org.elasticsearch.shield.ssl.ClientSSLService;
|
||||
import org.elasticsearch.shield.ssl.SSLConfiguration.Global;
|
||||
import org.elasticsearch.test.ESTestCase;
|
||||
import org.elasticsearch.test.junit.annotations.Network;
|
||||
import org.junit.Before;
|
||||
|
@ -38,23 +39,28 @@ public class ActiveDirectorySessionFactoryTests extends ESTestCase {
|
|||
|
||||
private ClientSSLService clientSSLService;
|
||||
private Settings globalSettings;
|
||||
private boolean useGlobalSSL;
|
||||
|
||||
@Before
|
||||
public void initializeSslSocketFactory() throws Exception {
|
||||
useGlobalSSL = randomBoolean();
|
||||
Path keystore = getDataPath("../ldap/support/ldaptrust.jks");
|
||||
Environment env = new Environment(Settings.builder().put("path.home", createTempDir()).build());
|
||||
|
||||
/*
|
||||
* Prior to each test we reinitialize the socket factory with a new SSLService so that we get a new SSLContext.
|
||||
* If we re-use a SSLContext, previously connected sessions can get re-established which breaks hostname
|
||||
* verification tests since a re-established connection does not perform hostname verification.
|
||||
*/
|
||||
clientSSLService = new ClientSSLService(Settings.builder()
|
||||
.put("xpack.security.ssl.keystore.path", keystore)
|
||||
.put("xpack.security.ssl.keystore.password", "changeit")
|
||||
.build());
|
||||
clientSSLService.setEnvironment(env);
|
||||
globalSettings = Settings.builder().put("path.home", createTempDir()).build();
|
||||
Settings.Builder builder = Settings.builder().put("path.home", createTempDir());
|
||||
if (useGlobalSSL) {
|
||||
builder.put("xpack.security.ssl.keystore.path", keystore)
|
||||
.put("xpack.security.ssl.keystore.password", "changeit");
|
||||
} else {
|
||||
builder.put(Global.AUTO_GENERATE_SSL_SETTING.getKey(), false);
|
||||
}
|
||||
globalSettings = builder.build();
|
||||
Environment environment = new Environment(globalSettings);
|
||||
clientSSLService = new ClientSSLService(globalSettings, new Global(globalSettings));
|
||||
clientSSLService.setEnvironment(environment);
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
|
@ -238,6 +244,13 @@ public class ActiveDirectorySessionFactoryTests extends ESTestCase {
|
|||
String groupSearchBase = "DC=ad,DC=test,DC=elasticsearch,DC=com";
|
||||
String userTemplate = "CN={0},CN=Users,DC=ad,DC=test,DC=elasticsearch,DC=com";
|
||||
Settings settings = LdapTestCase.buildLdapSettings(AD_LDAP_URL, userTemplate, groupSearchBase, LdapSearchScope.SUB_TREE);
|
||||
if (useGlobalSSL == false) {
|
||||
settings = Settings.builder()
|
||||
.put(settings)
|
||||
.put("ssl.truststore.path", getDataPath("../ldap/support/ldaptrust.jks"))
|
||||
.put("ssl.truststore.password", "changeit")
|
||||
.build();
|
||||
}
|
||||
RealmConfig config = new RealmConfig("ad-as-ldap-test", settings, globalSettings);
|
||||
LdapSessionFactory sessionFactory = new LdapSessionFactory(config, clientSSLService).init();
|
||||
|
||||
|
@ -257,6 +270,13 @@ public class ActiveDirectorySessionFactoryTests extends ESTestCase {
|
|||
public void testStandardLdapWithAttributeGroups() throws Exception {
|
||||
String userTemplate = "CN={0},CN=Users,DC=ad,DC=test,DC=elasticsearch,DC=com";
|
||||
Settings settings = LdapTestCase.buildLdapSettings(new String[] { AD_LDAP_URL }, userTemplate, false);
|
||||
if (useGlobalSSL == false) {
|
||||
settings = Settings.builder()
|
||||
.put(settings)
|
||||
.put("ssl.truststore.path", getDataPath("../ldap/support/ldaptrust.jks"))
|
||||
.put("ssl.truststore.password", "changeit")
|
||||
.build();
|
||||
}
|
||||
RealmConfig config = new RealmConfig("ad-as-ldap-test", settings, globalSettings);
|
||||
LdapSessionFactory sessionFactory = new LdapSessionFactory(config, clientSSLService).init();
|
||||
|
||||
|
@ -302,26 +322,30 @@ public class ActiveDirectorySessionFactoryTests extends ESTestCase {
|
|||
}
|
||||
}
|
||||
|
||||
public static Settings buildAdSettings(String ldapUrl, String adDomainName, boolean hostnameVerification) {
|
||||
return Settings.builder()
|
||||
Settings buildAdSettings(String ldapUrl, String adDomainName, boolean hostnameVerification) {
|
||||
Settings.Builder builder = Settings.builder()
|
||||
.put(ActiveDirectorySessionFactory.URLS_SETTING, ldapUrl)
|
||||
.put(ActiveDirectorySessionFactory.AD_DOMAIN_NAME_SETTING, adDomainName)
|
||||
.put(ActiveDirectorySessionFactory.HOSTNAME_VERIFICATION_SETTING, hostnameVerification)
|
||||
.build();
|
||||
.put(ActiveDirectorySessionFactory.HOSTNAME_VERIFICATION_SETTING, hostnameVerification);
|
||||
if (useGlobalSSL == false) {
|
||||
builder.put("ssl.truststore.path", getDataPath("../ldap/support/ldaptrust.jks"))
|
||||
.put("ssl.truststore.password", "changeit");
|
||||
}
|
||||
return builder.build();
|
||||
}
|
||||
|
||||
public static Settings buildAdSettings(String ldapUrl, String adDomainName, LdapSearchScope scope, String userSearchDN) {
|
||||
return buildAdSettings(ldapUrl, adDomainName, userSearchDN, scope, true);
|
||||
}
|
||||
|
||||
public static Settings buildAdSettings(String ldapUrl, String adDomainName, String userSearchDN, LdapSearchScope scope,
|
||||
Settings buildAdSettings(String ldapUrl, String adDomainName, String userSearchDN, LdapSearchScope scope,
|
||||
boolean hostnameVerification) {
|
||||
return Settings.builder()
|
||||
Settings.Builder builder = Settings.builder()
|
||||
.putArray(ActiveDirectorySessionFactory.URLS_SETTING, ldapUrl)
|
||||
.put(ActiveDirectorySessionFactory.AD_DOMAIN_NAME_SETTING, adDomainName)
|
||||
.put(ActiveDirectorySessionFactory.AD_USER_SEARCH_BASEDN_SETTING, userSearchDN)
|
||||
.put(ActiveDirectorySessionFactory.AD_USER_SEARCH_SCOPE_SETTING, scope)
|
||||
.put(ActiveDirectorySessionFactory.HOSTNAME_VERIFICATION_SETTING, hostnameVerification)
|
||||
.build();
|
||||
.put(ActiveDirectorySessionFactory.HOSTNAME_VERIFICATION_SETTING, hostnameVerification);
|
||||
if (useGlobalSSL == false) {
|
||||
builder.put("ssl.truststore.path", getDataPath("../ldap/support/ldaptrust.jks"))
|
||||
.put("ssl.truststore.password", "changeit");
|
||||
}
|
||||
return builder.build();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,72 @@
|
|||
/*
|
||||
* 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.shield.authc.ldap;
|
||||
|
||||
import com.unboundid.ldap.sdk.LDAPConnection;
|
||||
import com.unboundid.ldap.sdk.LDAPConnectionOptions;
|
||||
import com.unboundid.ldap.sdk.LDAPURL;
|
||||
import org.elasticsearch.common.settings.Settings;
|
||||
import org.elasticsearch.env.Environment;
|
||||
import org.elasticsearch.shield.authc.ldap.support.SessionFactory;
|
||||
import org.elasticsearch.shield.ssl.ClientSSLService;
|
||||
import org.elasticsearch.shield.ssl.SSLConfiguration.Global;
|
||||
import org.elasticsearch.test.ESTestCase;
|
||||
import org.junit.After;
|
||||
import org.junit.Before;
|
||||
|
||||
import java.nio.file.Path;
|
||||
|
||||
public abstract class GroupsResolverTestCase extends ESTestCase {
|
||||
|
||||
protected LDAPConnection ldapConnection;
|
||||
|
||||
protected abstract String ldapUrl();
|
||||
|
||||
protected abstract String bindDN();
|
||||
|
||||
protected abstract String bindPassword();
|
||||
|
||||
@Before
|
||||
public void setUpLdapConnection() throws Exception {
|
||||
Path keystore = getDataPath("../ldap/support/ldaptrust.jks");
|
||||
boolean useGlobalSSL = randomBoolean();
|
||||
Settings.Builder builder = Settings.builder().put("path.home", createTempDir());
|
||||
if (useGlobalSSL) {
|
||||
builder.put("xpack.security.ssl.keystore.path", keystore)
|
||||
.put("xpack.security.ssl.keystore.password", "changeit");
|
||||
} else {
|
||||
builder.put(Global.AUTO_GENERATE_SSL_SETTING.getKey(), false);
|
||||
}
|
||||
Settings settings = builder.build();
|
||||
Environment env = new Environment(settings);
|
||||
ClientSSLService clientSSLService = new ClientSSLService(settings, new Global(settings));
|
||||
clientSSLService.setEnvironment(env);
|
||||
|
||||
LDAPURL ldapurl = new LDAPURL(ldapUrl());
|
||||
LDAPConnectionOptions options = new LDAPConnectionOptions();
|
||||
options.setFollowReferrals(true);
|
||||
options.setAutoReconnect(true);
|
||||
options.setAllowConcurrentSocketFactoryUse(true);
|
||||
options.setConnectTimeoutMillis(Math.toIntExact(SessionFactory.TIMEOUT_DEFAULT.millis()));
|
||||
options.setResponseTimeoutMillis(SessionFactory.TIMEOUT_DEFAULT.millis());
|
||||
|
||||
Settings connectionSettings;
|
||||
if (useGlobalSSL) {
|
||||
connectionSettings = Settings.EMPTY;
|
||||
} else {
|
||||
connectionSettings = Settings.builder().put("keystore.path", keystore)
|
||||
.put("keystore.password", "changeit").build();
|
||||
}
|
||||
|
||||
ldapConnection = new LDAPConnection(clientSSLService.sslSocketFactory(connectionSettings), options, ldapurl.getHost(),
|
||||
ldapurl.getPort(), bindDN(), bindPassword());
|
||||
}
|
||||
|
||||
@After
|
||||
public void tearDownLdapConnection() throws Exception {
|
||||
ldapConnection.close();
|
||||
}
|
||||
}
|
|
@ -29,6 +29,7 @@ import org.elasticsearch.shield.authc.ldap.support.LdapTestCase;
|
|||
import org.elasticsearch.shield.authc.support.SecuredString;
|
||||
import org.elasticsearch.shield.authc.support.SecuredStringTests;
|
||||
import org.elasticsearch.shield.ssl.ClientSSLService;
|
||||
import org.elasticsearch.shield.ssl.SSLConfiguration.Global;
|
||||
import org.elasticsearch.shield.support.NoOpLogger;
|
||||
import org.elasticsearch.test.junit.annotations.Network;
|
||||
import org.elasticsearch.watcher.Watcher;
|
||||
|
@ -70,10 +71,11 @@ public class LdapUserSearchSessionFactoryTests extends LdapTestCase {
|
|||
* If we re-use a SSLContext, previously connected sessions can get re-established which breaks hostname
|
||||
* verification tests since a re-established connection does not perform hostname verification.
|
||||
*/
|
||||
clientSSLService = new ClientSSLService(Settings.builder()
|
||||
Settings settings = Settings.builder()
|
||||
.put("xpack.security.ssl.keystore.path", keystore)
|
||||
.put("xpack.security.ssl.keystore.password", "changeit")
|
||||
.build());
|
||||
.build();
|
||||
clientSSLService = new ClientSSLService(settings, new Global(settings));
|
||||
clientSSLService.setEnvironment(env);
|
||||
|
||||
globalSettings = Settings.builder().put("path.home", createTempDir()).build();
|
||||
|
|
|
@ -15,6 +15,7 @@ import org.elasticsearch.shield.authc.ldap.support.LdapTestCase;
|
|||
import org.elasticsearch.shield.authc.ldap.support.SessionFactory;
|
||||
import org.elasticsearch.shield.authc.support.SecuredStringTests;
|
||||
import org.elasticsearch.shield.ssl.ClientSSLService;
|
||||
import org.elasticsearch.shield.ssl.SSLConfiguration.Global;
|
||||
import org.elasticsearch.test.ESTestCase;
|
||||
import org.elasticsearch.test.junit.annotations.Network;
|
||||
import org.junit.Before;
|
||||
|
@ -31,32 +32,37 @@ public class OpenLdapTests extends ESTestCase {
|
|||
public static final String OPEN_LDAP_URL = "ldaps://54.200.235.244:636";
|
||||
public static final String PASSWORD = "NickFuryHeartsES";
|
||||
|
||||
private boolean useGlobalSSL;
|
||||
private ClientSSLService clientSSLService;
|
||||
private Settings globalSettings;
|
||||
|
||||
@Before
|
||||
public void initializeSslSocketFactory() throws Exception {
|
||||
useGlobalSSL = randomBoolean();
|
||||
Path keystore = getDataPath("../ldap/support/ldaptrust.jks");
|
||||
Environment env = new Environment(Settings.builder().put("path.home", createTempDir()).build());
|
||||
|
||||
/*
|
||||
* Prior to each test we reinitialize the socket factory with a new SSLService so that we get a new SSLContext.
|
||||
* If we re-use a SSLContext, previously connected sessions can get re-established which breaks hostname
|
||||
* verification tests since a re-established connection does not perform hostname verification.
|
||||
*/
|
||||
clientSSLService = new ClientSSLService(Settings.builder()
|
||||
.put("xpack.security.ssl.keystore.path", keystore)
|
||||
.put("xpack.security.ssl.keystore.password", "changeit")
|
||||
.build());
|
||||
clientSSLService.setEnvironment(env);
|
||||
globalSettings = Settings.builder().put("path.home", createTempDir()).build();
|
||||
Settings.Builder builder = Settings.builder().put("path.home", createTempDir());
|
||||
if (useGlobalSSL) {
|
||||
builder.put("xpack.security.ssl.keystore.path", keystore)
|
||||
.put("xpack.security.ssl.keystore.password", "changeit");
|
||||
} else {
|
||||
builder.put(Global.AUTO_GENERATE_SSL_SETTING.getKey(), false);
|
||||
}
|
||||
globalSettings = builder.build();
|
||||
Environment environment = new Environment(globalSettings);
|
||||
clientSSLService = new ClientSSLService(globalSettings, new Global(globalSettings));
|
||||
clientSSLService.setEnvironment(environment);
|
||||
}
|
||||
|
||||
public void testConnect() throws Exception {
|
||||
//openldap does not use cn as naming attributes by default
|
||||
String groupSearchBase = "ou=people,dc=oldap,dc=test,dc=elasticsearch,dc=com";
|
||||
String userTemplate = "uid={0},ou=people,dc=oldap,dc=test,dc=elasticsearch,dc=com";
|
||||
RealmConfig config = new RealmConfig("oldap-test", LdapTestCase.buildLdapSettings(OPEN_LDAP_URL, userTemplate, groupSearchBase,
|
||||
RealmConfig config = new RealmConfig("oldap-test", buildLdapSettings(OPEN_LDAP_URL, userTemplate, groupSearchBase,
|
||||
LdapSearchScope.ONE_LEVEL), globalSettings);
|
||||
LdapSessionFactory sessionFactory = new LdapSessionFactory(config, clientSSLService).init();
|
||||
|
||||
|
@ -73,7 +79,7 @@ public class OpenLdapTests extends ESTestCase {
|
|||
|
||||
String groupSearchBase = "cn=Avengers,ou=people,dc=oldap,dc=test,dc=elasticsearch,dc=com";
|
||||
String userTemplate = "uid={0},ou=people,dc=oldap,dc=test,dc=elasticsearch,dc=com";
|
||||
RealmConfig config = new RealmConfig("oldap-test", LdapTestCase.buildLdapSettings(OPEN_LDAP_URL, userTemplate, groupSearchBase,
|
||||
RealmConfig config = new RealmConfig("oldap-test", buildLdapSettings(OPEN_LDAP_URL, userTemplate, groupSearchBase,
|
||||
LdapSearchScope.BASE), globalSettings);
|
||||
LdapSessionFactory sessionFactory = new LdapSessionFactory(config, clientSSLService).init();
|
||||
|
||||
|
@ -89,7 +95,7 @@ public class OpenLdapTests extends ESTestCase {
|
|||
String groupSearchBase = "ou=people,dc=oldap,dc=test,dc=elasticsearch,dc=com";
|
||||
String userTemplate = "uid={0},ou=people,dc=oldap,dc=test,dc=elasticsearch,dc=com";
|
||||
Settings settings = Settings.builder()
|
||||
.put(LdapTestCase.buildLdapSettings(OPEN_LDAP_URL, userTemplate, groupSearchBase, LdapSearchScope.ONE_LEVEL))
|
||||
.put(buildLdapSettings(OPEN_LDAP_URL, userTemplate, groupSearchBase, LdapSearchScope.ONE_LEVEL))
|
||||
.put("group_search.filter", "(&(objectclass=posixGroup)(memberUID={0}))")
|
||||
.put("group_search.user_attribute", "uid")
|
||||
.build();
|
||||
|
@ -106,7 +112,7 @@ public class OpenLdapTests extends ESTestCase {
|
|||
String groupSearchBase = "ou=people,dc=oldap,dc=test,dc=elasticsearch,dc=com";
|
||||
String userTemplate = "uid={0},ou=people,dc=oldap,dc=test,dc=elasticsearch,dc=com";
|
||||
Settings settings = Settings.builder()
|
||||
.put(LdapTestCase.buildLdapSettings(OPEN_LDAP_URL, userTemplate, groupSearchBase, LdapSearchScope.ONE_LEVEL))
|
||||
.put(buildLdapSettings(OPEN_LDAP_URL, userTemplate, groupSearchBase, LdapSearchScope.ONE_LEVEL))
|
||||
.put(SessionFactory.HOSTNAME_VERIFICATION_SETTING, false)
|
||||
.put(SessionFactory.TIMEOUT_TCP_READ_SETTING, "1ms") //1 millisecond
|
||||
.build();
|
||||
|
@ -127,7 +133,7 @@ public class OpenLdapTests extends ESTestCase {
|
|||
String groupSearchBase = "ou=people,dc=oldap,dc=test,dc=elasticsearch,dc=com";
|
||||
String userTemplate = "uid={0},ou=people,dc=oldap,dc=test,dc=elasticsearch,dc=com";
|
||||
Settings settings = Settings.builder()
|
||||
.put(LdapTestCase.buildLdapSettings(OPEN_LDAP_URL, userTemplate, groupSearchBase, LdapSearchScope.ONE_LEVEL))
|
||||
.put(buildLdapSettings(OPEN_LDAP_URL, userTemplate, groupSearchBase, LdapSearchScope.ONE_LEVEL))
|
||||
.put(LdapSessionFactory.HOSTNAME_VERIFICATION_SETTING, true)
|
||||
.build();
|
||||
|
||||
|
@ -141,4 +147,16 @@ public class OpenLdapTests extends ESTestCase {
|
|||
assertThat(e.getMessage(), containsString("failed to connect to any LDAP servers"));
|
||||
}
|
||||
}
|
||||
|
||||
Settings buildLdapSettings(String ldapUrl, String userTemplate, String groupSearchBase, LdapSearchScope scope) {
|
||||
Settings baseSettings = LdapTestCase.buildLdapSettings(ldapUrl, userTemplate, groupSearchBase, scope);
|
||||
if (useGlobalSSL) {
|
||||
return baseSettings;
|
||||
}
|
||||
return Settings.builder()
|
||||
.put(baseSettings)
|
||||
.put("ssl.truststore.path", getDataPath("../ldap/support/ldaptrust.jks"))
|
||||
.put("ssl.truststore.password", "changeit")
|
||||
.build();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -5,23 +5,13 @@
|
|||
*/
|
||||
package org.elasticsearch.shield.authc.ldap;
|
||||
|
||||
import com.unboundid.ldap.sdk.LDAPConnection;
|
||||
import com.unboundid.ldap.sdk.LDAPConnectionOptions;
|
||||
import com.unboundid.ldap.sdk.LDAPURL;
|
||||
import org.elasticsearch.ElasticsearchSecurityException;
|
||||
import org.elasticsearch.common.settings.Settings;
|
||||
import org.elasticsearch.common.unit.TimeValue;
|
||||
import org.elasticsearch.env.Environment;
|
||||
import org.elasticsearch.shield.authc.ldap.support.LdapSearchScope;
|
||||
import org.elasticsearch.shield.authc.ldap.support.SessionFactory;
|
||||
import org.elasticsearch.shield.ssl.ClientSSLService;
|
||||
import org.elasticsearch.shield.support.NoOpLogger;
|
||||
import org.elasticsearch.test.ESTestCase;
|
||||
import org.elasticsearch.test.junit.annotations.Network;
|
||||
import org.junit.After;
|
||||
import org.junit.Before;
|
||||
|
||||
import java.nio.file.Path;
|
||||
import java.util.List;
|
||||
|
||||
import static org.hamcrest.Matchers.containsInAnyOrder;
|
||||
|
@ -31,41 +21,10 @@ import static org.hamcrest.Matchers.is;
|
|||
import static org.hamcrest.Matchers.notNullValue;
|
||||
|
||||
@Network
|
||||
public class SearchGroupsResolverTests extends ESTestCase {
|
||||
public class SearchGroupsResolverTests extends GroupsResolverTestCase {
|
||||
|
||||
public static final String BRUCE_BANNER_DN = "uid=hulk,ou=people,dc=oldap,dc=test,dc=elasticsearch,dc=com";
|
||||
|
||||
private LDAPConnection ldapConnection;
|
||||
|
||||
@Before
|
||||
public void setup() throws Exception {
|
||||
super.setUp();
|
||||
Path keystore = getDataPath("../ldap/support/ldaptrust.jks");
|
||||
Environment env = new Environment(Settings.builder().put("path.home", createTempDir()).build());
|
||||
ClientSSLService clientSSLService = new ClientSSLService(Settings.builder()
|
||||
.put("xpack.security.ssl.keystore.path", keystore)
|
||||
.put("xpack.security.ssl.keystore.password", "changeit")
|
||||
.build());
|
||||
clientSSLService.setEnvironment(env);
|
||||
|
||||
LDAPURL ldapurl = new LDAPURL(OpenLdapTests.OPEN_LDAP_URL);
|
||||
LDAPConnectionOptions options = new LDAPConnectionOptions();
|
||||
options.setFollowReferrals(true);
|
||||
options.setAutoReconnect(true);
|
||||
options.setAllowConcurrentSocketFactoryUse(true);
|
||||
options.setConnectTimeoutMillis(Math.toIntExact(SessionFactory.TIMEOUT_DEFAULT.millis()));
|
||||
options.setResponseTimeoutMillis(SessionFactory.TIMEOUT_DEFAULT.millis());
|
||||
ldapConnection = new LDAPConnection(clientSSLService.sslSocketFactory(), options, ldapurl.getHost(), ldapurl.getPort(),
|
||||
BRUCE_BANNER_DN, OpenLdapTests.PASSWORD);
|
||||
}
|
||||
|
||||
@Override
|
||||
@After
|
||||
public void tearDown() throws Exception {
|
||||
super.tearDown();
|
||||
ldapConnection.close();
|
||||
}
|
||||
|
||||
public void testResolveSubTree() throws Exception {
|
||||
Settings settings = Settings.builder()
|
||||
.put("base_dn", "dc=oldap,dc=test,dc=elasticsearch,dc=com")
|
||||
|
@ -174,4 +133,19 @@ public class SearchGroupsResolverTests extends ESTestCase {
|
|||
String attribute = resolver.readUserAttribute(ldapConnection, BRUCE_BANNER_DN, TimeValue.timeValueSeconds(5), NoOpLogger.INSTANCE);
|
||||
assertThat(attribute, is(notNullValue()));
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String ldapUrl() {
|
||||
return OpenLdapTests.OPEN_LDAP_URL;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String bindDN() {
|
||||
return BRUCE_BANNER_DN;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String bindPassword() {
|
||||
return OpenLdapTests.PASSWORD;
|
||||
}
|
||||
}
|
|
@ -5,22 +5,12 @@
|
|||
*/
|
||||
package org.elasticsearch.shield.authc.ldap;
|
||||
|
||||
import com.unboundid.ldap.sdk.LDAPConnection;
|
||||
import com.unboundid.ldap.sdk.LDAPConnectionOptions;
|
||||
import com.unboundid.ldap.sdk.LDAPURL;
|
||||
import org.elasticsearch.common.settings.Settings;
|
||||
import org.elasticsearch.common.unit.TimeValue;
|
||||
import org.elasticsearch.env.Environment;
|
||||
import org.elasticsearch.shield.authc.activedirectory.ActiveDirectorySessionFactoryTests;
|
||||
import org.elasticsearch.shield.authc.ldap.support.SessionFactory;
|
||||
import org.elasticsearch.shield.ssl.ClientSSLService;
|
||||
import org.elasticsearch.shield.support.NoOpLogger;
|
||||
import org.elasticsearch.test.ESTestCase;
|
||||
import org.elasticsearch.test.junit.annotations.Network;
|
||||
import org.junit.After;
|
||||
import org.junit.Before;
|
||||
|
||||
import java.nio.file.Path;
|
||||
import java.util.List;
|
||||
|
||||
import static org.hamcrest.Matchers.containsInAnyOrder;
|
||||
|
@ -29,40 +19,9 @@ import static org.hamcrest.Matchers.empty;
|
|||
import static org.hamcrest.Matchers.hasItems;
|
||||
|
||||
@Network
|
||||
public class UserAttributeGroupsResolverTests extends ESTestCase {
|
||||
public class UserAttributeGroupsResolverTests extends GroupsResolverTestCase {
|
||||
|
||||
public static final String BRUCE_BANNER_DN = "cn=Bruce Banner,CN=Users,DC=ad,DC=test,DC=elasticsearch,DC=com";
|
||||
private LDAPConnection ldapConnection;
|
||||
|
||||
@Override
|
||||
@Before
|
||||
public void setUp() throws Exception {
|
||||
super.setUp();
|
||||
Path keystore = getDataPath("../ldap/support/ldaptrust.jks");
|
||||
Environment env = new Environment(Settings.builder().put("path.home", createTempDir()).build());
|
||||
|
||||
ClientSSLService clientSSLService = new ClientSSLService(Settings.builder()
|
||||
.put("xpack.security.ssl.keystore.path", keystore)
|
||||
.put("xpack.security.ssl.keystore.password", "changeit")
|
||||
.build());
|
||||
clientSSLService.setEnvironment(env);
|
||||
|
||||
LDAPURL ldapurl = new LDAPURL(ActiveDirectorySessionFactoryTests.AD_LDAP_URL);
|
||||
LDAPConnectionOptions options = new LDAPConnectionOptions();
|
||||
options.setFollowReferrals(true);
|
||||
options.setAutoReconnect(true);
|
||||
options.setAllowConcurrentSocketFactoryUse(true);
|
||||
options.setConnectTimeoutMillis(Math.toIntExact(SessionFactory.TIMEOUT_DEFAULT.millis()));
|
||||
options.setResponseTimeoutMillis(SessionFactory.TIMEOUT_DEFAULT.millis());
|
||||
ldapConnection = new LDAPConnection(clientSSLService.sslSocketFactory(), options, ldapurl.getHost(), ldapurl.getPort(),
|
||||
BRUCE_BANNER_DN, ActiveDirectorySessionFactoryTests.PASSWORD);
|
||||
}
|
||||
|
||||
@Override
|
||||
@After
|
||||
public void tearDown() throws Exception {
|
||||
super.tearDown();
|
||||
ldapConnection.close();
|
||||
}
|
||||
|
||||
public void testResolve() throws Exception {
|
||||
//falling back on the 'memberOf' attribute
|
||||
|
@ -92,4 +51,19 @@ public class UserAttributeGroupsResolverTests extends ESTestCase {
|
|||
List<String> groups = resolver.resolve(ldapConnection, BRUCE_BANNER_DN, TimeValue.timeValueSeconds(20), NoOpLogger.INSTANCE);
|
||||
assertThat(groups, empty());
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String ldapUrl() {
|
||||
return ActiveDirectorySessionFactoryTests.AD_LDAP_URL;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String bindDN() {
|
||||
return BRUCE_BANNER_DN;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String bindPassword() {
|
||||
return ActiveDirectorySessionFactoryTests.PASSWORD;
|
||||
}
|
||||
}
|
|
@ -36,6 +36,7 @@ import java.nio.file.Path;
|
|||
import java.security.KeyStore;
|
||||
import java.security.SecureRandom;
|
||||
import java.util.Locale;
|
||||
import java.util.Map.Entry;
|
||||
|
||||
import static org.elasticsearch.test.ShieldSettingsSource.getSSLSettingsForStore;
|
||||
import static org.hamcrest.Matchers.containsString;
|
||||
|
@ -73,6 +74,11 @@ public class PkiAuthenticationTests extends ShieldIntegTestCase {
|
|||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean autoSSLEnabled() {
|
||||
return false;
|
||||
}
|
||||
|
||||
public void testTransportClientCanAuthenticateViaPki() {
|
||||
Settings settings = getSSLSettingsForStore("/org/elasticsearch/shield/transport/ssl/certs/simple/testnode.jks", "testnode");
|
||||
try (TransportClient client = createTransportClient(settings)) {
|
||||
|
@ -138,8 +144,18 @@ public class PkiAuthenticationTests extends ShieldIntegTestCase {
|
|||
}
|
||||
|
||||
private TransportClient createTransportClient(Settings additionalSettings) {
|
||||
Settings.Builder builder = Settings.builder()
|
||||
.put(transportClientSettings())
|
||||
Settings clientSettings = transportClientSettings();
|
||||
if (additionalSettings.getByPrefix("xpack.security.ssl.").isEmpty() == false) {
|
||||
Settings.Builder builder = Settings.builder();
|
||||
for (Entry<String, String> entry : clientSettings.getAsMap().entrySet()) {
|
||||
if (entry.getKey().startsWith("xpack.security.ssl.") == false) {
|
||||
builder.put(entry.getKey(), entry.getValue());
|
||||
}
|
||||
}
|
||||
clientSettings = builder.build();
|
||||
}
|
||||
|
||||
Settings.Builder builder = Settings.builder().put(clientSettings)
|
||||
.put(additionalSettings)
|
||||
.put("cluster.name", internalCluster().getClusterName());
|
||||
builder.remove(Security.USER_SETTING.getKey());
|
||||
|
|
|
@ -77,6 +77,11 @@ public class PkiOptionalClientAuthTests extends ShieldIntegTestCase {
|
|||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean autoSSLEnabled() {
|
||||
return false;
|
||||
}
|
||||
|
||||
public void testRestClientWithoutClientCertificate() throws Exception {
|
||||
HttpServerTransport httpServerTransport = internalCluster().getDataNodeInstance(HttpServerTransport.class);
|
||||
|
||||
|
|
|
@ -52,7 +52,7 @@ public class PkiRealmTests extends ESTestCase {
|
|||
}
|
||||
|
||||
public void testExtractToken() throws Exception {
|
||||
X509Certificate certificate = readCert(getDataPath("/org/elasticsearch/shield/transport/ssl/certs/simple/testnode.cert"));
|
||||
X509Certificate certificate = readCert(getDataPath("/org/elasticsearch/shield/transport/ssl/certs/simple/testnode.crt"));
|
||||
ThreadContext threadContext = new ThreadContext(Settings.EMPTY);
|
||||
threadContext.putTransient(PkiRealm.PKI_CERT_HEADER_NAME, new X509Certificate[] { certificate });
|
||||
PkiRealm realm = new PkiRealm(new RealmConfig("", Settings.EMPTY, globalSettings), mock(DnRoleMapper.class));
|
||||
|
@ -64,7 +64,7 @@ public class PkiRealmTests extends ESTestCase {
|
|||
}
|
||||
|
||||
public void testAuthenticateBasedOnCertToken() throws Exception {
|
||||
X509Certificate certificate = readCert(getDataPath("/org/elasticsearch/shield/transport/ssl/certs/simple/testnode.cert"));
|
||||
X509Certificate certificate = readCert(getDataPath("/org/elasticsearch/shield/transport/ssl/certs/simple/testnode.crt"));
|
||||
X509AuthenticationToken token = new X509AuthenticationToken(new X509Certificate[] { certificate }, "Elasticsearch Test Node",
|
||||
"CN=Elasticsearch Test Node,");
|
||||
DnRoleMapper roleMapper = mock(DnRoleMapper.class);
|
||||
|
@ -79,7 +79,7 @@ public class PkiRealmTests extends ESTestCase {
|
|||
}
|
||||
|
||||
public void testCustomUsernamePattern() throws Exception {
|
||||
X509Certificate certificate = readCert(getDataPath("/org/elasticsearch/shield/transport/ssl/certs/simple/testnode.cert"));
|
||||
X509Certificate certificate = readCert(getDataPath("/org/elasticsearch/shield/transport/ssl/certs/simple/testnode.crt"));
|
||||
DnRoleMapper roleMapper = mock(DnRoleMapper.class);
|
||||
PkiRealm realm = new PkiRealm(new RealmConfig("", Settings.builder().put("username_pattern", "OU=(.*?),").build(), globalSettings),
|
||||
roleMapper);
|
||||
|
@ -96,7 +96,7 @@ public class PkiRealmTests extends ESTestCase {
|
|||
}
|
||||
|
||||
public void testVerificationUsingATruststore() throws Exception {
|
||||
X509Certificate certificate = readCert(getDataPath("/org/elasticsearch/shield/transport/ssl/certs/simple/testnode.cert"));
|
||||
X509Certificate certificate = readCert(getDataPath("/org/elasticsearch/shield/transport/ssl/certs/simple/testnode.crt"));
|
||||
DnRoleMapper roleMapper = mock(DnRoleMapper.class);
|
||||
Settings settings = Settings.builder()
|
||||
.put("truststore.path", getDataPath("/org/elasticsearch/shield/transport/ssl/certs/simple/testnode.jks"))
|
||||
|
@ -117,7 +117,7 @@ public class PkiRealmTests extends ESTestCase {
|
|||
}
|
||||
|
||||
public void testVerificationFailsUsingADifferentTruststore() throws Exception {
|
||||
X509Certificate certificate = readCert(getDataPath("/org/elasticsearch/shield/transport/ssl/certs/simple/testnode.cert"));
|
||||
X509Certificate certificate = readCert(getDataPath("/org/elasticsearch/shield/transport/ssl/certs/simple/testnode.crt"));
|
||||
DnRoleMapper roleMapper = mock(DnRoleMapper.class);
|
||||
Settings settings = Settings.builder()
|
||||
.put("truststore.path", getDataPath("/org/elasticsearch/shield/transport/ssl/certs/simple/testnode-client-profile.jks"))
|
||||
|
|
|
@ -57,6 +57,11 @@ public class PkiWithoutClientAuthenticationTests extends ShieldIntegTestCase {
|
|||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean autoSSLEnabled() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Settings nodeSettings(int nodeOrdinal) {
|
||||
return Settings.builder()
|
||||
|
|
|
@ -0,0 +1,60 @@
|
|||
/*
|
||||
* 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.shield.ssl;
|
||||
|
||||
import org.elasticsearch.client.transport.NoNodeAvailableException;
|
||||
import org.elasticsearch.client.transport.TransportClient;
|
||||
import org.elasticsearch.common.settings.Settings;
|
||||
import org.elasticsearch.common.transport.TransportAddress;
|
||||
import org.elasticsearch.shield.Security;
|
||||
import org.elasticsearch.shield.transport.netty.ShieldNettyTransport;
|
||||
import org.elasticsearch.test.ShieldIntegTestCase;
|
||||
import org.elasticsearch.transport.Transport;
|
||||
import org.elasticsearch.xpack.XPackPlugin;
|
||||
|
||||
import static org.elasticsearch.test.ShieldSettingsSource.DEFAULT_PASSWORD;
|
||||
import static org.elasticsearch.test.ShieldSettingsSource.DEFAULT_USER_NAME;
|
||||
import static org.hamcrest.Matchers.containsString;
|
||||
|
||||
public class AutoSSLIntegTests extends ShieldIntegTestCase {
|
||||
|
||||
@Override
|
||||
public boolean sslTransportEnabled() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean autoSSLEnabled() {
|
||||
return true;
|
||||
}
|
||||
|
||||
public void testTransportClient() {
|
||||
String clusterName = internalCluster().getClusterName();
|
||||
TransportAddress transportAddress = randomFrom(internalCluster().getInstance(Transport.class).boundAddress().boundAddresses());
|
||||
try (TransportClient transportClient = TransportClient.builder().addPlugin(XPackPlugin.class)
|
||||
.settings(Settings.builder()
|
||||
.put("cluster.name", clusterName)
|
||||
.put(Security.USER_SETTING.getKey(), DEFAULT_USER_NAME + ":" + DEFAULT_PASSWORD))
|
||||
.build()) {
|
||||
transportClient.addTransportAddress(transportAddress);
|
||||
assertGreenClusterState(transportClient);
|
||||
}
|
||||
|
||||
// now try with SSL disabled and it should fail
|
||||
try (TransportClient transportClient = TransportClient.builder().addPlugin(XPackPlugin.class)
|
||||
.settings(Settings.builder()
|
||||
.put("cluster.name", clusterName)
|
||||
.put(ShieldNettyTransport.SSL_SETTING.getKey(), false)
|
||||
.put(Security.USER_SETTING.getKey(), DEFAULT_USER_NAME + ":" + DEFAULT_PASSWORD))
|
||||
.build()) {
|
||||
transportClient.addTransportAddress(transportAddress);
|
||||
assertGreenClusterState(transportClient);
|
||||
fail("should not have been able to connect");
|
||||
} catch (NoNodeAvailableException e) {
|
||||
assertThat(e.getMessage(), containsString("None of the configured nodes are available"));
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,144 @@
|
|||
/*
|
||||
* 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.shield.ssl;
|
||||
|
||||
import org.bouncycastle.asn1.x509.GeneralName;
|
||||
import org.bouncycastle.asn1.x509.GeneralNames;
|
||||
import org.elasticsearch.common.network.InetAddresses;
|
||||
import org.elasticsearch.test.ESTestCase;
|
||||
|
||||
import java.io.InputStream;
|
||||
import java.io.Reader;
|
||||
import java.math.BigInteger;
|
||||
import java.net.InetAddress;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.security.Key;
|
||||
import java.security.KeyPair;
|
||||
import java.security.KeyStore;
|
||||
import java.security.PrivateKey;
|
||||
import java.security.cert.Certificate;
|
||||
import java.security.cert.CertificateFactory;
|
||||
import java.security.cert.X509Certificate;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
import static org.hamcrest.Matchers.equalTo;
|
||||
import static org.hamcrest.Matchers.instanceOf;
|
||||
import static org.hamcrest.Matchers.is;
|
||||
import static org.hamcrest.Matchers.notNullValue;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.verify;
|
||||
import static org.mockito.Mockito.verifyNoMoreInteractions;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
/**
|
||||
* Unit tests for cert utils
|
||||
*/
|
||||
public class CertUtilsTests extends ESTestCase {
|
||||
|
||||
public void testSerialNotRepeated() {
|
||||
int iterations = scaledRandomIntBetween(10, 100);
|
||||
List<BigInteger> list = new ArrayList<>(iterations);
|
||||
for (int i = 0; i < iterations; i++) {
|
||||
BigInteger serial = CertUtils.getSerial();
|
||||
assertThat(list.contains(serial), is(false));
|
||||
list.add(serial);
|
||||
}
|
||||
}
|
||||
|
||||
public void testGenerateKeyPair() throws Exception {
|
||||
KeyPair keyPair = CertUtils.generateKeyPair();
|
||||
assertThat(keyPair.getPrivate().getAlgorithm(), is("RSA"));
|
||||
assertThat(keyPair.getPublic().getAlgorithm(), is("RSA"));
|
||||
}
|
||||
|
||||
|
||||
public void testReadKeysCorrectly() throws Exception {
|
||||
// read in keystore version
|
||||
Path keystorePath = getDataPath("/org/elasticsearch/shield/transport/ssl/certs/simple/testnode.jks");
|
||||
Key key;
|
||||
try (InputStream in = Files.newInputStream(keystorePath)) {
|
||||
KeyStore keyStore = KeyStore.getInstance("jks");
|
||||
keyStore.load(in, "testnode".toCharArray());
|
||||
key = keyStore.getKey("testnode", "testnode".toCharArray());
|
||||
}
|
||||
assertThat(key, notNullValue());
|
||||
assertThat(key, instanceOf(PrivateKey.class));
|
||||
|
||||
PrivateKey privateKey;
|
||||
try (Reader reader = Files.newBufferedReader(getDataPath("/org/elasticsearch/shield/transport/ssl/certs/simple/testnode.pem"),
|
||||
StandardCharsets.UTF_8)) {
|
||||
privateKey = CertUtils.readPrivateKey(reader, "testnode".toCharArray());
|
||||
}
|
||||
assertThat(privateKey, notNullValue());
|
||||
assertThat(privateKey, equalTo(key));
|
||||
}
|
||||
|
||||
public void testReadCertsCorrectly() throws Exception {
|
||||
// read in keystore version
|
||||
Path keystorePath = getDataPath("/org/elasticsearch/shield/transport/ssl/certs/simple/testnode.jks");
|
||||
Certificate certificate;
|
||||
try (InputStream in = Files.newInputStream(keystorePath)) {
|
||||
KeyStore keyStore = KeyStore.getInstance("jks");
|
||||
keyStore.load(in, "testnode".toCharArray());
|
||||
certificate = keyStore.getCertificate("testnode");
|
||||
}
|
||||
assertThat(certificate, notNullValue());
|
||||
assertThat(certificate, instanceOf(X509Certificate.class));
|
||||
|
||||
Certificate pemCert;
|
||||
try (Reader reader = Files.newBufferedReader(getDataPath("/org/elasticsearch/shield/transport/ssl/certs/simple/testnode.crt"),
|
||||
StandardCharsets.UTF_8)) {
|
||||
List<Certificate> certificateList = new ArrayList<>(1);
|
||||
CertUtils.readCertificates(reader, certificateList, CertificateFactory.getInstance("X.509"));
|
||||
assertThat(certificateList.size(), is(1));
|
||||
pemCert = certificateList.get(0);
|
||||
}
|
||||
assertThat(pemCert, notNullValue());
|
||||
assertThat(pemCert, equalTo(certificate));
|
||||
}
|
||||
|
||||
public void testSubjectAlternativeNames() throws Exception {
|
||||
final boolean resolveName = randomBoolean();
|
||||
InetAddress address = InetAddresses.forString("127.0.0.1");
|
||||
|
||||
GeneralNames generalNames = CertUtils.getSubjectAlternativeNames(resolveName, Collections.singleton(address));
|
||||
assertThat(generalNames, notNullValue());
|
||||
GeneralName[] generalNameArray = generalNames.getNames();
|
||||
assertThat(generalNameArray, notNullValue());
|
||||
|
||||
if (resolveName) {
|
||||
assertThat(generalNameArray.length, is(2));
|
||||
int firstType = generalNameArray[0].getTagNo();
|
||||
if (firstType == GeneralName.iPAddress) {
|
||||
assertThat(generalNameArray[1].getTagNo(), is(GeneralName.dNSName));
|
||||
} else if (firstType == GeneralName.dNSName) {
|
||||
assertThat(generalNameArray[1].getTagNo(), is(GeneralName.iPAddress));
|
||||
} else {
|
||||
fail("unknown tag value: " + firstType);
|
||||
}
|
||||
} else {
|
||||
assertThat(generalNameArray.length, is(1));
|
||||
assertThat(generalNameArray[0].getTagNo(), is(GeneralName.iPAddress));
|
||||
}
|
||||
}
|
||||
|
||||
public void testIsAnyLocalAddress() throws Exception {
|
||||
InetAddress address = mock(InetAddress.class);
|
||||
when(address.isAnyLocalAddress()).thenReturn(true);
|
||||
|
||||
GeneralNames generalNames = CertUtils.getSubjectAlternativeNames(randomBoolean(), Collections.singleton(address));
|
||||
assertThat(generalNames, notNullValue());
|
||||
GeneralName[] generalNameArray = generalNames.getNames();
|
||||
assertThat(generalNameArray, notNullValue());
|
||||
|
||||
verify(address).isAnyLocalAddress();
|
||||
verifyNoMoreInteractions(address);
|
||||
}
|
||||
}
|
|
@ -12,6 +12,7 @@ import org.elasticsearch.ElasticsearchException;
|
|||
import org.elasticsearch.common.settings.Settings;
|
||||
import org.elasticsearch.common.unit.TimeValue;
|
||||
import org.elasticsearch.env.Environment;
|
||||
import org.elasticsearch.shield.ssl.SSLConfiguration.Global;
|
||||
import org.elasticsearch.test.ESTestCase;
|
||||
import org.elasticsearch.test.junit.annotations.Network;
|
||||
import org.junit.Before;
|
||||
|
@ -39,6 +40,7 @@ import static org.hamcrest.Matchers.nullValue;
|
|||
import static org.hamcrest.Matchers.sameInstance;
|
||||
|
||||
public class ClientSSLServiceTests extends ESTestCase {
|
||||
|
||||
Environment env;
|
||||
Path testclientStore;
|
||||
|
||||
|
@ -50,13 +52,15 @@ public class ClientSSLServiceTests extends ESTestCase {
|
|||
|
||||
public void testThatInvalidProtocolThrowsException() throws Exception {
|
||||
try {
|
||||
new ClientSSLService(Settings.builder()
|
||||
Settings settings = Settings.builder()
|
||||
.put("xpack.security.ssl.protocol", "non-existing")
|
||||
.put("xpack.security.ssl.keystore.path", testclientStore)
|
||||
.put("xpack.security.ssl.keystore.password", "testclient")
|
||||
.put("xpack.security.ssl.truststore.path", testclientStore)
|
||||
.put("xpack.security.ssl.truststore.password", "testclient")
|
||||
.build()).createSSLEngine();
|
||||
.build();
|
||||
ClientSSLService clientSSLService = new ClientSSLService(settings, new Global(settings));
|
||||
clientSSLService.createSSLEngine();
|
||||
fail("expected an exception");
|
||||
} catch (ElasticsearchException e) {
|
||||
assertThat(e.getMessage(), containsString("failed to initialize the SSLContext"));
|
||||
|
@ -148,7 +152,9 @@ public class ClientSSLServiceTests extends ESTestCase {
|
|||
}
|
||||
|
||||
public void testThatCreateClientSSLEngineWithoutAnySettingsWorks() throws Exception {
|
||||
ClientSSLService sslService = createClientSSLService(Settings.EMPTY);
|
||||
ClientSSLService sslService = createClientSSLService(Settings.builder()
|
||||
.put(Global.AUTO_GENERATE_SSL_SETTING.getKey(), false)
|
||||
.build());
|
||||
SSLEngine sslEngine = sslService.createSSLEngine();
|
||||
assertThat(sslEngine, notNullValue());
|
||||
}
|
||||
|
@ -173,7 +179,8 @@ public class ClientSSLServiceTests extends ESTestCase {
|
|||
|
||||
@Network
|
||||
public void testThatSSLContextWithoutSettingsWorks() throws Exception {
|
||||
ClientSSLService sslService = createClientSSLService(Settings.EMPTY);
|
||||
ClientSSLService sslService = createClientSSLService(Settings.builder()
|
||||
.put(Global.AUTO_GENERATE_SSL_SETTING.getKey(), false).build());
|
||||
SSLContext sslContext = sslService.sslContext();
|
||||
try (CloseableHttpClient client = HttpClients.custom().setSslcontext(sslContext).build()) {
|
||||
// Execute a GET on a site known to have a valid certificate signed by a trusted public CA
|
||||
|
@ -184,12 +191,24 @@ public class ClientSSLServiceTests extends ESTestCase {
|
|||
}
|
||||
|
||||
@Network
|
||||
public void testThatSSLContextWithKeystoreDoesNotTrustAllPublicCAs() throws Exception {
|
||||
public void testThatSSLContextTrustsJDKTrustedCAs() throws Exception {
|
||||
ClientSSLService sslService = createClientSSLService(Settings.builder()
|
||||
.put("xpack.security.ssl.keystore.path", testclientStore)
|
||||
.put("xpack.security.ssl.keystore.password", "testclient")
|
||||
.build());
|
||||
SSLContext sslContext = sslService.sslContext();
|
||||
try (CloseableHttpClient client = HttpClients.custom().setSslcontext(sslContext).build()) {
|
||||
// Execute a GET on a site known to have a valid certificate signed by a trusted public CA which will succeed because the JDK
|
||||
// certs are trusted by default
|
||||
client.execute(new HttpGet("https://www.elastic.co/")).close();
|
||||
}
|
||||
|
||||
sslService = createClientSSLService(Settings.builder()
|
||||
.put("xpack.security.ssl.keystore.path", testclientStore)
|
||||
.put("xpack.security.ssl.keystore.password", "testclient")
|
||||
.put(Global.INCLUDE_JDK_CERTS_SETTING.getKey(), "false")
|
||||
.build());
|
||||
sslContext = sslService.sslContext();
|
||||
try (CloseableHttpClient client = HttpClients.custom().setSslcontext(sslContext).build()) {
|
||||
// Execute a GET on a site known to have a valid certificate signed by a trusted public CA
|
||||
// This will result in a SSLHandshakeException because the truststore is the testnodestore, which doesn't
|
||||
|
@ -226,7 +245,7 @@ public class ClientSSLServiceTests extends ESTestCase {
|
|||
}
|
||||
|
||||
public void testValidCiphersAndInvalidCiphersWork() throws Exception {
|
||||
List<String> ciphers = new ArrayList<>(SSLSettings.Globals.DEFAULT_CIPHERS);
|
||||
List<String> ciphers = new ArrayList<>(Global.DEFAULT_CIPHERS);
|
||||
ciphers.add("foo");
|
||||
ciphers.add("bar");
|
||||
ClientSSLService sslService = createClientSSLService(Settings.builder()
|
||||
|
@ -246,7 +265,7 @@ public class ClientSSLServiceTests extends ESTestCase {
|
|||
sslService.createSSLEngine();
|
||||
fail("Expected IllegalArgumentException");
|
||||
} catch (IllegalArgumentException e) {
|
||||
assertThat(e.getMessage(), is("failed loading cipher suites [[foo, bar]]"));
|
||||
assertThat(e.getMessage(), is("none of the ciphers [foo, bar] are supported by this JVM"));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -255,8 +274,8 @@ public class ClientSSLServiceTests extends ESTestCase {
|
|||
.put("xpack.security.ssl.keystore.path", testclientStore)
|
||||
.put("xpack.security.ssl.keystore.password", "testclient")
|
||||
.build());
|
||||
SSLSocketFactory factory = sslService.sslSocketFactory();
|
||||
final String[] ciphers = sslService.supportedCiphers(factory.getSupportedCipherSuites(), sslService.ciphers());
|
||||
SSLSocketFactory factory = sslService.sslSocketFactory(Settings.EMPTY);
|
||||
final String[] ciphers = sslService.supportedCiphers(factory.getSupportedCipherSuites(), sslService.ciphers(), false);
|
||||
assertThat(factory.getDefaultCipherSuites(), is(ciphers));
|
||||
|
||||
try (SSLSocket socket = (SSLSocket) factory.createSocket()) {
|
||||
|
@ -266,7 +285,7 @@ public class ClientSSLServiceTests extends ESTestCase {
|
|||
}
|
||||
|
||||
ClientSSLService createClientSSLService(Settings settings) {
|
||||
ClientSSLService clientSSLService = new ClientSSLService(settings);
|
||||
ClientSSLService clientSSLService = new ClientSSLService(settings, new Global(settings));
|
||||
clientSSLService.setEnvironment(env);
|
||||
return clientSSLService;
|
||||
}
|
||||
|
|
|
@ -0,0 +1,751 @@
|
|||
/*
|
||||
* 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.shield.ssl;
|
||||
|
||||
import org.bouncycastle.openssl.jcajce.JcaPEMWriter;
|
||||
import org.bouncycastle.openssl.jcajce.JcePEMEncryptorBuilder;
|
||||
import org.elasticsearch.ElasticsearchException;
|
||||
import org.elasticsearch.common.settings.Settings;
|
||||
import org.elasticsearch.common.unit.TimeValue;
|
||||
import org.elasticsearch.env.Environment;
|
||||
import org.elasticsearch.shield.ssl.SSLConfiguration.Custom;
|
||||
import org.elasticsearch.shield.ssl.SSLConfiguration.Global;
|
||||
import org.elasticsearch.shield.ssl.TrustConfig.Reloadable.Listener;
|
||||
import org.elasticsearch.test.ESTestCase;
|
||||
import org.elasticsearch.threadpool.ThreadPool;
|
||||
import org.elasticsearch.watcher.ResourceWatcherService;
|
||||
|
||||
import javax.net.ssl.KeyManager;
|
||||
import javax.net.ssl.KeyManagerFactory;
|
||||
import javax.net.ssl.TrustManager;
|
||||
import javax.net.ssl.X509ExtendedKeyManager;
|
||||
import javax.net.ssl.X509ExtendedTrustManager;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.OutputStream;
|
||||
import java.io.OutputStreamWriter;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.nio.file.AtomicMoveNotSupportedException;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.StandardCopyOption;
|
||||
import java.nio.file.attribute.BasicFileAttributes;
|
||||
import java.security.KeyPair;
|
||||
import java.security.KeyStore;
|
||||
import java.security.PrivateKey;
|
||||
import java.security.cert.Certificate;
|
||||
import java.security.cert.X509Certificate;
|
||||
import java.util.Arrays;
|
||||
import java.util.concurrent.CountDownLatch;
|
||||
import java.util.concurrent.atomic.AtomicReference;
|
||||
|
||||
import static org.hamcrest.Matchers.containsString;
|
||||
import static org.hamcrest.Matchers.equalTo;
|
||||
import static org.hamcrest.Matchers.instanceOf;
|
||||
import static org.hamcrest.Matchers.is;
|
||||
import static org.hamcrest.Matchers.not;
|
||||
import static org.hamcrest.Matchers.notNullValue;
|
||||
import static org.hamcrest.Matchers.nullValue;
|
||||
import static org.hamcrest.Matchers.sameInstance;
|
||||
|
||||
public class SSLConfigurationTests extends ESTestCase {
|
||||
|
||||
private static final Settings NO_AUTO_GEN = Settings.builder()
|
||||
.put(Global.AUTO_GENERATE_SSL_SETTING.getKey(), false)
|
||||
.build();
|
||||
|
||||
public void testThatSSLConfigurationHasCorrectDefaults() {
|
||||
SSLConfiguration globalConfig = new Global(Settings.EMPTY);
|
||||
assertThat(globalConfig.keyConfig(), instanceOf(AutoGeneratedKeyConfig.class));
|
||||
assertThat(globalConfig.trustConfig(), sameInstance(globalConfig.keyConfig()));
|
||||
assertThat(globalConfig.sessionCacheSize(), is(equalTo(Global.DEFAULT_SESSION_CACHE_SIZE)));
|
||||
assertThat(globalConfig.sessionCacheTimeout(), is(equalTo(Global.DEFAULT_SESSION_CACHE_TIMEOUT)));
|
||||
assertThat(globalConfig.protocol(), is(equalTo(Global.DEFAULT_PROTOCOL)));
|
||||
|
||||
SSLConfiguration scopedConfig = new Custom(Settings.EMPTY, globalConfig);
|
||||
assertThat(scopedConfig.keyConfig(), sameInstance(globalConfig.keyConfig()));
|
||||
assertThat(scopedConfig.trustConfig(), sameInstance(globalConfig.trustConfig()));
|
||||
assertThat(globalConfig.sessionCacheSize(), is(equalTo(Global.DEFAULT_SESSION_CACHE_SIZE)));
|
||||
assertThat(globalConfig.sessionCacheTimeout(), is(equalTo(Global.DEFAULT_SESSION_CACHE_TIMEOUT)));
|
||||
assertThat(globalConfig.protocol(), is(equalTo(Global.DEFAULT_PROTOCOL)));
|
||||
}
|
||||
|
||||
public void testThatSSLConfigurationWithoutAutoGenHasCorrectDefaults() {
|
||||
SSLConfiguration globalSettings = new Global(NO_AUTO_GEN);
|
||||
SSLConfiguration scopedSettings = new Custom(Settings.EMPTY, globalSettings);
|
||||
for (SSLConfiguration sslConfiguration : Arrays.asList(globalSettings, scopedSettings)) {
|
||||
assertThat(sslConfiguration.keyConfig(), sameInstance(KeyConfig.NONE));
|
||||
assertThat(sslConfiguration.sessionCacheSize(), is(equalTo(Global.DEFAULT_SESSION_CACHE_SIZE)));
|
||||
assertThat(sslConfiguration.sessionCacheTimeout(), is(equalTo(Global.DEFAULT_SESSION_CACHE_TIMEOUT)));
|
||||
assertThat(sslConfiguration.protocol(), is(equalTo(Global.DEFAULT_PROTOCOL)));
|
||||
assertThat(sslConfiguration.trustConfig(), notNullValue());
|
||||
assertThat(sslConfiguration.trustConfig(), is(instanceOf(StoreTrustConfig.class)));
|
||||
|
||||
StoreTrustConfig ksTrustInfo = (StoreTrustConfig) sslConfiguration.trustConfig();
|
||||
assertThat(ksTrustInfo.trustStorePath, is(nullValue()));
|
||||
assertThat(ksTrustInfo.trustStorePassword, is(nullValue()));
|
||||
assertThat(ksTrustInfo.trustStoreAlgorithm, is(nullValue()));
|
||||
}
|
||||
}
|
||||
|
||||
public void testThatOnlyKeystoreInSettingsSetsTruststoreSettings() {
|
||||
Settings settings = Settings.builder()
|
||||
.put("xpack.security.ssl.keystore.path", "path")
|
||||
.put("xpack.security.ssl.keystore.password", "password")
|
||||
.build();
|
||||
Settings profileSettings = settings.getByPrefix("xpack.security.ssl.");
|
||||
// Pass settings in as component settings
|
||||
SSLConfiguration globalSettings = new Global(settings);
|
||||
SSLConfiguration scopedSettings = new Custom(profileSettings, globalSettings);
|
||||
SSLConfiguration scopedEmptyGlobalSettings =
|
||||
new Custom(profileSettings, new Global(NO_AUTO_GEN));
|
||||
for (SSLConfiguration sslConfiguration : Arrays.asList(globalSettings, scopedSettings, scopedEmptyGlobalSettings)) {
|
||||
assertThat(sslConfiguration.keyConfig(), instanceOf(StoreKeyConfig.class));
|
||||
StoreKeyConfig ksKeyInfo = (StoreKeyConfig) sslConfiguration.keyConfig();
|
||||
|
||||
assertThat(ksKeyInfo.keyStorePath, is(equalTo("path")));
|
||||
assertThat(ksKeyInfo.keyStorePassword, is(equalTo("password")));
|
||||
assertThat(ksKeyInfo.keyPassword, is(equalTo(ksKeyInfo.keyStorePassword)));
|
||||
assertThat(ksKeyInfo.keyStoreAlgorithm, is(KeyManagerFactory.getDefaultAlgorithm()));
|
||||
assertThat(sslConfiguration.trustConfig(), is(sameInstance(ksKeyInfo)));
|
||||
}
|
||||
}
|
||||
|
||||
public void testThatKeyPasswordCanBeSet() {
|
||||
Settings settings = Settings.builder()
|
||||
.put("xpack.security.ssl.keystore.path", "path")
|
||||
.put("xpack.security.ssl.keystore.password", "password")
|
||||
.put("xpack.security.ssl.keystore.key_password", "key")
|
||||
.build();
|
||||
SSLConfiguration sslConfiguration = new Global(settings);
|
||||
assertThat(sslConfiguration.keyConfig(), instanceOf(StoreKeyConfig.class));
|
||||
StoreKeyConfig ksKeyInfo = (StoreKeyConfig) sslConfiguration.keyConfig();
|
||||
assertThat(ksKeyInfo.keyStorePassword, is(equalTo("password")));
|
||||
assertThat(ksKeyInfo.keyPassword, is(equalTo("key")));
|
||||
|
||||
// Pass settings in as profile settings
|
||||
Settings profileSettings = settings.getByPrefix("xpack.security.ssl.");
|
||||
SSLConfiguration sslConfiguration1 = new Custom(profileSettings,
|
||||
randomBoolean() ? sslConfiguration : new Global(NO_AUTO_GEN));
|
||||
assertThat(sslConfiguration1.keyConfig(), instanceOf(StoreKeyConfig.class));
|
||||
ksKeyInfo = (StoreKeyConfig) sslConfiguration1.keyConfig();
|
||||
assertThat(ksKeyInfo.keyStorePassword, is(equalTo("password")));
|
||||
assertThat(ksKeyInfo.keyPassword, is(equalTo("key")));
|
||||
}
|
||||
|
||||
|
||||
public void testThatProfileSettingsOverrideServiceSettings() {
|
||||
Settings profileSettings = Settings.builder()
|
||||
.put("keystore.path", "path")
|
||||
.put("keystore.password", "password")
|
||||
.put("keystore.key_password", "key")
|
||||
.put("keystore.algorithm", "algo")
|
||||
.put("truststore.path", "trust path")
|
||||
.put("truststore.password", "password for trust")
|
||||
.put("truststore.algorithm", "trusted")
|
||||
.put("protocol", "ssl")
|
||||
.put("session.cache_size", "3")
|
||||
.put("session.cache_timeout", "10m")
|
||||
.build();
|
||||
|
||||
Settings serviceSettings = Settings.builder()
|
||||
.put("xpack.security.ssl.keystore.path", "comp path")
|
||||
.put("xpack.security.ssl.keystore.password", "comp password")
|
||||
.put("xpack.security.ssl.keystore.key_password", "comp key")
|
||||
.put("xpack.security.ssl.keystore.algorithm", "comp algo")
|
||||
.put("xpack.security.ssl.truststore.path", "comp trust path")
|
||||
.put("xpack.security.ssl.truststore.password", "comp password for trust")
|
||||
.put("xpack.security.ssl.truststore.algorithm", "comp trusted")
|
||||
.put("xpack.security.ssl.protocol", "tls")
|
||||
.put("xpack.security.ssl.session.cache_size", "7")
|
||||
.put("xpack.security.ssl.session.cache_timeout", "20m")
|
||||
.build();
|
||||
|
||||
SSLConfiguration globalSettings = new Global(serviceSettings);
|
||||
SSLConfiguration sslConfiguration = new Custom(profileSettings, globalSettings);
|
||||
assertThat(sslConfiguration.keyConfig(), instanceOf(StoreKeyConfig.class));
|
||||
StoreKeyConfig ksKeyInfo = (StoreKeyConfig) sslConfiguration.keyConfig();
|
||||
assertThat(ksKeyInfo.keyStorePath, is(equalTo("path")));
|
||||
assertThat(ksKeyInfo.keyStorePassword, is(equalTo("password")));
|
||||
assertThat(ksKeyInfo.keyPassword, is(equalTo("key")));
|
||||
assertThat(ksKeyInfo.keyStoreAlgorithm, is(equalTo("algo")));
|
||||
assertThat(sslConfiguration.trustConfig(), instanceOf(StoreTrustConfig.class));
|
||||
StoreTrustConfig ksTrustInfo = (StoreTrustConfig) sslConfiguration.trustConfig();
|
||||
assertThat(ksTrustInfo.trustStorePath, is(equalTo("trust path")));
|
||||
assertThat(ksTrustInfo.trustStorePassword, is(equalTo("password for trust")));
|
||||
assertThat(ksTrustInfo.trustStoreAlgorithm, is(equalTo("trusted")));
|
||||
assertThat(sslConfiguration.protocol(), is(equalTo("ssl")));
|
||||
assertThat(sslConfiguration.sessionCacheSize(), is(equalTo(3)));
|
||||
assertThat(sslConfiguration.sessionCacheTimeout(), is(equalTo(TimeValue.timeValueMinutes(10L))));
|
||||
}
|
||||
|
||||
public void testThatEmptySettingsAreEqual() {
|
||||
SSLConfiguration sslConfiguration = new Global(NO_AUTO_GEN);
|
||||
SSLConfiguration sslConfiguration1 = new Global(NO_AUTO_GEN);
|
||||
assertThat(sslConfiguration.equals(sslConfiguration1), is(equalTo(true)));
|
||||
assertThat(sslConfiguration1.equals(sslConfiguration), is(equalTo(true)));
|
||||
assertThat(sslConfiguration.equals(sslConfiguration), is(equalTo(true)));
|
||||
assertThat(sslConfiguration1.equals(sslConfiguration1), is(equalTo(true)));
|
||||
|
||||
SSLConfiguration profileSSLConfiguration = new Custom(Settings.EMPTY, sslConfiguration);
|
||||
assertThat(sslConfiguration.equals(profileSSLConfiguration), is(equalTo(true)));
|
||||
assertThat(profileSSLConfiguration.equals(sslConfiguration), is(equalTo(true)));
|
||||
assertThat(profileSSLConfiguration.equals(profileSSLConfiguration), is(equalTo(true)));
|
||||
}
|
||||
|
||||
public void testThatSettingsWithDifferentKeystoresAreNotEqual() {
|
||||
SSLConfiguration sslConfiguration = new Global(Settings.builder()
|
||||
.put("xpack.security.ssl.keystore.path", "path").build());
|
||||
SSLConfiguration sslConfiguration1 = new Global(Settings.builder()
|
||||
.put("xpack.security.ssl.keystore.path", "path1").build());
|
||||
assertThat(sslConfiguration.equals(sslConfiguration1), is(equalTo(false)));
|
||||
assertThat(sslConfiguration1.equals(sslConfiguration), is(equalTo(false)));
|
||||
assertThat(sslConfiguration.equals(sslConfiguration), is(equalTo(true)));
|
||||
assertThat(sslConfiguration1.equals(sslConfiguration1), is(equalTo(true)));
|
||||
}
|
||||
|
||||
public void testThatSettingsWithDifferentProtocolsAreNotEqual() {
|
||||
SSLConfiguration sslConfiguration = new Global(Settings.builder()
|
||||
.put("xpack.security.ssl.protocol", "ssl").build());
|
||||
SSLConfiguration sslConfiguration1 = new Global(Settings.builder()
|
||||
.put("xpack.security.ssl.protocol", "tls").build());
|
||||
assertThat(sslConfiguration.equals(sslConfiguration1), is(equalTo(false)));
|
||||
assertThat(sslConfiguration1.equals(sslConfiguration), is(equalTo(false)));
|
||||
assertThat(sslConfiguration.equals(sslConfiguration), is(equalTo(true)));
|
||||
assertThat(sslConfiguration1.equals(sslConfiguration1), is(equalTo(true)));
|
||||
}
|
||||
|
||||
public void testThatSettingsWithDifferentTruststoresAreNotEqual() {
|
||||
SSLConfiguration sslConfiguration = new Global(Settings.builder()
|
||||
.put("xpack.security.ssl.truststore.path", "/trust").build());
|
||||
SSLConfiguration sslConfiguration1 = new Global(Settings.builder()
|
||||
.put("xpack.security.ssl.truststore.path", "/truststore").build());
|
||||
assertThat(sslConfiguration.equals(sslConfiguration1), is(equalTo(false)));
|
||||
assertThat(sslConfiguration1.equals(sslConfiguration), is(equalTo(false)));
|
||||
assertThat(sslConfiguration.equals(sslConfiguration), is(equalTo(true)));
|
||||
assertThat(sslConfiguration1.equals(sslConfiguration1), is(equalTo(true)));
|
||||
}
|
||||
|
||||
public void testThatEmptySettingsHaveSameHashCode() {
|
||||
SSLConfiguration sslConfiguration = new Global(NO_AUTO_GEN);
|
||||
SSLConfiguration sslConfiguration1 = new Global(NO_AUTO_GEN);
|
||||
assertThat(sslConfiguration.hashCode(), is(equalTo(sslConfiguration1.hashCode())));
|
||||
|
||||
SSLConfiguration profileSettings = new Custom(Settings.EMPTY, sslConfiguration);
|
||||
assertThat(profileSettings.hashCode(), is(equalTo(sslConfiguration.hashCode())));
|
||||
}
|
||||
|
||||
public void testThatSettingsWithDifferentKeystoresHaveDifferentHashCode() {
|
||||
SSLConfiguration sslConfiguration = new Global(Settings.builder()
|
||||
.put("xpack.security.ssl.keystore.path", "path").build());
|
||||
SSLConfiguration sslConfiguration1 = new Global(Settings.builder()
|
||||
.put("xpack.security.ssl.keystore.path", "path1").build());
|
||||
assertThat(sslConfiguration.hashCode(), is(not(equalTo(sslConfiguration1.hashCode()))));
|
||||
}
|
||||
|
||||
public void testThatSettingsWithDifferentProtocolsHaveDifferentHashCode() {
|
||||
SSLConfiguration sslConfiguration = new Global(Settings.builder()
|
||||
.put("xpack.security.ssl.protocol", "ssl").build());
|
||||
SSLConfiguration sslConfiguration1 = new Global(Settings.builder()
|
||||
.put("xpack.security.ssl.protocol", "tls").build());
|
||||
assertThat(sslConfiguration.hashCode(), is(not(equalTo(sslConfiguration1.hashCode()))));
|
||||
}
|
||||
|
||||
public void testThatSettingsWithDifferentTruststoresHaveDifferentHashCode() {
|
||||
SSLConfiguration sslConfiguration = new Global(Settings.builder()
|
||||
.put("xpack.security.ssl.truststore.path", "/trust").build());
|
||||
SSLConfiguration sslConfiguration1 = new Global(Settings.builder()
|
||||
.put("xpack.security.ssl.truststore.path", "/truststore").build());
|
||||
assertThat(sslConfiguration.hashCode(), is(not(equalTo(sslConfiguration1.hashCode()))));
|
||||
}
|
||||
|
||||
public void testConfigurationUsingPEMKeyFiles() {
|
||||
Environment env = randomBoolean() ? null :
|
||||
new Environment(Settings.builder().put("path.home", createTempDir()).build());
|
||||
Settings settings = Settings.builder()
|
||||
.put("xpack.security.ssl.key.path", getDataPath("/org/elasticsearch/shield/transport/ssl/certs/simple/testnode.pem"))
|
||||
.put("xpack.security.ssl.key.password", "testnode")
|
||||
.put("xpack.security.ssl.cert", getDataPath("/org/elasticsearch/shield/transport/ssl/certs/simple/testnode.crt"))
|
||||
.build();
|
||||
|
||||
SSLConfiguration config = new Global(settings);
|
||||
assertThat(config.keyConfig(), instanceOf(PEMKeyConfig.class));
|
||||
PEMKeyConfig keyConfig = (PEMKeyConfig) config.keyConfig();
|
||||
KeyManager[] keyManagers = keyConfig.keyManagers(env, null, null);
|
||||
assertThat(keyManagers.length, is(1));
|
||||
assertThat(config.trustConfig(), sameInstance(keyConfig));
|
||||
TrustManager[] trustManagers = keyConfig.trustManagers(env, null, null);
|
||||
assertThat(trustManagers.length, is(1));
|
||||
}
|
||||
|
||||
public void testConfigurationUsingPEMKeyAndTrustFiles() {
|
||||
Environment env = randomBoolean() ? null :
|
||||
new Environment(Settings.builder().put("path.home", createTempDir()).build());
|
||||
Settings settings = Settings.builder()
|
||||
.put("xpack.security.ssl.key.path", getDataPath("/org/elasticsearch/shield/transport/ssl/certs/simple/testnode.pem"))
|
||||
.put("xpack.security.ssl.key.password", "testnode")
|
||||
.put("xpack.security.ssl.cert", getDataPath("/org/elasticsearch/shield/transport/ssl/certs/simple/testnode.crt"))
|
||||
.putArray("xpack.security.ssl.ca",
|
||||
getDataPath("/org/elasticsearch/shield/transport/ssl/certs/simple/testnode.crt").toString(),
|
||||
getDataPath("/org/elasticsearch/shield/transport/ssl/certs/simple/testclient.crt").toString())
|
||||
.build();
|
||||
|
||||
SSLConfiguration config = new Global(settings);
|
||||
assertThat(config.keyConfig(), instanceOf(PEMKeyConfig.class));
|
||||
PEMKeyConfig keyConfig = (PEMKeyConfig) config.keyConfig();
|
||||
KeyManager[] keyManagers = keyConfig.keyManagers(env, null, null);
|
||||
assertThat(keyManagers.length, is(1));
|
||||
assertThat(config.trustConfig(), not(sameInstance(keyConfig)));
|
||||
assertThat(config.trustConfig(), instanceOf(PEMTrustConfig.class));
|
||||
TrustManager[] trustManagers = keyConfig.trustManagers(env, null, null);
|
||||
assertThat(trustManagers.length, is(1));
|
||||
}
|
||||
|
||||
public void testReloadingKeyStore() throws Exception {
|
||||
Environment env = randomBoolean() ? null :
|
||||
new Environment(Settings.builder().put("path.home", createTempDir()).build());
|
||||
Path tempDir = createTempDir();
|
||||
Path keystorePath = tempDir.resolve("testnode.jks");
|
||||
Files.copy(getDataPath("/org/elasticsearch/shield/transport/ssl/certs/simple/testnode.jks"), keystorePath);
|
||||
Settings settings = Settings.builder()
|
||||
.put("xpack.security.ssl.keystore.path", keystorePath)
|
||||
.put("xpack.security.ssl.keystore.password", "testnode")
|
||||
.put(Global.INCLUDE_JDK_CERTS_SETTING.getKey(), randomBoolean())
|
||||
.build();
|
||||
|
||||
SSLConfiguration config = new Global(settings);
|
||||
assertThat(config.keyConfig(), instanceOf(StoreKeyConfig.class));
|
||||
StoreKeyConfig keyConfig = (StoreKeyConfig) config.keyConfig();
|
||||
|
||||
CountDownLatch latch = new CountDownLatch(2);
|
||||
AtomicReference<Exception> exceptionRef = new AtomicReference<>();
|
||||
Listener listener = createRefreshListener(latch, exceptionRef);
|
||||
|
||||
ThreadPool threadPool = new ThreadPool("reload");
|
||||
try {
|
||||
ResourceWatcherService resourceWatcherService =
|
||||
new ResourceWatcherService(Settings.builder().put("resource.reload.interval.high", "1s").build(), threadPool).start();
|
||||
KeyManager[] keyManagers = keyConfig.keyManagers(env, resourceWatcherService, listener);
|
||||
assertThat(keyManagers.length, is(1));
|
||||
assertThat(keyManagers[0], instanceOf(X509ExtendedKeyManager.class));
|
||||
X509ExtendedKeyManager keyManager = (X509ExtendedKeyManager) keyManagers[0];
|
||||
String[] aliases = keyManager.getServerAliases("RSA", null);
|
||||
assertNotNull(aliases);
|
||||
assertThat(aliases.length, is(1));
|
||||
assertThat(aliases[0], is("testnode"));
|
||||
TrustManager[] trustManagers = keyConfig.trustManagers(env, resourceWatcherService, listener);
|
||||
assertThat(trustManagers.length, is(1));
|
||||
assertThat(trustManagers[0], instanceOf(X509ExtendedTrustManager.class));
|
||||
X509ExtendedTrustManager trustManager = (X509ExtendedTrustManager) trustManagers[0];
|
||||
Certificate[] certificates = trustManager.getAcceptedIssuers();
|
||||
final int trustedCount = certificates.length;
|
||||
assertThat(latch.getCount(), is(2L));
|
||||
|
||||
KeyStore keyStore = KeyStore.getInstance("jks");
|
||||
keyStore.load(null, null);
|
||||
Path updated = tempDir.resolve("updated.jks");
|
||||
try (OutputStream out = Files.newOutputStream(updated)) {
|
||||
keyStore.store(out, "testnode".toCharArray());
|
||||
}
|
||||
atomicMoveIfPossible(updated, keystorePath);
|
||||
latch.await();
|
||||
assertThat(exceptionRef.get(), is(nullValue()));
|
||||
aliases = keyManager.getServerAliases("RSA", null);
|
||||
assertThat(aliases, is(nullValue()));
|
||||
certificates = trustManager.getAcceptedIssuers();
|
||||
assertThat(trustedCount - certificates.length, is(5));
|
||||
} finally {
|
||||
threadPool.shutdown();
|
||||
}
|
||||
}
|
||||
|
||||
public void testReloadingPEMKeyConfig() throws Exception {
|
||||
Environment env = randomBoolean() ? null :
|
||||
new Environment(Settings.builder().put("path.home", createTempDir()).build());
|
||||
Path tempDir = createTempDir();
|
||||
Path keyPath = tempDir.resolve("testnode.pem");
|
||||
Path certPath = tempDir.resolve("testnode.crt");
|
||||
Path clientCertPath = tempDir.resolve("testclient.crt");
|
||||
Files.copy(getDataPath("/org/elasticsearch/shield/transport/ssl/certs/simple/testnode.pem"), keyPath);
|
||||
Files.copy(getDataPath("/org/elasticsearch/shield/transport/ssl/certs/simple/testnode.crt"), certPath);
|
||||
Files.copy(getDataPath("/org/elasticsearch/shield/transport/ssl/certs/simple/testclient.crt"), clientCertPath);
|
||||
Settings settings = Settings.builder()
|
||||
.put("xpack.security.ssl.key.path", keyPath)
|
||||
.put("xpack.security.ssl.key.password", "testnode")
|
||||
.put("xpack.security.ssl.cert", certPath)
|
||||
.putArray("xpack.security.ssl.ca", certPath.toString(), clientCertPath.toString())
|
||||
.put(Global.INCLUDE_JDK_CERTS_SETTING.getKey(), randomBoolean())
|
||||
.build();
|
||||
SSLConfiguration config = new Global(settings);
|
||||
assertThat(config.keyConfig(), instanceOf(PEMKeyConfig.class));
|
||||
PEMKeyConfig keyConfig = (PEMKeyConfig) config.keyConfig();
|
||||
|
||||
CountDownLatch latch = new CountDownLatch(2);
|
||||
AtomicReference<Exception> exceptionRef = new AtomicReference<>();
|
||||
Listener listener = createRefreshListener(latch, exceptionRef);
|
||||
|
||||
ThreadPool threadPool = new ThreadPool("reload pem");
|
||||
try {
|
||||
ResourceWatcherService resourceWatcherService =
|
||||
new ResourceWatcherService(Settings.builder().put("resource.reload.interval.high", "1s").build(), threadPool).start();
|
||||
KeyManager[] keyManagers = keyConfig.keyManagers(env, resourceWatcherService, listener);
|
||||
assertThat(keyManagers.length, is(1));
|
||||
assertThat(keyManagers[0], instanceOf(X509ExtendedKeyManager.class));
|
||||
X509ExtendedKeyManager keyManager = (X509ExtendedKeyManager) keyManagers[0];
|
||||
String[] aliases = keyManager.getServerAliases("RSA", null);
|
||||
assertThat(aliases, is(notNullValue()));
|
||||
assertThat(aliases.length, is(1));
|
||||
assertThat(aliases[0], is("key"));
|
||||
PrivateKey privateKey = keyManager.getPrivateKey(aliases[0]);
|
||||
TrustManager[] trustManagers = keyConfig.trustManagers(env, resourceWatcherService, listener);
|
||||
assertThat(trustManagers.length, is(1));
|
||||
assertThat(trustManagers[0], instanceOf(X509ExtendedTrustManager.class));
|
||||
X509ExtendedTrustManager trustManager = (X509ExtendedTrustManager) trustManagers[0];
|
||||
Certificate[] certificates = trustManager.getAcceptedIssuers();
|
||||
final int trustedCount = certificates.length;
|
||||
assertThat(latch.getCount(), is(2L));
|
||||
|
||||
// make sure we wait enough to see a change. if time is within a second the file may not be seen as modified since the size is
|
||||
// the same!
|
||||
awaitBusy(() -> {
|
||||
try {
|
||||
BasicFileAttributes attributes = Files.readAttributes(keyPath, BasicFileAttributes.class);
|
||||
return System.currentTimeMillis() - attributes.lastModifiedTime().toMillis() >= 1000L;
|
||||
} catch (IOException e) {
|
||||
throw new ElasticsearchException("io exception while checking time", e);
|
||||
}
|
||||
});
|
||||
Path updatedKeyPath = tempDir.resolve("updated.pem");
|
||||
KeyPair keyPair = CertUtils.generateKeyPair();
|
||||
try (OutputStream os = Files.newOutputStream(updatedKeyPath);
|
||||
OutputStreamWriter osWriter = new OutputStreamWriter(os, StandardCharsets.UTF_8);
|
||||
JcaPEMWriter writer = new JcaPEMWriter(osWriter)) {
|
||||
writer.writeObject(keyPair,
|
||||
new JcePEMEncryptorBuilder("DES-EDE3-CBC").setProvider(CertUtils.BC_PROV).build("testnode".toCharArray()));
|
||||
}
|
||||
atomicMoveIfPossible(updatedKeyPath, keyPath);
|
||||
|
||||
latch.await();
|
||||
assertThat(exceptionRef.get(), is(nullValue()));
|
||||
aliases = keyManager.getServerAliases("RSA", null);
|
||||
assertThat(aliases, is(notNullValue()));
|
||||
assertThat(aliases.length, is(1));
|
||||
assertThat(aliases[0], is("key"));
|
||||
assertThat(keyManager.getPrivateKey(aliases[0]), not(equalTo(privateKey)));
|
||||
assertThat(keyManager.getPrivateKey(aliases[0]), is(equalTo(keyPair.getPrivate())));
|
||||
certificates = trustManager.getAcceptedIssuers();
|
||||
assertThat(trustedCount - certificates.length, is(0));
|
||||
} finally {
|
||||
threadPool.shutdown();
|
||||
}
|
||||
}
|
||||
|
||||
public void testReloadingTrustStore() throws Exception {
|
||||
Environment env = randomBoolean() ? null :
|
||||
new Environment(Settings.builder().put("path.home", createTempDir()).build());
|
||||
Path tempDir = createTempDir();
|
||||
Path trustStorePath = tempDir.resolve("testnode.jks");
|
||||
Files.copy(getDataPath("/org/elasticsearch/shield/transport/ssl/certs/simple/testnode.jks"), trustStorePath);
|
||||
Settings settings = Settings.builder()
|
||||
.put("xpack.security.ssl.truststore.path", trustStorePath)
|
||||
.put("xpack.security.ssl.truststore.password", "testnode")
|
||||
.put(Global.INCLUDE_JDK_CERTS_SETTING.getKey(), randomBoolean())
|
||||
.build();
|
||||
|
||||
SSLConfiguration config = new Global(settings);
|
||||
assertThat(config.trustConfig(), instanceOf(StoreTrustConfig.class));
|
||||
StoreTrustConfig trustConfig = (StoreTrustConfig) config.trustConfig();
|
||||
|
||||
CountDownLatch latch = new CountDownLatch(1);
|
||||
AtomicReference<Exception> exceptionRef = new AtomicReference<>();
|
||||
Listener listener = createRefreshListener(latch, exceptionRef);
|
||||
|
||||
ThreadPool threadPool = new ThreadPool("reload");
|
||||
try {
|
||||
ResourceWatcherService resourceWatcherService =
|
||||
new ResourceWatcherService(Settings.builder().put("resource.reload.interval.high", "1s").build(), threadPool).start();
|
||||
TrustManager[] trustManagers = trustConfig.trustManagers(env, resourceWatcherService, listener);
|
||||
assertThat(trustManagers.length, is(1));
|
||||
assertThat(trustManagers[0], instanceOf(X509ExtendedTrustManager.class));
|
||||
X509ExtendedTrustManager trustManager = (X509ExtendedTrustManager) trustManagers[0];
|
||||
Certificate[] certificates = trustManager.getAcceptedIssuers();
|
||||
final int trustedCount = certificates.length;
|
||||
|
||||
assertThat(latch.getCount(), is(1L));
|
||||
|
||||
Path updatedTruststore = tempDir.resolve("updated.jks");
|
||||
KeyStore keyStore = KeyStore.getInstance("jks");
|
||||
keyStore.load(null, null);
|
||||
try (OutputStream out = Files.newOutputStream(updatedTruststore)) {
|
||||
keyStore.store(out, "testnode".toCharArray());
|
||||
}
|
||||
atomicMoveIfPossible(updatedTruststore, trustStorePath);
|
||||
latch.await();
|
||||
assertThat(exceptionRef.get(), is(nullValue()));
|
||||
certificates = trustManager.getAcceptedIssuers();
|
||||
assertThat(trustedCount - certificates.length, is(5));
|
||||
} finally {
|
||||
threadPool.shutdown();
|
||||
}
|
||||
}
|
||||
|
||||
public void testReloadingPEMTrustConfig() throws Exception {
|
||||
Environment env = randomBoolean() ? null :
|
||||
new Environment(Settings.builder().put("path.home", createTempDir()).build());
|
||||
Path tempDir = createTempDir();
|
||||
Path clientCertPath = tempDir.resolve("testclient.crt");
|
||||
Files.copy(getDataPath("/org/elasticsearch/shield/transport/ssl/certs/simple/testclient.crt"), clientCertPath);
|
||||
Settings settings = Settings.builder()
|
||||
.putArray("xpack.security.ssl.ca", clientCertPath.toString())
|
||||
.put(Global.INCLUDE_JDK_CERTS_SETTING.getKey(), false)
|
||||
.build();
|
||||
SSLConfiguration config = new Global(settings);
|
||||
assertThat(config.trustConfig(), instanceOf(PEMTrustConfig.class));
|
||||
PEMTrustConfig trustConfig = (PEMTrustConfig) config.trustConfig();
|
||||
CountDownLatch latch = new CountDownLatch(1);
|
||||
AtomicReference<Exception> exceptionRef = new AtomicReference<>();
|
||||
Listener listener = createRefreshListener(latch, exceptionRef);
|
||||
|
||||
ThreadPool threadPool = new ThreadPool("reload");
|
||||
try {
|
||||
ResourceWatcherService resourceWatcherService =
|
||||
new ResourceWatcherService(Settings.builder().put("resource.reload.interval.high", "1s").build(), threadPool).start();
|
||||
TrustManager[] trustManagers = trustConfig.trustManagers(env, resourceWatcherService, listener);
|
||||
assertThat(trustManagers.length, is(1));
|
||||
assertThat(trustManagers[0], instanceOf(X509ExtendedTrustManager.class));
|
||||
X509ExtendedTrustManager trustManager = (X509ExtendedTrustManager) trustManagers[0];
|
||||
Certificate[] certificates = trustManager.getAcceptedIssuers();
|
||||
assertThat(certificates.length, is(1));
|
||||
assertThat(((X509Certificate)certificates[0]).getSubjectX500Principal().getName(), containsString("Test Client"));
|
||||
assertThat(latch.getCount(), is(1L));
|
||||
|
||||
Path updatedCert = tempDir.resolve("updated.crt");
|
||||
Files.copy(getDataPath("/org/elasticsearch/shield/transport/ssl/certs/simple/testnode.crt"), updatedCert,
|
||||
StandardCopyOption.REPLACE_EXISTING);
|
||||
atomicMoveIfPossible(updatedCert, clientCertPath);
|
||||
latch.await();
|
||||
assertThat(exceptionRef.get(), is(nullValue()));
|
||||
Certificate[] updatedCerts = trustManager.getAcceptedIssuers();
|
||||
assertThat(updatedCerts.length, is(1));
|
||||
assertThat(((X509Certificate)updatedCerts[0]).getSubjectX500Principal().getName(), containsString("Test Node"));
|
||||
assertThat(updatedCerts[0], not(equalTo(certificates[0])));
|
||||
} finally {
|
||||
threadPool.shutdown();
|
||||
}
|
||||
}
|
||||
|
||||
public void testReloadingKeyStoreException() throws Exception {
|
||||
Environment env = randomBoolean() ? null :
|
||||
new Environment(Settings.builder().put("path.home", createTempDir()).build());
|
||||
Path tempDir = createTempDir();
|
||||
Path keystorePath = tempDir.resolve("testnode.jks");
|
||||
Files.copy(getDataPath("/org/elasticsearch/shield/transport/ssl/certs/simple/testnode.jks"), keystorePath);
|
||||
Settings settings = Settings.builder()
|
||||
.put("xpack.security.ssl.keystore.path", keystorePath)
|
||||
.put("xpack.security.ssl.keystore.password", "testnode")
|
||||
.put(Global.INCLUDE_JDK_CERTS_SETTING.getKey(), randomBoolean())
|
||||
.build();
|
||||
|
||||
SSLConfiguration config = new Global(settings);
|
||||
assertThat(config.keyConfig(), instanceOf(StoreKeyConfig.class));
|
||||
StoreKeyConfig keyConfig = (StoreKeyConfig) config.keyConfig();
|
||||
|
||||
CountDownLatch latch = new CountDownLatch(1);
|
||||
AtomicReference<Exception> exceptionRef = new AtomicReference<>();
|
||||
Listener listener = createRefreshListener(latch, exceptionRef);
|
||||
|
||||
ThreadPool threadPool = new ThreadPool("reload");
|
||||
try {
|
||||
ResourceWatcherService resourceWatcherService =
|
||||
new ResourceWatcherService(Settings.builder().put("resource.reload.interval.high", "1s").build(), threadPool).start();
|
||||
KeyManager[] keyManagers = keyConfig.keyManagers(env, resourceWatcherService, listener);
|
||||
X509ExtendedKeyManager keyManager = (X509ExtendedKeyManager) keyManagers[0];
|
||||
String[] aliases = keyManager.getServerAliases("RSA", null);
|
||||
assertNotNull(aliases);
|
||||
assertThat(aliases.length, is(1));
|
||||
assertThat(aliases[0], is("testnode"));
|
||||
assertThat(latch.getCount(), is(1L));
|
||||
|
||||
// truncate the keystore
|
||||
try (OutputStream out = Files.newOutputStream(keystorePath)) {
|
||||
}
|
||||
latch.await();
|
||||
assertThat(exceptionRef.get(), notNullValue());
|
||||
assertThat(exceptionRef.get(), instanceOf(ElasticsearchException.class));
|
||||
assertThat(keyManager.getServerAliases("RSA", null), equalTo(aliases));
|
||||
} finally {
|
||||
threadPool.shutdown();
|
||||
}
|
||||
}
|
||||
|
||||
public void testReloadingPEMKeyConfigException() throws Exception {
|
||||
Environment env = randomBoolean() ? null :
|
||||
new Environment(Settings.builder().put("path.home", createTempDir()).build());
|
||||
Path tempDir = createTempDir();
|
||||
Path keyPath = tempDir.resolve("testnode.pem");
|
||||
Path certPath = tempDir.resolve("testnode.crt");
|
||||
Path clientCertPath = tempDir.resolve("testclient.crt");
|
||||
Files.copy(getDataPath("/org/elasticsearch/shield/transport/ssl/certs/simple/testnode.pem"), keyPath);
|
||||
Files.copy(getDataPath("/org/elasticsearch/shield/transport/ssl/certs/simple/testnode.crt"), certPath);
|
||||
Files.copy(getDataPath("/org/elasticsearch/shield/transport/ssl/certs/simple/testclient.crt"), clientCertPath);
|
||||
Settings settings = Settings.builder()
|
||||
.put("xpack.security.ssl.key.path", keyPath)
|
||||
.put("xpack.security.ssl.key.password", "testnode")
|
||||
.put("xpack.security.ssl.cert", certPath)
|
||||
.putArray("xpack.security.ssl.ca", certPath.toString(), clientCertPath.toString())
|
||||
.put(Global.INCLUDE_JDK_CERTS_SETTING.getKey(), randomBoolean())
|
||||
.build();
|
||||
SSLConfiguration config = new Global(settings);
|
||||
assertThat(config.keyConfig(), instanceOf(PEMKeyConfig.class));
|
||||
PEMKeyConfig keyConfig = (PEMKeyConfig) config.keyConfig();
|
||||
|
||||
CountDownLatch latch = new CountDownLatch(1);
|
||||
AtomicReference<Exception> exceptionRef = new AtomicReference<>();
|
||||
Listener listener = createRefreshListener(latch, exceptionRef);
|
||||
|
||||
ThreadPool threadPool = new ThreadPool("reload pem");
|
||||
try {
|
||||
ResourceWatcherService resourceWatcherService =
|
||||
new ResourceWatcherService(Settings.builder().put("resource.reload.interval.high", "1s").build(), threadPool).start();
|
||||
KeyManager[] keyManagers = keyConfig.keyManagers(env, resourceWatcherService, listener);
|
||||
assertThat(keyManagers.length, is(1));
|
||||
assertThat(keyManagers[0], instanceOf(X509ExtendedKeyManager.class));
|
||||
X509ExtendedKeyManager keyManager = (X509ExtendedKeyManager) keyManagers[0];
|
||||
String[] aliases = keyManager.getServerAliases("RSA", null);
|
||||
assertThat(aliases, is(notNullValue()));
|
||||
assertThat(aliases.length, is(1));
|
||||
assertThat(aliases[0], is("key"));
|
||||
PrivateKey privateKey = keyManager.getPrivateKey(aliases[0]);
|
||||
assertThat(latch.getCount(), is(1L));
|
||||
|
||||
// pick a random file to truncate
|
||||
Path toTruncate = randomFrom(keyPath, certPath);
|
||||
|
||||
// truncate the file
|
||||
try (OutputStream os = Files.newOutputStream(toTruncate)) {
|
||||
}
|
||||
|
||||
latch.await();
|
||||
assertThat(exceptionRef.get(), is(instanceOf(ElasticsearchException.class)));
|
||||
assertThat(keyManager.getServerAliases("RSA", null), equalTo(aliases));
|
||||
assertThat(keyManager.getPrivateKey(aliases[0]), is(equalTo(privateKey)));
|
||||
} finally {
|
||||
threadPool.shutdown();
|
||||
}
|
||||
}
|
||||
|
||||
public void testTrustStoreReloadException() throws Exception {
|
||||
Environment env = randomBoolean() ? null :
|
||||
new Environment(Settings.builder().put("path.home", createTempDir()).build());
|
||||
Path tempDir = createTempDir();
|
||||
Path trustStorePath = tempDir.resolve("testnode.jks");
|
||||
Files.copy(getDataPath("/org/elasticsearch/shield/transport/ssl/certs/simple/testnode.jks"), trustStorePath);
|
||||
Settings settings = Settings.builder()
|
||||
.put("xpack.security.ssl.truststore.path", trustStorePath)
|
||||
.put("xpack.security.ssl.truststore.password", "testnode")
|
||||
.put(Global.INCLUDE_JDK_CERTS_SETTING.getKey(), randomBoolean())
|
||||
.build();
|
||||
|
||||
SSLConfiguration config = new Global(settings);
|
||||
assertThat(config.trustConfig(), instanceOf(StoreTrustConfig.class));
|
||||
StoreTrustConfig trustConfig = (StoreTrustConfig) config.trustConfig();
|
||||
|
||||
CountDownLatch latch = new CountDownLatch(1);
|
||||
AtomicReference<Exception> exceptionRef = new AtomicReference<>();
|
||||
Listener listener = createRefreshListener(latch, exceptionRef);
|
||||
|
||||
ThreadPool threadPool = new ThreadPool("reload");
|
||||
try {
|
||||
ResourceWatcherService resourceWatcherService =
|
||||
new ResourceWatcherService(Settings.builder().put("resource.reload.interval.high", "1s").build(), threadPool).start();
|
||||
TrustManager[] trustManagers = trustConfig.trustManagers(env, resourceWatcherService, listener);
|
||||
assertThat(trustManagers.length, is(1));
|
||||
assertThat(trustManagers[0], instanceOf(X509ExtendedTrustManager.class));
|
||||
X509ExtendedTrustManager trustManager = (X509ExtendedTrustManager) trustManagers[0];
|
||||
Certificate[] certificates = trustManager.getAcceptedIssuers();
|
||||
|
||||
// truncate the truststore
|
||||
try (OutputStream os = Files.newOutputStream(trustStorePath)) {
|
||||
}
|
||||
|
||||
latch.await();
|
||||
assertThat(exceptionRef.get(), instanceOf(ElasticsearchException.class));
|
||||
assertThat(trustManager.getAcceptedIssuers(), equalTo(certificates));
|
||||
} finally {
|
||||
threadPool.shutdown();
|
||||
}
|
||||
}
|
||||
|
||||
public void testPEMTrustReloadException() throws Exception {
|
||||
Environment env = randomBoolean() ? null :
|
||||
new Environment(Settings.builder().put("path.home", createTempDir()).build());
|
||||
Path tempDir = createTempDir();
|
||||
Path clientCertPath = tempDir.resolve("testclient.crt");
|
||||
Files.copy(getDataPath("/org/elasticsearch/shield/transport/ssl/certs/simple/testclient.crt"), clientCertPath);
|
||||
Settings settings = Settings.builder()
|
||||
.putArray("xpack.security.ssl.ca", clientCertPath.toString())
|
||||
.put(Global.INCLUDE_JDK_CERTS_SETTING.getKey(), false)
|
||||
.build();
|
||||
SSLConfiguration config = new Global(settings);
|
||||
assertThat(config.trustConfig(), instanceOf(PEMTrustConfig.class));
|
||||
PEMTrustConfig trustConfig = (PEMTrustConfig) config.trustConfig();
|
||||
CountDownLatch latch = new CountDownLatch(1);
|
||||
AtomicReference<Exception> exceptionRef = new AtomicReference<>();
|
||||
Listener listener = createRefreshListener(latch, exceptionRef);
|
||||
|
||||
ThreadPool threadPool = new ThreadPool("reload");
|
||||
try {
|
||||
ResourceWatcherService resourceWatcherService =
|
||||
new ResourceWatcherService(Settings.builder().put("resource.reload.interval.high", "1s").build(), threadPool).start();
|
||||
TrustManager[] trustManagers = trustConfig.trustManagers(env, resourceWatcherService, listener);
|
||||
assertThat(trustManagers.length, is(1));
|
||||
assertThat(trustManagers[0], instanceOf(X509ExtendedTrustManager.class));
|
||||
X509ExtendedTrustManager trustManager = (X509ExtendedTrustManager) trustManagers[0];
|
||||
Certificate[] certificates = trustManager.getAcceptedIssuers();
|
||||
assertThat(certificates.length, is(1));
|
||||
assertThat(((X509Certificate) certificates[0]).getSubjectX500Principal().getName(), containsString("Test Client"));
|
||||
assertThat(latch.getCount(), is(1L));
|
||||
|
||||
// write bad file
|
||||
Path updatedCert = tempDir.resolve("updated.crt");
|
||||
try (OutputStream os = Files.newOutputStream(updatedCert)) {
|
||||
os.write(randomByte());
|
||||
}
|
||||
atomicMoveIfPossible(updatedCert, clientCertPath);
|
||||
|
||||
latch.await();
|
||||
assertThat(exceptionRef.get(), instanceOf(ElasticsearchException.class));
|
||||
assertThat(trustManager.getAcceptedIssuers(), equalTo(certificates));
|
||||
} finally {
|
||||
threadPool.shutdown();
|
||||
}
|
||||
}
|
||||
|
||||
private Listener createRefreshListener(CountDownLatch latch, AtomicReference<Exception> exceptionRef) {
|
||||
return new Listener() {
|
||||
@Override
|
||||
public void onReload() {
|
||||
logger.info("refresh called");
|
||||
latch.countDown();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onFailure(Exception e) {
|
||||
logger.error("exception " + e);
|
||||
exceptionRef.set(e);
|
||||
latch.countDown();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
private void atomicMoveIfPossible(Path source, Path target) throws IOException {
|
||||
try {
|
||||
Files.move(source, target, StandardCopyOption.REPLACE_EXISTING, StandardCopyOption.ATOMIC_MOVE);
|
||||
} catch (AtomicMoveNotSupportedException e) {
|
||||
Files.move(source, target, StandardCopyOption.REPLACE_EXISTING);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,180 @@
|
|||
/*
|
||||
* 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.shield.ssl;
|
||||
|
||||
import org.bouncycastle.asn1.x500.X500Name;
|
||||
import org.bouncycastle.asn1.x509.Extension;
|
||||
import org.bouncycastle.asn1.x509.Time;
|
||||
import org.bouncycastle.cert.X509CertificateHolder;
|
||||
import org.bouncycastle.cert.jcajce.JcaX509CertificateConverter;
|
||||
import org.bouncycastle.cert.jcajce.JcaX509ExtensionUtils;
|
||||
import org.bouncycastle.cert.jcajce.JcaX509v3CertificateBuilder;
|
||||
import org.bouncycastle.operator.ContentSigner;
|
||||
import org.bouncycastle.operator.jcajce.JcaContentSignerBuilder;
|
||||
import org.elasticsearch.ElasticsearchException;
|
||||
import org.elasticsearch.common.network.InetAddressHelper;
|
||||
import org.elasticsearch.common.settings.Settings;
|
||||
import org.elasticsearch.common.transport.InetSocketTransportAddress;
|
||||
import org.elasticsearch.common.util.set.Sets;
|
||||
import org.elasticsearch.shield.Security;
|
||||
import org.elasticsearch.test.ShieldIntegTestCase;
|
||||
import org.elasticsearch.test.ShieldSettingsSource;
|
||||
import org.elasticsearch.transport.Transport;
|
||||
import org.joda.time.DateTime;
|
||||
import org.joda.time.DateTimeZone;
|
||||
|
||||
import javax.net.ssl.SSLHandshakeException;
|
||||
import javax.net.ssl.SSLSocket;
|
||||
import javax.net.ssl.SSLSocketFactory;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.nio.file.AtomicMoveNotSupportedException;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.StandardCopyOption;
|
||||
import java.security.KeyPair;
|
||||
import java.security.KeyStore;
|
||||
import java.security.cert.Certificate;
|
||||
import java.security.cert.X509Certificate;
|
||||
import java.util.Locale;
|
||||
import java.util.Map.Entry;
|
||||
import java.util.concurrent.CountDownLatch;
|
||||
|
||||
import static org.hamcrest.Matchers.containsString;
|
||||
|
||||
/**
|
||||
* Integration tests for SSL reloading support
|
||||
*/
|
||||
public class SSLReloadIntegTests extends ShieldIntegTestCase {
|
||||
|
||||
private Path nodeStorePath;
|
||||
|
||||
@Override
|
||||
public Settings nodeSettings(int nodeOrdinal) {
|
||||
if (nodeStorePath == null) {
|
||||
Path origPath = getDataPath("/org/elasticsearch/shield/transport/ssl/certs/simple/testnode.jks");
|
||||
Path tempDir = createTempDir();
|
||||
nodeStorePath = tempDir.resolve("testnode.jks");
|
||||
try {
|
||||
Files.copy(origPath, nodeStorePath);
|
||||
} catch (IOException e) {
|
||||
throw new ElasticsearchException("failed to copy keystore");
|
||||
}
|
||||
}
|
||||
Settings settings = super.nodeSettings(nodeOrdinal);
|
||||
Settings.Builder builder = Settings.builder();
|
||||
for (Entry<String, String> entry : settings.getAsMap().entrySet()) {
|
||||
if (entry.getKey().startsWith(Security.setting("ssl.")) == false) {
|
||||
builder.put(entry.getKey(), entry.getValue());
|
||||
}
|
||||
}
|
||||
|
||||
builder.put("resource.reload.interval.high", "1s")
|
||||
.put(ShieldSettingsSource.getSSLSettingsForStore("/org/elasticsearch/shield/transport/ssl/certs/simple/testnode.jks",
|
||||
"testnode"))
|
||||
.put("xpack.security.ssl.keystore.path", nodeStorePath);
|
||||
|
||||
if (builder.get("xpack.security.ssl.truststore.path") != null) {
|
||||
builder.put("xpack.security.ssl.truststore.path", nodeStorePath);
|
||||
}
|
||||
|
||||
return builder.build();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean sslTransportEnabled() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean autoSSLEnabled() {
|
||||
return false;
|
||||
}
|
||||
|
||||
public void testThatSSLConfigurationReloadsOnModification() throws Exception {
|
||||
KeyPair keyPair = CertUtils.generateKeyPair();
|
||||
X509Certificate certificate = getCertificate(keyPair);
|
||||
KeyStore keyStore = KeyStore.getInstance("jks");
|
||||
keyStore.load(null, null);
|
||||
keyStore.setKeyEntry("key", keyPair.getPrivate(), "changeme".toCharArray(), new Certificate[] { certificate });
|
||||
Path keystorePath = createTempDir().resolve("newcert.jks");
|
||||
try (OutputStream out = Files.newOutputStream(keystorePath)) {
|
||||
keyStore.store(out, "changeme".toCharArray());
|
||||
}
|
||||
|
||||
Settings settings = Settings.builder()
|
||||
.put("keystore.path", keystorePath)
|
||||
.put("keystore.password", "changeme")
|
||||
.put("truststore.path", nodeStorePath)
|
||||
.put("truststore.password", "testnode")
|
||||
.build();
|
||||
String node = randomFrom(internalCluster().getNodeNames());
|
||||
ServerSSLService sslService = internalCluster().getInstance(ServerSSLService.class, node);
|
||||
SSLSocketFactory sslSocketFactory = sslService.sslSocketFactory(settings);
|
||||
InetSocketTransportAddress address = (InetSocketTransportAddress) internalCluster()
|
||||
.getInstance(Transport.class, node).boundAddress().publishAddress();
|
||||
try (SSLSocket socket = (SSLSocket) sslSocketFactory.createSocket(address.getAddress(), address.getPort())) {
|
||||
socket.startHandshake();
|
||||
fail("handshake should not have been successful!");
|
||||
} catch (SSLHandshakeException expected) {
|
||||
}
|
||||
|
||||
KeyStore nodeStore = KeyStore.getInstance("jks");
|
||||
try (InputStream in = Files.newInputStream(nodeStorePath)) {
|
||||
nodeStore.load(in, "testnode".toCharArray());
|
||||
}
|
||||
nodeStore.setCertificateEntry("newcert", certificate);
|
||||
Path path = nodeStorePath.getParent().resolve("updated.jks");
|
||||
try (OutputStream out = Files.newOutputStream(path)) {
|
||||
nodeStore.store(out, "testnode".toCharArray());
|
||||
}
|
||||
try {
|
||||
Files.move(path, nodeStorePath, StandardCopyOption.REPLACE_EXISTING, StandardCopyOption.ATOMIC_MOVE);
|
||||
} catch (AtomicMoveNotSupportedException e) {
|
||||
Files.move(path, nodeStorePath, StandardCopyOption.REPLACE_EXISTING);
|
||||
}
|
||||
|
||||
CountDownLatch latch = new CountDownLatch(1);
|
||||
assertBusy(() -> {
|
||||
try (SSLSocket socket = (SSLSocket) sslSocketFactory.createSocket(address.getAddress(), address.getPort())) {
|
||||
socket.addHandshakeCompletedListener(event -> {
|
||||
try {
|
||||
assertThat(event.getPeerPrincipal().getName(), containsString("Test Node"));
|
||||
logger.info("ssl handshake completed on port [{}]", event.getSocket().getLocalPort());
|
||||
latch.countDown();
|
||||
} catch (Exception e) {
|
||||
fail("caught exception in listener " + e.getMessage());
|
||||
}
|
||||
});
|
||||
socket.startHandshake();
|
||||
|
||||
} catch (Exception e) {
|
||||
fail("caught exception " + e.getMessage());
|
||||
}
|
||||
});
|
||||
latch.await();
|
||||
}
|
||||
|
||||
private X509Certificate getCertificate(KeyPair keyPair) throws Exception {
|
||||
final DateTime notBefore = new DateTime(DateTimeZone.UTC);
|
||||
final DateTime notAfter = notBefore.plusYears(1);
|
||||
X500Name subject = new X500Name("CN=random cert");
|
||||
JcaX509v3CertificateBuilder builder =
|
||||
new JcaX509v3CertificateBuilder(subject, CertUtils.getSerial(),
|
||||
new Time(notBefore.toDate(), Locale.ROOT), new Time(notAfter.toDate(), Locale.ROOT), subject, keyPair.getPublic());
|
||||
|
||||
JcaX509ExtensionUtils extUtils = new JcaX509ExtensionUtils();
|
||||
builder.addExtension(Extension.subjectKeyIdentifier, false, extUtils.createSubjectKeyIdentifier(keyPair.getPublic()));
|
||||
builder.addExtension(Extension.authorityKeyIdentifier, false, extUtils.createAuthorityKeyIdentifier(keyPair.getPublic()));
|
||||
builder.addExtension(Extension.subjectAlternativeName, false,
|
||||
CertUtils.getSubjectAlternativeNames(true, Sets.newHashSet(InetAddressHelper.getAllAddresses())));
|
||||
|
||||
ContentSigner signer = new JcaContentSignerBuilder("SHA256withRSA").build(keyPair.getPrivate());
|
||||
X509CertificateHolder certificateHolder = builder.build(signer);
|
||||
return new JcaX509CertificateConverter().getCertificate(certificateHolder);
|
||||
}
|
||||
}
|
|
@ -1,206 +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.shield.ssl;
|
||||
|
||||
import org.elasticsearch.common.settings.Settings;
|
||||
import org.elasticsearch.common.unit.TimeValue;
|
||||
import org.elasticsearch.test.ESTestCase;
|
||||
|
||||
import javax.net.ssl.KeyManagerFactory;
|
||||
import javax.net.ssl.TrustManagerFactory;
|
||||
|
||||
import static org.hamcrest.Matchers.equalTo;
|
||||
import static org.hamcrest.Matchers.is;
|
||||
import static org.hamcrest.Matchers.not;
|
||||
import static org.hamcrest.Matchers.nullValue;
|
||||
|
||||
public class SSLSettingsTests extends ESTestCase {
|
||||
public void testThatSSLSettingsWithEmptySettingsHaveCorrectDefaults() {
|
||||
SSLSettings sslSettings = new SSLSettings(Settings.EMPTY, Settings.EMPTY);
|
||||
assertThat(sslSettings.keyStorePath, nullValue());
|
||||
assertThat(sslSettings.keyStorePassword, nullValue());
|
||||
assertThat(sslSettings.keyPassword, nullValue());
|
||||
assertThat(sslSettings.keyStoreAlgorithm, is(equalTo(KeyManagerFactory.getDefaultAlgorithm())));
|
||||
assertThat(sslSettings.sessionCacheSize, is(equalTo(SSLSettings.Globals.DEFAULT_SESSION_CACHE_SIZE)));
|
||||
assertThat(sslSettings.sessionCacheTimeout, is(equalTo(SSLSettings.Globals.DEFAULT_SESSION_CACHE_TIMEOUT)));
|
||||
assertThat(sslSettings.sslProtocol, is(equalTo(SSLSettings.Globals.DEFAULT_PROTOCOL)));
|
||||
assertThat(sslSettings.trustStoreAlgorithm, is(equalTo(TrustManagerFactory.getDefaultAlgorithm())));
|
||||
assertThat(sslSettings.trustStorePassword, nullValue());
|
||||
assertThat(sslSettings.trustStorePath, nullValue());
|
||||
}
|
||||
|
||||
public void testThatOnlyKeystoreInSettingsSetsTruststoreSettings() {
|
||||
Settings settings = Settings.builder()
|
||||
.put("xpack.security.ssl.keystore.path", "path")
|
||||
.put("xpack.security.ssl.keystore.password", "password")
|
||||
.build();
|
||||
// Pass settings in as component settings
|
||||
SSLSettings sslSettings = new SSLSettings(Settings.EMPTY, settings);
|
||||
assertThat(sslSettings.keyStorePath, is(equalTo("path")));
|
||||
assertThat(sslSettings.keyStorePassword, is(equalTo("password")));
|
||||
assertThat(sslSettings.trustStorePath, is(equalTo(sslSettings.keyStorePath)));
|
||||
assertThat(sslSettings.trustStorePassword, is(equalTo(sslSettings.keyStorePassword)));
|
||||
|
||||
// Pass settings in as profile settings
|
||||
settings = Settings.builder()
|
||||
.put("keystore.path", "path")
|
||||
.put("keystore.password", "password")
|
||||
.build();
|
||||
SSLSettings sslSettings1 = new SSLSettings(settings, Settings.EMPTY);
|
||||
assertThat(sslSettings1.keyStorePath, is(equalTo("path")));
|
||||
assertThat(sslSettings1.keyStorePassword, is(equalTo("password")));
|
||||
assertThat(sslSettings1.trustStorePath, is(equalTo(sslSettings1.keyStorePath)));
|
||||
assertThat(sslSettings1.trustStorePassword, is(equalTo(sslSettings1.keyStorePassword)));
|
||||
}
|
||||
|
||||
public void testThatKeystorePasswordIsDefaultKeyPassword() {
|
||||
Settings settings = Settings.builder()
|
||||
.put("xpack.security.ssl.keystore.password", "password")
|
||||
.build();
|
||||
// Pass settings in as component settings
|
||||
SSLSettings sslSettings = new SSLSettings(Settings.EMPTY, settings);
|
||||
assertThat(sslSettings.keyPassword, is(equalTo(sslSettings.keyStorePassword)));
|
||||
|
||||
settings = Settings.builder()
|
||||
.put("keystore.password", "password")
|
||||
.build();
|
||||
// Pass settings in as profile settings
|
||||
SSLSettings sslSettings1 = new SSLSettings(settings, Settings.EMPTY);
|
||||
assertThat(sslSettings1.keyPassword, is(equalTo(sslSettings1.keyStorePassword)));
|
||||
}
|
||||
|
||||
public void testThatKeyPasswordCanBeSet() {
|
||||
Settings settings = Settings.builder()
|
||||
.put("xpack.security.ssl.keystore.password", "password")
|
||||
.put("xpack.security.ssl.keystore.key_password", "key")
|
||||
.build();
|
||||
// Pass settings in as component settings
|
||||
SSLSettings sslSettings = new SSLSettings(Settings.EMPTY, settings);
|
||||
assertThat(sslSettings.keyStorePassword, is(equalTo("password")));
|
||||
assertThat(sslSettings.keyPassword, is(equalTo("key")));
|
||||
|
||||
// Pass settings in as profile settings
|
||||
settings = Settings.builder()
|
||||
.put("keystore.password", "password")
|
||||
.put("keystore.key_password", "key")
|
||||
.build();
|
||||
SSLSettings sslSettings1 = new SSLSettings(settings, Settings.EMPTY);
|
||||
assertThat(sslSettings1.keyStorePassword, is(equalTo("password")));
|
||||
assertThat(sslSettings1.keyPassword, is(equalTo("key")));
|
||||
}
|
||||
|
||||
public void testThatProfileSettingsOverrideServiceSettings() {
|
||||
Settings profileSettings = Settings.builder()
|
||||
.put("keystore.path", "path")
|
||||
.put("keystore.password", "password")
|
||||
.put("keystore.key_password", "key")
|
||||
.put("keystore.algorithm", "algo")
|
||||
.put("truststore.path", "trust path")
|
||||
.put("truststore.password", "password for trust")
|
||||
.put("truststore.algorithm", "trusted")
|
||||
.put("protocol", "ssl")
|
||||
.put("session.cache_size", "3")
|
||||
.put("session.cache_timeout", "10m")
|
||||
.build();
|
||||
|
||||
Settings serviceSettings = Settings.builder()
|
||||
.put("xpack.security.ssl.keystore.path", "comp path")
|
||||
.put("xpack.security.ssl.keystore.password", "comp password")
|
||||
.put("xpack.security.ssl.keystore.key_password", "comp key")
|
||||
.put("xpack.security.ssl.keystore.algorithm", "comp algo")
|
||||
.put("xpack.security.ssl.truststore.path", "comp trust path")
|
||||
.put("xpack.security.ssl.truststore.password", "comp password for trust")
|
||||
.put("xpack.security.ssl.truststore.algorithm", "comp trusted")
|
||||
.put("xpack.security.ssl.protocol", "tls")
|
||||
.put("xpack.security.ssl.session.cache_size", "7")
|
||||
.put("xpack.security.ssl.session.cache_timeout", "20m")
|
||||
.build();
|
||||
|
||||
SSLSettings sslSettings = new SSLSettings(profileSettings, serviceSettings);
|
||||
assertThat(sslSettings.keyStorePath, is(equalTo("path")));
|
||||
assertThat(sslSettings.keyStorePassword, is(equalTo("password")));
|
||||
assertThat(sslSettings.keyPassword, is(equalTo("key")));
|
||||
assertThat(sslSettings.keyStoreAlgorithm, is(equalTo("algo")));
|
||||
assertThat(sslSettings.trustStorePath, is(equalTo("trust path")));
|
||||
assertThat(sslSettings.trustStorePassword, is(equalTo("password for trust")));
|
||||
assertThat(sslSettings.trustStoreAlgorithm, is(equalTo("trusted")));
|
||||
assertThat(sslSettings.sslProtocol, is(equalTo("ssl")));
|
||||
assertThat(sslSettings.sessionCacheSize, is(equalTo(3)));
|
||||
assertThat(sslSettings.sessionCacheTimeout, is(equalTo(TimeValue.timeValueMinutes(10L))));
|
||||
}
|
||||
|
||||
public void testThatEmptySettingsAreEqual() {
|
||||
SSLSettings sslSettings = new SSLSettings(Settings.EMPTY, Settings.EMPTY);
|
||||
SSLSettings sslSettings1 = new SSLSettings(Settings.EMPTY, Settings.EMPTY);
|
||||
assertThat(sslSettings.equals(sslSettings1), is(equalTo(true)));
|
||||
assertThat(sslSettings1.equals(sslSettings), is(equalTo(true)));
|
||||
assertThat(sslSettings.equals(sslSettings), is(equalTo(true)));
|
||||
assertThat(sslSettings1.equals(sslSettings1), is(equalTo(true)));
|
||||
}
|
||||
|
||||
public void testThatSettingsWithDifferentKeystoresAreNotEqual() {
|
||||
SSLSettings sslSettings = new SSLSettings(Settings.EMPTY, Settings.builder()
|
||||
.put("xpack.security.ssl.keystore.path", "path").build());
|
||||
SSLSettings sslSettings1 = new SSLSettings(Settings.EMPTY, Settings.builder()
|
||||
.put("xpack.security.ssl.keystore.path", "path1").build());
|
||||
assertThat(sslSettings.equals(sslSettings1), is(equalTo(false)));
|
||||
assertThat(sslSettings1.equals(sslSettings), is(equalTo(false)));
|
||||
assertThat(sslSettings.equals(sslSettings), is(equalTo(true)));
|
||||
assertThat(sslSettings1.equals(sslSettings1), is(equalTo(true)));
|
||||
}
|
||||
|
||||
public void testThatSettingsWithDifferentProtocolsAreNotEqual() {
|
||||
SSLSettings sslSettings = new SSLSettings(Settings.EMPTY, Settings.builder()
|
||||
.put("xpack.security.ssl.protocol", "ssl").build());
|
||||
SSLSettings sslSettings1 = new SSLSettings(Settings.EMPTY, Settings.builder()
|
||||
.put("xpack.security.ssl.protocol", "tls").build());
|
||||
assertThat(sslSettings.equals(sslSettings1), is(equalTo(false)));
|
||||
assertThat(sslSettings1.equals(sslSettings), is(equalTo(false)));
|
||||
assertThat(sslSettings.equals(sslSettings), is(equalTo(true)));
|
||||
assertThat(sslSettings1.equals(sslSettings1), is(equalTo(true)));
|
||||
}
|
||||
|
||||
public void testThatSettingsWithDifferentTruststoresAreNotEqual() {
|
||||
SSLSettings sslSettings = new SSLSettings(Settings.EMPTY, Settings.builder()
|
||||
.put("xpack.security.ssl.truststore.path", "/trust").build());
|
||||
SSLSettings sslSettings1 = new SSLSettings(Settings.EMPTY, Settings.builder()
|
||||
.put("xpack.security.ssl.truststore.path", "/truststore").build());
|
||||
assertThat(sslSettings.equals(sslSettings1), is(equalTo(false)));
|
||||
assertThat(sslSettings1.equals(sslSettings), is(equalTo(false)));
|
||||
assertThat(sslSettings.equals(sslSettings), is(equalTo(true)));
|
||||
assertThat(sslSettings1.equals(sslSettings1), is(equalTo(true)));
|
||||
}
|
||||
|
||||
public void testThatEmptySettingsHaveSameHashCode() {
|
||||
SSLSettings sslSettings = new SSLSettings(Settings.EMPTY, Settings.EMPTY);
|
||||
SSLSettings sslSettings1 = new SSLSettings(Settings.EMPTY, Settings.EMPTY);
|
||||
assertThat(sslSettings.hashCode(), is(equalTo(sslSettings1.hashCode())));
|
||||
}
|
||||
|
||||
public void testThatSettingsWithDifferentKeystoresHaveDifferentHashCode() {
|
||||
SSLSettings sslSettings = new SSLSettings(Settings.EMPTY, Settings.builder()
|
||||
.put("xpack.security.ssl.keystore.path", "path").build());
|
||||
SSLSettings sslSettings1 = new SSLSettings(Settings.EMPTY, Settings.builder()
|
||||
.put("xpack.security.ssl.keystore.path", "path1").build());
|
||||
assertThat(sslSettings.hashCode(), is(not(equalTo(sslSettings1.hashCode()))));
|
||||
}
|
||||
|
||||
public void testThatSettingsWithDifferentProtocolsHaveDifferentHashCode() {
|
||||
SSLSettings sslSettings = new SSLSettings(Settings.EMPTY, Settings.builder()
|
||||
.put("xpack.security.ssl.protocol", "ssl").build());
|
||||
SSLSettings sslSettings1 = new SSLSettings(Settings.EMPTY, Settings.builder()
|
||||
.put("xpack.security.ssl.protocol", "tls").build());
|
||||
assertThat(sslSettings.hashCode(), is(not(equalTo(sslSettings1.hashCode()))));
|
||||
}
|
||||
|
||||
public void testThatSettingsWithDifferentTruststoresHaveDifferentHashCode() {
|
||||
SSLSettings sslSettings = new SSLSettings(Settings.EMPTY, Settings.builder()
|
||||
.put("xpack.security.ssl.truststore.path", "/trust").build());
|
||||
SSLSettings sslSettings1 = new SSLSettings(Settings.EMPTY, Settings.builder()
|
||||
.put("xpack.security.ssl.truststore.path", "/truststore").build());
|
||||
assertThat(sslSettings.hashCode(), is(not(equalTo(sslSettings1.hashCode()))));
|
||||
}
|
||||
}
|
|
@ -9,6 +9,7 @@ import org.elasticsearch.ElasticsearchException;
|
|||
import org.elasticsearch.common.settings.Settings;
|
||||
import org.elasticsearch.common.unit.TimeValue;
|
||||
import org.elasticsearch.env.Environment;
|
||||
import org.elasticsearch.shield.ssl.SSLConfiguration.Global;
|
||||
import org.elasticsearch.test.ESTestCase;
|
||||
import org.junit.Before;
|
||||
|
||||
|
@ -33,6 +34,7 @@ import static org.hamcrest.Matchers.nullValue;
|
|||
import static org.hamcrest.Matchers.sameInstance;
|
||||
|
||||
public class ServerSSLServiceTests extends ESTestCase {
|
||||
|
||||
Path testnodeStore;
|
||||
Environment env;
|
||||
|
||||
|
@ -51,7 +53,7 @@ public class ServerSSLServiceTests extends ESTestCase {
|
|||
.put("xpack.security.ssl.truststore.password", "testnode")
|
||||
.build();
|
||||
try {
|
||||
new ServerSSLService(settings, env).createSSLEngine();
|
||||
new ServerSSLService(settings, env, new Global(settings), null).createSSLEngine();
|
||||
fail("expected an exception");
|
||||
} catch (ElasticsearchException e) {
|
||||
assertThat(e.getMessage(), containsString("failed to initialize the SSLContext"));
|
||||
|
@ -65,7 +67,7 @@ public class ServerSSLServiceTests extends ESTestCase {
|
|||
.put("xpack.security.ssl.keystore.path", testnodeStore)
|
||||
.put("xpack.security.ssl.keystore.password", "testnode")
|
||||
.build();
|
||||
ServerSSLService sslService = new ServerSSLService(settings, env);
|
||||
ServerSSLService sslService = new ServerSSLService(settings, env, new Global(settings), null);
|
||||
|
||||
Settings.Builder settingsBuilder = Settings.builder()
|
||||
.put("truststore.path", testClientStore)
|
||||
|
@ -79,10 +81,11 @@ public class ServerSSLServiceTests extends ESTestCase {
|
|||
}
|
||||
|
||||
public void testThatSslContextCachingWorks() throws Exception {
|
||||
ServerSSLService sslService = new ServerSSLService(Settings.builder()
|
||||
.put("xpack.security.ssl.keystore.path", testnodeStore)
|
||||
.put("xpack.security.ssl.keystore.password", "testnode")
|
||||
.build(), env);
|
||||
Settings settings = Settings.builder()
|
||||
.put("xpack.security.ssl.keystore.path", testnodeStore)
|
||||
.put("xpack.security.ssl.keystore.password", "testnode")
|
||||
.build();
|
||||
ServerSSLService sslService = new ServerSSLService(settings, env, new Global(settings), null);
|
||||
|
||||
SSLContext sslContext = sslService.sslContext();
|
||||
SSLContext cachedSslContext = sslService.sslContext();
|
||||
|
@ -92,20 +95,22 @@ public class ServerSSLServiceTests extends ESTestCase {
|
|||
|
||||
public void testThatKeyStoreAndKeyCanHaveDifferentPasswords() throws Exception {
|
||||
Path differentPasswordsStore = getDataPath("/org/elasticsearch/shield/transport/ssl/certs/simple/testnode-different-passwords.jks");
|
||||
new ServerSSLService(Settings.builder()
|
||||
Settings settings = Settings.builder()
|
||||
.put("xpack.security.ssl.keystore.path", differentPasswordsStore)
|
||||
.put("xpack.security.ssl.keystore.password", "testnode")
|
||||
.put("xpack.security.ssl.keystore.key_password", "testnode1")
|
||||
.build(), env).createSSLEngine();
|
||||
.build();
|
||||
new ServerSSLService(settings, env, new Global(settings), null).createSSLEngine();
|
||||
}
|
||||
|
||||
public void testIncorrectKeyPasswordThrowsException() throws Exception {
|
||||
Path differentPasswordsStore = getDataPath("/org/elasticsearch/shield/transport/ssl/certs/simple/testnode-different-passwords.jks");
|
||||
try {
|
||||
new ServerSSLService(Settings.builder()
|
||||
Settings settings = Settings.builder()
|
||||
.put("xpack.security.ssl.keystore.path", differentPasswordsStore)
|
||||
.put("xpack.security.ssl.keystore.password", "testnode")
|
||||
.build(), env).createSSLEngine();
|
||||
.build();
|
||||
new ServerSSLService(settings, env, new Global(settings), null).createSSLEngine();
|
||||
fail("expected an exception");
|
||||
} catch (ElasticsearchException e) {
|
||||
assertThat(e.getMessage(), containsString("failed to initialize a KeyManagerFactory"));
|
||||
|
@ -113,65 +118,71 @@ public class ServerSSLServiceTests extends ESTestCase {
|
|||
}
|
||||
|
||||
public void testThatSSLv3IsNotEnabled() throws Exception {
|
||||
ServerSSLService sslService = new ServerSSLService(Settings.builder()
|
||||
Settings settings = Settings.builder()
|
||||
.put("xpack.security.ssl.keystore.path", testnodeStore)
|
||||
.put("xpack.security.ssl.keystore.password", "testnode")
|
||||
.build(), env);
|
||||
.build();
|
||||
ServerSSLService sslService = new ServerSSLService(settings, env, new Global(settings), null);
|
||||
SSLEngine engine = sslService.createSSLEngine();
|
||||
assertThat(Arrays.asList(engine.getEnabledProtocols()), not(hasItem("SSLv3")));
|
||||
}
|
||||
|
||||
public void testThatSSLSessionCacheHasDefaultLimits() throws Exception {
|
||||
ServerSSLService sslService = new ServerSSLService(Settings.builder()
|
||||
Settings settings = Settings.builder()
|
||||
.put("xpack.security.ssl.keystore.path", testnodeStore)
|
||||
.put("xpack.security.ssl.keystore.password", "testnode")
|
||||
.build(), env);
|
||||
.build();
|
||||
ServerSSLService sslService = new ServerSSLService(settings, env, new Global(settings), null);
|
||||
SSLSessionContext context = sslService.sslContext().getServerSessionContext();
|
||||
assertThat(context.getSessionCacheSize(), equalTo(1000));
|
||||
assertThat(context.getSessionTimeout(), equalTo((int) TimeValue.timeValueHours(24).seconds()));
|
||||
}
|
||||
|
||||
public void testThatSettingSSLSessionCacheLimitsWorks() throws Exception {
|
||||
ServerSSLService sslService = new ServerSSLService(Settings.builder()
|
||||
Settings settings = Settings.builder()
|
||||
.put("xpack.security.ssl.keystore.path", testnodeStore)
|
||||
.put("xpack.security.ssl.keystore.password", "testnode")
|
||||
.put("xpack.security.ssl.session.cache_size", "300")
|
||||
.put("xpack.security.ssl.session.cache_timeout", "600s")
|
||||
.build(), env);
|
||||
.build();
|
||||
ServerSSLService sslService = new ServerSSLService(settings, env, new Global(settings), null);
|
||||
SSLSessionContext context = sslService.sslContext().getServerSessionContext();
|
||||
assertThat(context.getSessionCacheSize(), equalTo(300));
|
||||
assertThat(context.getSessionTimeout(), equalTo(600));
|
||||
}
|
||||
|
||||
public void testThatCreateSSLEngineWithoutAnySettingsDoesNotWork() throws Exception {
|
||||
ServerSSLService sslService = new ServerSSLService(Settings.EMPTY, env);
|
||||
ServerSSLService sslService = new ServerSSLService(Settings.EMPTY, env, new Global(Settings.builder()
|
||||
.put(Global.AUTO_GENERATE_SSL_SETTING.getKey(), false).build()), null);
|
||||
try {
|
||||
sslService.createSSLEngine();
|
||||
fail("Expected IllegalArgumentException");
|
||||
} catch (IllegalArgumentException e) {
|
||||
assertThat(e.getMessage(), is("no keystore configured"));
|
||||
assertThat(e.getMessage(), is("a key must be configured to act as a server"));
|
||||
}
|
||||
}
|
||||
|
||||
public void testThatCreateSSLEngineWithOnlyTruststoreDoesNotWork() throws Exception {
|
||||
ServerSSLService sslService = new ServerSSLService(Settings.builder()
|
||||
Settings settings = Settings.builder()
|
||||
.put("xpack.security.ssl.truststore.path", testnodeStore)
|
||||
.put("xpack.security.ssl.truststore.password", "testnode")
|
||||
.build(), env);
|
||||
.build();
|
||||
ServerSSLService sslService = new ServerSSLService(settings, env, new Global(settings), null);
|
||||
try {
|
||||
sslService.createSSLEngine();
|
||||
fail("Expected IllegalArgumentException");
|
||||
} catch (IllegalArgumentException e) {
|
||||
assertThat(e.getMessage(), is("no keystore configured"));
|
||||
assertThat(e.getMessage(), is("a key must be configured to act as a server"));
|
||||
}
|
||||
}
|
||||
|
||||
public void testThatTruststorePasswordIsRequired() throws Exception {
|
||||
ServerSSLService sslService = new ServerSSLService(Settings.builder()
|
||||
Settings settings = Settings.builder()
|
||||
.put("xpack.security.ssl.keystore.path", testnodeStore)
|
||||
.put("xpack.security.ssl.keystore.password", "testnode")
|
||||
.put("xpack.security.ssl.truststore.path", testnodeStore)
|
||||
.build(), env);
|
||||
.build();
|
||||
ServerSSLService sslService = new ServerSSLService(settings, env, new Global(settings), null);
|
||||
try {
|
||||
sslService.sslContext();
|
||||
fail("Expected IllegalArgumentException");
|
||||
|
@ -181,9 +192,10 @@ public class ServerSSLServiceTests extends ESTestCase {
|
|||
}
|
||||
|
||||
public void testThatKeystorePasswordIsRequired() throws Exception {
|
||||
ServerSSLService sslService = new ServerSSLService(Settings.builder()
|
||||
Settings settings = Settings.builder()
|
||||
.put("xpack.security.ssl.keystore.path", testnodeStore)
|
||||
.build(), env);
|
||||
.build();
|
||||
ServerSSLService sslService = new ServerSSLService(settings, env, new Global(settings), null);
|
||||
try {
|
||||
sslService.sslContext();
|
||||
fail("Expected IllegalArgumentException");
|
||||
|
@ -193,14 +205,15 @@ public class ServerSSLServiceTests extends ESTestCase {
|
|||
}
|
||||
|
||||
public void testCiphersAndInvalidCiphersWork() throws Exception {
|
||||
List<String> ciphers = new ArrayList<>(SSLSettings.Globals.DEFAULT_CIPHERS);
|
||||
List<String> ciphers = new ArrayList<>(Global.DEFAULT_CIPHERS);
|
||||
ciphers.add("foo");
|
||||
ciphers.add("bar");
|
||||
ServerSSLService sslService = new ServerSSLService(Settings.builder()
|
||||
Settings settings = Settings.builder()
|
||||
.put("xpack.security.ssl.keystore.path", testnodeStore)
|
||||
.put("xpack.security.ssl.keystore.password", "testnode")
|
||||
.putArray("xpack.security.ssl.ciphers", ciphers.toArray(new String[ciphers.size()]))
|
||||
.build(), env);
|
||||
.build();
|
||||
ServerSSLService sslService = new ServerSSLService(settings, env, new Global(settings), null);
|
||||
SSLEngine engine = sslService.createSSLEngine();
|
||||
assertThat(engine, is(notNullValue()));
|
||||
String[] enabledCiphers = engine.getEnabledCipherSuites();
|
||||
|
@ -208,26 +221,28 @@ public class ServerSSLServiceTests extends ESTestCase {
|
|||
}
|
||||
|
||||
public void testInvalidCiphersOnlyThrowsException() throws Exception {
|
||||
ServerSSLService sslService = new ServerSSLService(Settings.builder()
|
||||
Settings settings = Settings.builder()
|
||||
.put("xpack.security.ssl.keystore.path", testnodeStore)
|
||||
.put("xpack.security.ssl.keystore.password", "testnode")
|
||||
.putArray("xpack.security.ssl.ciphers", new String[] { "foo", "bar" })
|
||||
.build(), env);
|
||||
.build();
|
||||
ServerSSLService sslService = new ServerSSLService(settings, env, new Global(settings), null);
|
||||
try {
|
||||
sslService.createSSLEngine();
|
||||
fail("Expected IllegalArgumentException");
|
||||
} catch (IllegalArgumentException e) {
|
||||
assertThat(e.getMessage(), is("failed loading cipher suites [[foo, bar]]"));
|
||||
assertThat(e.getMessage(), is("none of the ciphers [foo, bar] are supported by this JVM"));
|
||||
}
|
||||
}
|
||||
|
||||
public void testThatSSLSocketFactoryHasProperCiphersAndProtocols() throws Exception {
|
||||
ServerSSLService sslService = new ServerSSLService(Settings.builder()
|
||||
Settings settings = Settings.builder()
|
||||
.put("xpack.security.ssl.keystore.path", testnodeStore)
|
||||
.put("xpack.security.ssl.keystore.password", "testnode")
|
||||
.build(), env);
|
||||
SSLSocketFactory factory = sslService.sslSocketFactory();
|
||||
final String[] ciphers = sslService.supportedCiphers(factory.getSupportedCipherSuites(), sslService.ciphers());
|
||||
.build();
|
||||
ServerSSLService sslService = new ServerSSLService(settings, env, new Global(settings), null);
|
||||
SSLSocketFactory factory = sslService.sslSocketFactory(Settings.EMPTY);
|
||||
final String[] ciphers = sslService.supportedCiphers(factory.getSupportedCipherSuites(), sslService.ciphers(), false);
|
||||
assertThat(factory.getDefaultCipherSuites(), is(ciphers));
|
||||
|
||||
try (SSLSocket socket = (SSLSocket) factory.createSocket()) {
|
||||
|
|
|
@ -51,6 +51,11 @@ public class ServerTransportFilterIntegrationTests extends ShieldIntegTestCase {
|
|||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean autoSSLEnabled() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Settings nodeSettings(int nodeOrdinal) {
|
||||
Settings.Builder settingsBuilder = Settings.builder();
|
||||
|
|
|
@ -8,6 +8,7 @@ package org.elasticsearch.shield.transport.netty;
|
|||
import org.elasticsearch.common.logging.Loggers;
|
||||
import org.elasticsearch.common.settings.Settings;
|
||||
import org.elasticsearch.env.Environment;
|
||||
import org.elasticsearch.shield.ssl.SSLConfiguration.Global;
|
||||
import org.elasticsearch.shield.ssl.ServerSSLService;
|
||||
import org.elasticsearch.test.ESTestCase;
|
||||
import org.jboss.netty.bootstrap.ClientBootstrap;
|
||||
|
@ -74,7 +75,7 @@ public class HandshakeWaitingHandlerTests extends ESTestCase {
|
|||
.put("xpack.security.ssl.keystore.password", "testnode")
|
||||
.build();
|
||||
Environment env = new Environment(Settings.builder().put("path.home", createTempDir()).build());
|
||||
ServerSSLService sslService = new ServerSSLService(settings, env);
|
||||
ServerSSLService sslService = new ServerSSLService(settings, env, new Global(settings), null);
|
||||
|
||||
sslContext = sslService.sslContext();
|
||||
|
||||
|
|
|
@ -12,6 +12,7 @@ import org.elasticsearch.transport.TransportSettings;
|
|||
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.util.Map.Entry;
|
||||
|
||||
import static org.hamcrest.CoreMatchers.is;
|
||||
|
||||
|
@ -23,9 +24,22 @@ public class IPHostnameVerificationTests extends ShieldIntegTestCase {
|
|||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean autoSSLEnabled() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Settings nodeSettings(int nodeOrdinal) {
|
||||
Settings settings = super.nodeSettings(nodeOrdinal);
|
||||
Settings.Builder builder = Settings.builder();
|
||||
for (Entry<String, String> entry : settings.getAsMap().entrySet()) {
|
||||
if (entry.getKey().startsWith("xpack.security.ssl.") == false) {
|
||||
builder.put(entry.getKey(), entry.getValue());
|
||||
}
|
||||
}
|
||||
settings = builder.build();
|
||||
|
||||
// The default Unicast test behavior is to use 'localhost' with the port number. For this test we need to use IP
|
||||
String[] unicastAddresses = settings.getAsArray("discovery.zen.ping.unicast.hosts");
|
||||
for (int i = 0; i < unicastAddresses.length; i++) {
|
||||
|
@ -59,7 +73,16 @@ public class IPHostnameVerificationTests extends ShieldIntegTestCase {
|
|||
|
||||
@Override
|
||||
protected Settings transportClientSettings() {
|
||||
return Settings.builder().put(super.transportClientSettings())
|
||||
Settings clientSettings = super.transportClientSettings();
|
||||
Settings.Builder builder = Settings.builder();
|
||||
for (Entry<String, String> entry : clientSettings.getAsMap().entrySet()) {
|
||||
if (entry.getKey().startsWith("xpack.security.ssl.") == false) {
|
||||
builder.put(entry.getKey(), entry.getValue());
|
||||
}
|
||||
}
|
||||
clientSettings = builder.build();
|
||||
|
||||
return Settings.builder().put(clientSettings)
|
||||
.put(ShieldNettyTransport.HOSTNAME_VERIFICATION_SETTING.getKey(), true)
|
||||
.put(ShieldNettyTransport.HOSTNAME_VERIFICATION_RESOLVE_NAME_SETTING.getKey(), false)
|
||||
.put("xpack.security.ssl.keystore.path", keystore.toAbsolutePath())
|
||||
|
|
|
@ -10,6 +10,7 @@ import org.elasticsearch.common.settings.Settings;
|
|||
import org.elasticsearch.common.util.BigArrays;
|
||||
import org.elasticsearch.env.Environment;
|
||||
import org.elasticsearch.http.netty.NettyHttpMockUtil;
|
||||
import org.elasticsearch.shield.ssl.SSLConfiguration.Global;
|
||||
import org.elasticsearch.shield.ssl.ServerSSLService;
|
||||
import org.elasticsearch.shield.transport.SSLClientAuth;
|
||||
import org.elasticsearch.shield.transport.filter.IPFilter;
|
||||
|
@ -19,10 +20,14 @@ import org.jboss.netty.channel.ChannelPipelineFactory;
|
|||
import org.jboss.netty.handler.ssl.SslHandler;
|
||||
import org.junit.Before;
|
||||
|
||||
import javax.net.ssl.SSLEngine;
|
||||
import java.nio.file.Path;
|
||||
import java.util.Locale;
|
||||
|
||||
import static org.hamcrest.Matchers.arrayContaining;
|
||||
import static org.hamcrest.Matchers.equalTo;
|
||||
import static org.hamcrest.Matchers.is;
|
||||
import static org.hamcrest.Matchers.not;
|
||||
import static org.mockito.Mockito.mock;
|
||||
|
||||
public class ShieldNettyHttpServerTransportTests extends ESTestCase {
|
||||
|
@ -37,13 +42,13 @@ public class ShieldNettyHttpServerTransportTests extends ESTestCase {
|
|||
.put("xpack.security.ssl.keystore.password", "testnode")
|
||||
.build();
|
||||
Environment env = new Environment(Settings.builder().put("path.home", createTempDir()).build());
|
||||
serverSSLService = new ServerSSLService(settings, env);
|
||||
serverSSLService = new ServerSSLService(settings, env, new Global(settings), null);
|
||||
}
|
||||
|
||||
public void testDefaultClientAuth() throws Exception {
|
||||
Settings settings = Settings.builder().put(ShieldNettyHttpServerTransport.SSL_SETTING.getKey(), true).build();
|
||||
ShieldNettyHttpServerTransport transport = new ShieldNettyHttpServerTransport(settings, mock(NetworkService.class),
|
||||
mock(BigArrays.class), mock(IPFilter.class), serverSSLService, mock(ThreadPool.class));
|
||||
mock(BigArrays.class), mock(IPFilter.class), serverSSLService, mock(ThreadPool.class), mock(Global.class));
|
||||
NettyHttpMockUtil.setOpenChannelsHandlerToMock(transport);
|
||||
ChannelPipelineFactory factory = transport.configureServerChannelPipelineFactory();
|
||||
assertThat(factory.getPipeline().get(SslHandler.class).getEngine().getNeedClientAuth(), is(false));
|
||||
|
@ -56,7 +61,7 @@ public class ShieldNettyHttpServerTransportTests extends ESTestCase {
|
|||
.put(ShieldNettyHttpServerTransport.SSL_SETTING.getKey(), true)
|
||||
.put(ShieldNettyHttpServerTransport.CLIENT_AUTH_SETTING.getKey(), value).build();
|
||||
ShieldNettyHttpServerTransport transport = new ShieldNettyHttpServerTransport(settings, mock(NetworkService.class),
|
||||
mock(BigArrays.class), mock(IPFilter.class), serverSSLService, mock(ThreadPool.class));
|
||||
mock(BigArrays.class), mock(IPFilter.class), serverSSLService, mock(ThreadPool.class), mock(Global.class));
|
||||
NettyHttpMockUtil.setOpenChannelsHandlerToMock(transport);
|
||||
ChannelPipelineFactory factory = transport.configureServerChannelPipelineFactory();
|
||||
assertThat(factory.getPipeline().get(SslHandler.class).getEngine().getNeedClientAuth(), is(false));
|
||||
|
@ -69,7 +74,7 @@ public class ShieldNettyHttpServerTransportTests extends ESTestCase {
|
|||
.put(ShieldNettyHttpServerTransport.SSL_SETTING.getKey(), true)
|
||||
.put(ShieldNettyHttpServerTransport.CLIENT_AUTH_SETTING.getKey(), value).build();
|
||||
ShieldNettyHttpServerTransport transport = new ShieldNettyHttpServerTransport(settings, mock(NetworkService.class),
|
||||
mock(BigArrays.class), mock(IPFilter.class), serverSSLService, mock(ThreadPool.class));
|
||||
mock(BigArrays.class), mock(IPFilter.class), serverSSLService, mock(ThreadPool.class), mock(Global.class));
|
||||
NettyHttpMockUtil.setOpenChannelsHandlerToMock(transport);
|
||||
ChannelPipelineFactory factory = transport.configureServerChannelPipelineFactory();
|
||||
assertThat(factory.getPipeline().get(SslHandler.class).getEngine().getNeedClientAuth(), is(true));
|
||||
|
@ -82,10 +87,32 @@ public class ShieldNettyHttpServerTransportTests extends ESTestCase {
|
|||
.put(ShieldNettyHttpServerTransport.SSL_SETTING.getKey(), true)
|
||||
.put(ShieldNettyHttpServerTransport.CLIENT_AUTH_SETTING.getKey(), value).build();
|
||||
ShieldNettyHttpServerTransport transport = new ShieldNettyHttpServerTransport(settings, mock(NetworkService.class),
|
||||
mock(BigArrays.class), mock(IPFilter.class), serverSSLService, mock(ThreadPool.class));
|
||||
mock(BigArrays.class), mock(IPFilter.class), serverSSLService, mock(ThreadPool.class), mock(Global.class));
|
||||
NettyHttpMockUtil.setOpenChannelsHandlerToMock(transport);
|
||||
ChannelPipelineFactory factory = transport.configureServerChannelPipelineFactory();
|
||||
assertThat(factory.getPipeline().get(SslHandler.class).getEngine().getNeedClientAuth(), is(false));
|
||||
assertThat(factory.getPipeline().get(SslHandler.class).getEngine().getWantClientAuth(), is(false));
|
||||
}
|
||||
|
||||
public void testCustomSSLConfiguration() throws Exception {
|
||||
Settings settings = Settings.builder()
|
||||
.put(ShieldNettyHttpServerTransport.SSL_SETTING.getKey(), true).build();
|
||||
ShieldNettyHttpServerTransport transport = new ShieldNettyHttpServerTransport(settings, mock(NetworkService.class),
|
||||
mock(BigArrays.class), mock(IPFilter.class), serverSSLService, mock(ThreadPool.class), mock(Global.class));
|
||||
NettyHttpMockUtil.setOpenChannelsHandlerToMock(transport);
|
||||
ChannelPipelineFactory factory = transport.configureServerChannelPipelineFactory();
|
||||
SSLEngine defaultEngine = factory.getPipeline().get(SslHandler.class).getEngine();
|
||||
|
||||
settings = Settings.builder()
|
||||
.put(ShieldNettyHttpServerTransport.SSL_SETTING.getKey(), true)
|
||||
.put("xpack.security.http.ssl.supported_protocols", "TLSv1.2")
|
||||
.build();
|
||||
transport = new ShieldNettyHttpServerTransport(settings, mock(NetworkService.class),
|
||||
mock(BigArrays.class), mock(IPFilter.class), serverSSLService, mock(ThreadPool.class), mock(Global.class));
|
||||
NettyHttpMockUtil.setOpenChannelsHandlerToMock(transport);
|
||||
factory = transport.configureServerChannelPipelineFactory();
|
||||
SSLEngine customEngine = factory.getPipeline().get(SslHandler.class).getEngine();
|
||||
assertThat(customEngine.getEnabledProtocols(), arrayContaining("TLSv1.2"));
|
||||
assertThat(customEngine.getEnabledProtocols(), not(equalTo(defaultEngine.getEnabledProtocols())));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -13,6 +13,7 @@ import org.elasticsearch.common.util.BigArrays;
|
|||
import org.elasticsearch.env.Environment;
|
||||
import org.elasticsearch.indices.breaker.CircuitBreakerService;
|
||||
import org.elasticsearch.shield.ssl.ClientSSLService;
|
||||
import org.elasticsearch.shield.ssl.SSLConfiguration.Global;
|
||||
import org.elasticsearch.shield.ssl.ServerSSLService;
|
||||
import org.elasticsearch.shield.transport.SSLClientAuth;
|
||||
import org.elasticsearch.test.ESTestCase;
|
||||
|
@ -42,8 +43,9 @@ public class ShieldNettyTransportTests extends ESTestCase {
|
|||
.put("xpack.security.ssl.keystore.password", "testnode")
|
||||
.build();
|
||||
Environment env = new Environment(Settings.builder().put("path.home", createTempDir()).build());
|
||||
serverSSLService = new ServerSSLService(settings, env);
|
||||
clientSSLService = new ClientSSLService(settings);
|
||||
Global globalSSLConfiguration = new Global(settings);
|
||||
serverSSLService = new ServerSSLService(settings, env, globalSSLConfiguration, null);
|
||||
clientSSLService = new ClientSSLService(settings, globalSSLConfiguration);
|
||||
clientSSLService.setEnvironment(env);
|
||||
}
|
||||
|
||||
|
@ -51,7 +53,7 @@ public class ShieldNettyTransportTests extends ESTestCase {
|
|||
Settings settings = Settings.builder().put(ShieldNettyTransport.SSL_SETTING.getKey(), true).build();
|
||||
ShieldNettyTransport transport = new ShieldNettyTransport(settings, mock(ThreadPool.class), mock(NetworkService.class),
|
||||
mock(BigArrays.class), Version.CURRENT, null, serverSSLService, clientSSLService, mock(NamedWriteableRegistry.class),
|
||||
mock(CircuitBreakerService.class));
|
||||
mock(CircuitBreakerService.class), mock(Global.class));
|
||||
NettyMockUtil.setOpenChannelsHandlerToMock(transport);
|
||||
ChannelPipelineFactory factory = transport.configureServerChannelPipelineFactory("client",
|
||||
Settings.builder().put("xpack.security.ssl", false).build());
|
||||
|
@ -62,7 +64,7 @@ public class ShieldNettyTransportTests extends ESTestCase {
|
|||
Settings settings = Settings.builder().put(ShieldNettyTransport.SSL_SETTING.getKey(), false).build();
|
||||
ShieldNettyTransport transport = new ShieldNettyTransport(settings, mock(ThreadPool.class), mock(NetworkService.class),
|
||||
mock(BigArrays.class), Version.CURRENT, null, serverSSLService, clientSSLService, mock(NamedWriteableRegistry.class),
|
||||
mock(CircuitBreakerService.class));
|
||||
mock(CircuitBreakerService.class), mock(Global.class));
|
||||
NettyMockUtil.setOpenChannelsHandlerToMock(transport);
|
||||
ChannelPipelineFactory factory = transport.configureServerChannelPipelineFactory("client",
|
||||
Settings.builder().put("xpack.security.ssl", true).build());
|
||||
|
@ -73,7 +75,7 @@ public class ShieldNettyTransportTests extends ESTestCase {
|
|||
Settings settings = Settings.builder().put(ShieldNettyTransport.SSL_SETTING.getKey(), true).build();
|
||||
ShieldNettyTransport transport = new ShieldNettyTransport(settings, mock(ThreadPool.class), mock(NetworkService.class),
|
||||
mock(BigArrays.class), Version.CURRENT, null, serverSSLService, clientSSLService, mock(NamedWriteableRegistry.class),
|
||||
mock(CircuitBreakerService.class));
|
||||
mock(CircuitBreakerService.class), mock(Global.class));
|
||||
NettyMockUtil.setOpenChannelsHandlerToMock(transport);
|
||||
ChannelPipelineFactory factory = transport.configureServerChannelPipelineFactory("client", Settings.EMPTY);
|
||||
assertThat(factory.getPipeline().get(SslHandler.class).getEngine(), notNullValue());
|
||||
|
@ -83,7 +85,7 @@ public class ShieldNettyTransportTests extends ESTestCase {
|
|||
Settings settings = Settings.builder().put(ShieldNettyTransport.SSL_SETTING.getKey(), true).build();
|
||||
ShieldNettyTransport transport = new ShieldNettyTransport(settings, mock(ThreadPool.class), mock(NetworkService.class),
|
||||
mock(BigArrays.class), Version.CURRENT, null, serverSSLService, clientSSLService, mock(NamedWriteableRegistry.class),
|
||||
mock(CircuitBreakerService.class));
|
||||
mock(CircuitBreakerService.class), mock(Global.class));
|
||||
NettyMockUtil.setOpenChannelsHandlerToMock(transport);
|
||||
ChannelPipelineFactory factory = transport.configureServerChannelPipelineFactory("client", Settings.EMPTY);
|
||||
assertThat(factory.getPipeline().get(SslHandler.class).getEngine().getNeedClientAuth(), is(true));
|
||||
|
@ -97,7 +99,7 @@ public class ShieldNettyTransportTests extends ESTestCase {
|
|||
.put(ShieldNettyTransport.CLIENT_AUTH_SETTING.getKey(), value).build();
|
||||
ShieldNettyTransport transport = new ShieldNettyTransport(settings, mock(ThreadPool.class), mock(NetworkService.class),
|
||||
mock(BigArrays.class), Version.CURRENT, null, serverSSLService, clientSSLService, mock(NamedWriteableRegistry.class),
|
||||
mock(CircuitBreakerService.class));
|
||||
mock(CircuitBreakerService.class), mock(Global.class));
|
||||
NettyMockUtil.setOpenChannelsHandlerToMock(transport);
|
||||
ChannelPipelineFactory factory = transport.configureServerChannelPipelineFactory("client", Settings.EMPTY);
|
||||
assertThat(factory.getPipeline().get(SslHandler.class).getEngine().getNeedClientAuth(), is(true));
|
||||
|
@ -111,7 +113,7 @@ public class ShieldNettyTransportTests extends ESTestCase {
|
|||
.put(ShieldNettyTransport.CLIENT_AUTH_SETTING.getKey(), value).build();
|
||||
ShieldNettyTransport transport = new ShieldNettyTransport(settings, mock(ThreadPool.class), mock(NetworkService.class),
|
||||
mock(BigArrays.class), Version.CURRENT, null, serverSSLService, clientSSLService, mock(NamedWriteableRegistry.class),
|
||||
mock(CircuitBreakerService.class));
|
||||
mock(CircuitBreakerService.class), mock(Global.class));
|
||||
NettyMockUtil.setOpenChannelsHandlerToMock(transport);
|
||||
ChannelPipelineFactory factory = transport.configureServerChannelPipelineFactory("client", Settings.EMPTY);
|
||||
assertThat(factory.getPipeline().get(SslHandler.class).getEngine().getNeedClientAuth(), is(false));
|
||||
|
@ -125,7 +127,7 @@ public class ShieldNettyTransportTests extends ESTestCase {
|
|||
.put(ShieldNettyTransport.CLIENT_AUTH_SETTING.getKey(), value).build();
|
||||
ShieldNettyTransport transport = new ShieldNettyTransport(settings, mock(ThreadPool.class), mock(NetworkService.class),
|
||||
mock(BigArrays.class), Version.CURRENT, null, serverSSLService, clientSSLService, mock(NamedWriteableRegistry.class),
|
||||
mock(CircuitBreakerService.class));
|
||||
mock(CircuitBreakerService.class), mock(Global.class));
|
||||
NettyMockUtil.setOpenChannelsHandlerToMock(transport);
|
||||
ChannelPipelineFactory factory = transport.configureServerChannelPipelineFactory("client", Settings.EMPTY);
|
||||
assertThat(factory.getPipeline().get(SslHandler.class).getEngine().getNeedClientAuth(), is(false));
|
||||
|
@ -137,7 +139,7 @@ public class ShieldNettyTransportTests extends ESTestCase {
|
|||
Settings settings = Settings.builder().put(ShieldNettyTransport.SSL_SETTING.getKey(), true).build();
|
||||
ShieldNettyTransport transport = new ShieldNettyTransport(settings, mock(ThreadPool.class), mock(NetworkService.class),
|
||||
mock(BigArrays.class), Version.CURRENT, null, serverSSLService, clientSSLService, mock(NamedWriteableRegistry.class),
|
||||
mock(CircuitBreakerService.class));
|
||||
mock(CircuitBreakerService.class), mock(Global.class));
|
||||
NettyMockUtil.setOpenChannelsHandlerToMock(transport);
|
||||
ChannelPipelineFactory factory = transport.configureServerChannelPipelineFactory("client",
|
||||
Settings.builder().put(ShieldNettyTransport.PROFILE_CLIENT_AUTH_SETTING, value).build());
|
||||
|
@ -150,7 +152,7 @@ public class ShieldNettyTransportTests extends ESTestCase {
|
|||
Settings settings = Settings.builder().put(ShieldNettyTransport.SSL_SETTING.getKey(), true).build();
|
||||
ShieldNettyTransport transport = new ShieldNettyTransport(settings, mock(ThreadPool.class), mock(NetworkService.class),
|
||||
mock(BigArrays.class), Version.CURRENT, null, serverSSLService, clientSSLService, mock(NamedWriteableRegistry.class),
|
||||
mock(CircuitBreakerService.class));
|
||||
mock(CircuitBreakerService.class), mock(Global.class));
|
||||
NettyMockUtil.setOpenChannelsHandlerToMock(transport);
|
||||
ChannelPipelineFactory factory = transport.configureServerChannelPipelineFactory("client",
|
||||
Settings.builder().put(ShieldNettyTransport.PROFILE_CLIENT_AUTH_SETTING.getKey(), value).build());
|
||||
|
@ -163,8 +165,7 @@ public class ShieldNettyTransportTests extends ESTestCase {
|
|||
Settings settings = Settings.builder().put(ShieldNettyTransport.SSL_SETTING.getKey(), true).build();
|
||||
ShieldNettyTransport transport = new ShieldNettyTransport(settings, mock(ThreadPool.class),
|
||||
mock(NetworkService.class), mock(BigArrays.class), Version.CURRENT, null, serverSSLService, clientSSLService,
|
||||
mock(NamedWriteableRegistry.class),
|
||||
mock(CircuitBreakerService.class));
|
||||
mock(NamedWriteableRegistry.class), mock(CircuitBreakerService.class), mock(Global.class));
|
||||
NettyMockUtil.setOpenChannelsHandlerToMock(transport);
|
||||
ChannelPipelineFactory factory = transport.configureServerChannelPipelineFactory("client",
|
||||
Settings.builder().put(ShieldNettyTransport.PROFILE_CLIENT_AUTH_SETTING.getKey(), value).build());
|
||||
|
|
|
@ -11,6 +11,7 @@ import org.elasticsearch.client.transport.TransportClient;
|
|||
import org.elasticsearch.common.settings.Settings;
|
||||
import org.elasticsearch.common.transport.InetSocketTransportAddress;
|
||||
import org.elasticsearch.common.transport.TransportAddress;
|
||||
import org.elasticsearch.shield.Security;
|
||||
import org.elasticsearch.test.ShieldIntegTestCase;
|
||||
import org.elasticsearch.transport.Transport;
|
||||
import org.elasticsearch.xpack.XPackPlugin;
|
||||
|
@ -18,20 +19,33 @@ import org.elasticsearch.xpack.XPackPlugin;
|
|||
import java.net.InetSocketAddress;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.util.Map.Entry;
|
||||
|
||||
import static org.hamcrest.CoreMatchers.instanceOf;
|
||||
import static org.hamcrest.CoreMatchers.is;
|
||||
import static org.hamcrest.Matchers.containsString;
|
||||
|
||||
public class SslHostnameVerificationTests extends ShieldIntegTestCase {
|
||||
|
||||
@Override
|
||||
protected boolean sslTransportEnabled() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean autoSSLEnabled() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Settings nodeSettings(int nodeOrdinal) {
|
||||
Settings.Builder settingsBuilder = Settings.builder().put(super.nodeSettings(nodeOrdinal));
|
||||
Settings settings = super.nodeSettings(nodeOrdinal);
|
||||
Settings.Builder settingsBuilder = Settings.builder();
|
||||
for (Entry<String, String> entry : settings.getAsMap().entrySet()) {
|
||||
if (entry.getKey().startsWith("xpack.security.ssl.") == false) {
|
||||
settingsBuilder.put(entry.getKey(), entry.getValue());
|
||||
}
|
||||
}
|
||||
Path keystore;
|
||||
try {
|
||||
/*
|
||||
|
@ -45,9 +59,9 @@ public class SslHostnameVerificationTests extends ShieldIntegTestCase {
|
|||
throw new RuntimeException(e);
|
||||
}
|
||||
|
||||
return settingsBuilder.put("xpack.security.ssl.keystore.path", keystore.toAbsolutePath()) // settings for client truststore
|
||||
return settingsBuilder.put("xpack.security.ssl.keystore.path", keystore.toAbsolutePath())
|
||||
.put("xpack.security.ssl.keystore.password", "testnode-no-subjaltname")
|
||||
.put("xpack.security.ssl.truststore.path", keystore.toAbsolutePath()) // settings for client truststore
|
||||
.put("xpack.security.ssl.truststore.path", keystore.toAbsolutePath())
|
||||
.put("xpack.security.ssl.truststore.password", "testnode-no-subjaltname")
|
||||
// disable hostname verification as this test uses non-localhost addresses
|
||||
.put(ShieldNettyTransport.HOSTNAME_VERIFICATION_SETTING.getKey(), false)
|
||||
|
@ -58,11 +72,26 @@ public class SslHostnameVerificationTests extends ShieldIntegTestCase {
|
|||
protected Settings transportClientSettings() {
|
||||
Path keystore = getDataPath("/org/elasticsearch/shield/transport/ssl/certs/simple/testnode-no-subjaltname.jks");
|
||||
assert keystore != null;
|
||||
return Settings.builder().put(super.transportClientSettings())
|
||||
.put(ShieldNettyTransport.HOSTNAME_VERIFICATION_SETTING.getKey(), false)
|
||||
.put("xpack.security.ssl.truststore.path", keystore.toAbsolutePath()) // settings for client truststore
|
||||
.put("xpack.security.ssl.truststore.password", "testnode-no-subjaltname")
|
||||
.build();
|
||||
Settings settings = super.transportClientSettings();
|
||||
// remove all ssl settings
|
||||
Settings.Builder builder = Settings.builder();
|
||||
for (Entry<String, String> entry : settings.getAsMap().entrySet()) {
|
||||
String key = entry.getKey();
|
||||
if (key.startsWith(Security.setting("ssl.")) == false) {
|
||||
builder.put(key, entry.getValue());
|
||||
}
|
||||
}
|
||||
|
||||
builder.put(ShieldNettyTransport.HOSTNAME_VERIFICATION_SETTING.getKey(), false)
|
||||
.put("xpack.security.ssl.keystore.path", keystore.toAbsolutePath()) // settings for client keystore
|
||||
.put("xpack.security.ssl.keystore.password", "testnode-no-subjaltname");
|
||||
|
||||
if (randomBoolean()) {
|
||||
// randomly set the truststore, if not set the keystore should be used
|
||||
builder.put("xpack.security.ssl.truststore.path", keystore.toAbsolutePath())
|
||||
.put("xpack.security.ssl.truststore.password", "testnode-no-subjaltname");
|
||||
}
|
||||
return builder.build();
|
||||
}
|
||||
|
||||
public void testThatHostnameMismatchDeniesTransportClientConnection() throws Exception {
|
||||
|
|
|
@ -17,6 +17,7 @@ import org.elasticsearch.common.transport.TransportAddress;
|
|||
import org.elasticsearch.http.HttpServerTransport;
|
||||
import org.elasticsearch.shield.Security;
|
||||
import org.elasticsearch.shield.ssl.ClientSSLService;
|
||||
import org.elasticsearch.shield.ssl.SSLConfiguration.Global;
|
||||
import org.elasticsearch.shield.transport.netty.ShieldNettyHttpServerTransport;
|
||||
import org.elasticsearch.shield.transport.netty.ShieldNettyTransport;
|
||||
import org.elasticsearch.test.ShieldIntegTestCase;
|
||||
|
@ -53,6 +54,11 @@ public class SslClientAuthTests extends ShieldIntegTestCase {
|
|||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean autoSSLEnabled() {
|
||||
return false;
|
||||
}
|
||||
|
||||
public void testThatHttpFailsWithoutSslClientAuth() throws IOException {
|
||||
SSLConnectionSocketFactory socketFactory = new SSLConnectionSocketFactory(
|
||||
SSLContexts.createDefault(),
|
||||
|
@ -76,7 +82,7 @@ public class SslClientAuthTests extends ShieldIntegTestCase {
|
|||
Settings settings = Settings.builder()
|
||||
.put(getSSLSettingsForStore("/org/elasticsearch/shield/transport/ssl/certs/simple/testclient.jks", "testclient"))
|
||||
.build();
|
||||
ClientSSLService sslService = new ClientSSLService(settings);
|
||||
ClientSSLService sslService = new ClientSSLService(settings, new Global(settings));
|
||||
|
||||
SSLConnectionSocketFactory socketFactory = new SSLConnectionSocketFactory(
|
||||
sslService.sslContext(),
|
||||
|
|
|
@ -23,6 +23,7 @@ import org.elasticsearch.common.transport.InetSocketTransportAddress;
|
|||
import org.elasticsearch.common.transport.TransportAddress;
|
||||
import org.elasticsearch.http.HttpServerTransport;
|
||||
import org.elasticsearch.shield.ssl.ClientSSLService;
|
||||
import org.elasticsearch.shield.ssl.SSLConfiguration.Global;
|
||||
import org.elasticsearch.shield.transport.netty.ShieldNettyHttpServerTransport;
|
||||
import org.elasticsearch.test.ShieldIntegTestCase;
|
||||
import org.elasticsearch.transport.Transport;
|
||||
|
@ -55,6 +56,11 @@ public class SslIntegrationTests extends ShieldIntegTestCase {
|
|||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean autoSSLEnabled() {
|
||||
return false;
|
||||
}
|
||||
|
||||
// no SSL exception as this is the exception is returned when connecting
|
||||
public void testThatUnconfiguredCiphersAreRejected() {
|
||||
try (TransportClient transportClient = TransportClient.builder().addPlugin(XPackPlugin.class).settings(Settings.builder()
|
||||
|
@ -94,8 +100,10 @@ public class SslIntegrationTests extends ShieldIntegTestCase {
|
|||
}
|
||||
|
||||
public void testThatConnectionToHTTPWorks() throws Exception {
|
||||
Settings settings = getSSLSettingsForStore("/org/elasticsearch/shield/transport/ssl/certs/simple/testclient.jks", "testclient");
|
||||
ClientSSLService service = new ClientSSLService(settings);
|
||||
Settings settings = Settings.builder()
|
||||
.put(getSSLSettingsForStore("/org/elasticsearch/shield/transport/ssl/certs/simple/testclient.jks", "testclient"))
|
||||
.build();
|
||||
ClientSSLService service = new ClientSSLService(settings, new Global(settings));
|
||||
|
||||
CredentialsProvider provider = new BasicCredentialsProvider();
|
||||
provider.setCredentials(AuthScope.ANY, new UsernamePasswordCredentials(nodeClientUsername(),
|
||||
|
|
|
@ -20,6 +20,7 @@ import org.junit.BeforeClass;
|
|||
import java.net.InetAddress;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.util.Map.Entry;
|
||||
|
||||
import static org.elasticsearch.test.ShieldSettingsSource.DEFAULT_PASSWORD;
|
||||
import static org.elasticsearch.test.ShieldSettingsSource.DEFAULT_USER_NAME;
|
||||
|
@ -86,8 +87,24 @@ public class SslMultiPortTests extends ShieldIntegTestCase {
|
|||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean autoSSLEnabled() {
|
||||
return false;
|
||||
}
|
||||
|
||||
private TransportClient createTransportClient(Settings additionalSettings) {
|
||||
Settings settings = Settings.builder().put(transportClientSettings())
|
||||
Settings clientSettings = transportClientSettings();
|
||||
if (additionalSettings.getByPrefix("xpack.security.ssl.").isEmpty() == false) {
|
||||
Settings.Builder builder = Settings.builder();
|
||||
for (Entry<String, String> entry : clientSettings.getAsMap().entrySet()) {
|
||||
if (entry.getKey().startsWith("xpack.security.ssl.") == false) {
|
||||
builder.put(entry.getKey(), entry.getValue());
|
||||
}
|
||||
}
|
||||
clientSettings = builder.build();
|
||||
}
|
||||
|
||||
Settings settings = Settings.builder().put(clientSettings)
|
||||
.put("node.name", "programmatic_transport_client")
|
||||
.put("cluster.name", internalCluster().getClusterName())
|
||||
.put(additionalSettings)
|
||||
|
@ -224,6 +241,7 @@ public class SslMultiPortTests extends ShieldIntegTestCase {
|
|||
public void testThatTransportClientCanConnectToNoSslProfile() throws Exception {
|
||||
Settings settings = Settings.builder()
|
||||
.put(Security.USER_SETTING.getKey(), DEFAULT_USER_NAME + ":" + DEFAULT_PASSWORD)
|
||||
.put(ShieldNettyTransport.SSL_SETTING.getKey(), false)
|
||||
.put("cluster.name", internalCluster().getClusterName())
|
||||
.build();
|
||||
try (TransportClient transportClient = TransportClient.builder().settings(settings).addPlugin(XPackPlugin.class).build()) {
|
||||
|
|
|
@ -100,7 +100,8 @@ public abstract class ShieldIntegTestCase extends ESIntegTestCase {
|
|||
@BeforeClass
|
||||
public static void initDefaultSettings() {
|
||||
if (SHIELD_DEFAULT_SETTINGS == null) {
|
||||
SHIELD_DEFAULT_SETTINGS = new ShieldSettingsSource(maxNumberOfNodes(), randomBoolean(), createTempDir(), Scope.SUITE);
|
||||
SHIELD_DEFAULT_SETTINGS = new ShieldSettingsSource(maxNumberOfNodes(), randomBoolean(), randomBoolean(), createTempDir(),
|
||||
Scope.SUITE);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -123,12 +124,12 @@ public abstract class ShieldIntegTestCase extends ESIntegTestCase {
|
|||
switch (currentClusterScope) {
|
||||
case SUITE:
|
||||
if (customShieldSettingsSource == null) {
|
||||
customShieldSettingsSource = new CustomShieldSettingsSource(sslTransportEnabled(), createTempDir(),
|
||||
currentClusterScope);
|
||||
customShieldSettingsSource = new CustomShieldSettingsSource(sslTransportEnabled(), autoSSLEnabled(),
|
||||
createTempDir(), currentClusterScope);
|
||||
}
|
||||
break;
|
||||
case TEST:
|
||||
customShieldSettingsSource = new CustomShieldSettingsSource(sslTransportEnabled(), createTempDir(),
|
||||
customShieldSettingsSource = new CustomShieldSettingsSource(sslTransportEnabled(), autoSSLEnabled(), createTempDir(),
|
||||
currentClusterScope);
|
||||
break;
|
||||
}
|
||||
|
@ -265,14 +266,18 @@ public abstract class ShieldIntegTestCase extends ESIntegTestCase {
|
|||
return randomBoolean();
|
||||
}
|
||||
|
||||
protected boolean autoSSLEnabled() {
|
||||
return randomBoolean();
|
||||
}
|
||||
|
||||
protected Class<? extends XPackPlugin> xpackPluginClass() {
|
||||
return SHIELD_DEFAULT_SETTINGS.xpackPluginClass();
|
||||
}
|
||||
|
||||
private class CustomShieldSettingsSource extends ShieldSettingsSource {
|
||||
|
||||
private CustomShieldSettingsSource(boolean sslTransportEnabled, Path configDir, Scope scope) {
|
||||
super(maxNumberOfNodes(), sslTransportEnabled, configDir, scope);
|
||||
private CustomShieldSettingsSource(boolean sslTransportEnabled, boolean autoSSLEnabled, Path configDir, Scope scope) {
|
||||
super(maxNumberOfNodes(), sslTransportEnabled, autoSSLEnabled, configDir, scope);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -6,6 +6,7 @@
|
|||
package org.elasticsearch.test;
|
||||
|
||||
import org.elasticsearch.ElasticsearchException;
|
||||
import org.elasticsearch.common.Strings;
|
||||
import org.elasticsearch.common.io.PathUtils;
|
||||
import org.elasticsearch.common.settings.Settings;
|
||||
import org.elasticsearch.common.util.concurrent.ThreadContext;
|
||||
|
@ -30,9 +31,11 @@ import org.elasticsearch.xpack.XPackPlugin;
|
|||
import java.net.URISyntaxException;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
import static com.carrotsearch.randomizedtesting.RandomizedTest.randomBoolean;
|
||||
import static org.elasticsearch.test.ESTestCase.randomFrom;
|
||||
|
@ -81,6 +84,7 @@ public class ShieldSettingsSource extends ClusterDiscoveryConfiguration.UnicastZ
|
|||
private final String subfolderPrefix;
|
||||
private final byte[] systemKey;
|
||||
private final boolean sslTransportEnabled;
|
||||
private final boolean autoSSLEnabled;
|
||||
private final boolean hostnameVerificationEnabled;
|
||||
private final boolean hostnameVerificationResolveNameEnabled;
|
||||
|
||||
|
@ -92,8 +96,9 @@ public class ShieldSettingsSource extends ClusterDiscoveryConfiguration.UnicastZ
|
|||
* @param parentFolder the parent folder that will contain all of the configuration files that need to be created
|
||||
* @param scope the scope of the test that is requiring an instance of ShieldSettingsSource
|
||||
*/
|
||||
public ShieldSettingsSource(int numOfNodes, boolean sslTransportEnabled, Path parentFolder, ESIntegTestCase.Scope scope) {
|
||||
this(numOfNodes, sslTransportEnabled, generateKey(), parentFolder, scope);
|
||||
public ShieldSettingsSource(int numOfNodes, boolean sslTransportEnabled, boolean autoSSLEnabled, Path parentFolder,
|
||||
ESIntegTestCase.Scope scope) {
|
||||
this(numOfNodes, sslTransportEnabled, autoSSLEnabled, generateKey(), parentFolder, scope);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -105,13 +110,14 @@ public class ShieldSettingsSource extends ClusterDiscoveryConfiguration.UnicastZ
|
|||
* @param parentFolder the parent folder that will contain all of the configuration files that need to be created
|
||||
* @param scope the scope of the test that is requiring an instance of ShieldSettingsSource
|
||||
*/
|
||||
public ShieldSettingsSource(int numOfNodes, boolean sslTransportEnabled, byte[] systemKey, Path parentFolder,
|
||||
public ShieldSettingsSource(int numOfNodes, boolean sslTransportEnabled, boolean autoSSLEnabled, byte[] systemKey, Path parentFolder,
|
||||
ESIntegTestCase.Scope scope) {
|
||||
super(numOfNodes, DEFAULT_SETTINGS);
|
||||
this.systemKey = systemKey;
|
||||
this.parentFolder = parentFolder;
|
||||
this.subfolderPrefix = scope.name();
|
||||
this.sslTransportEnabled = sslTransportEnabled;
|
||||
this.autoSSLEnabled = autoSSLEnabled;
|
||||
this.hostnameVerificationEnabled = randomBoolean();
|
||||
this.hostnameVerificationResolveNameEnabled = randomBoolean();
|
||||
}
|
||||
|
@ -210,11 +216,37 @@ public class ShieldSettingsSource extends ClusterDiscoveryConfiguration.UnicastZ
|
|||
}
|
||||
|
||||
public Settings getNodeSSLSettings() {
|
||||
if (sslTransportEnabled && autoSSLEnabled) {
|
||||
return Settings.EMPTY;
|
||||
}
|
||||
|
||||
if (randomBoolean()) {
|
||||
return getSSLSettingsForPEMFiles("/org/elasticsearch/shield/transport/ssl/certs/simple/testnode.pem", "testnode",
|
||||
Collections.singletonList("/org/elasticsearch/shield/transport/ssl/certs/simple/testnode.crt"),
|
||||
Arrays.asList("/org/elasticsearch/shield/transport/ssl/certs/simple/testnode-client-profile.crt",
|
||||
"/org/elasticsearch/shield/transport/ssl/certs/simple/activedir.crt",
|
||||
"/org/elasticsearch/shield/transport/ssl/certs/simple/testclient.crt",
|
||||
"/org/elasticsearch/shield/transport/ssl/certs/simple/openldap.crt",
|
||||
"/org/elasticsearch/shield/transport/ssl/certs/simple/testnode.crt"),
|
||||
sslTransportEnabled, hostnameVerificationEnabled, hostnameVerificationResolveNameEnabled, false);
|
||||
}
|
||||
return getSSLSettingsForStore("/org/elasticsearch/shield/transport/ssl/certs/simple/testnode.jks", "testnode",
|
||||
sslTransportEnabled, hostnameVerificationEnabled, hostnameVerificationResolveNameEnabled, false);
|
||||
}
|
||||
|
||||
public Settings getClientSSLSettings() {
|
||||
if (sslTransportEnabled && autoSSLEnabled) {
|
||||
return Settings.EMPTY;
|
||||
}
|
||||
|
||||
if (randomBoolean()) {
|
||||
return getSSLSettingsForPEMFiles("/org/elasticsearch/shield/transport/ssl/certs/simple/testclient.pem", "testclient",
|
||||
Collections.singletonList("/org/elasticsearch/shield/transport/ssl/certs/simple/testclient.crt"),
|
||||
Arrays.asList("/org/elasticsearch/shield/transport/ssl/certs/simple/testnode.crt",
|
||||
"/org/elasticsearch/shield/transport/ssl/certs/simple/testclient.crt"),
|
||||
sslTransportEnabled, hostnameVerificationEnabled, hostnameVerificationResolveNameEnabled, true);
|
||||
}
|
||||
|
||||
return getSSLSettingsForStore("/org/elasticsearch/shield/transport/ssl/certs/simple/testclient.jks", "testclient",
|
||||
sslTransportEnabled, hostnameVerificationEnabled, hostnameVerificationResolveNameEnabled, true);
|
||||
}
|
||||
|
@ -233,16 +265,7 @@ public class ShieldSettingsSource extends ClusterDiscoveryConfiguration.UnicastZ
|
|||
private static Settings getSSLSettingsForStore(String resourcePathToStore, String password, boolean sslTransportEnabled,
|
||||
boolean hostnameVerificationEnabled, boolean hostnameVerificationResolveNameEnabled,
|
||||
boolean transportClient) {
|
||||
Path store;
|
||||
try {
|
||||
store = PathUtils.get(ShieldSettingsSource.class.getResource(resourcePathToStore).toURI());
|
||||
} catch (URISyntaxException e) {
|
||||
throw new ElasticsearchException("exception while reading the store", e);
|
||||
}
|
||||
|
||||
if (Files.notExists(store)) {
|
||||
throw new ElasticsearchException("store path doesn't exist");
|
||||
}
|
||||
Path store = resolveResourcePath(resourcePathToStore);
|
||||
|
||||
final String sslEnabledSetting =
|
||||
randomFrom(ShieldNettyTransport.SSL_SETTING.getKey(), ShieldNettyTransport.DEPRECATED_SSL_SETTING.getKey());
|
||||
|
@ -265,4 +288,52 @@ public class ShieldSettingsSource extends ClusterDiscoveryConfiguration.UnicastZ
|
|||
}
|
||||
return builder.build();
|
||||
}
|
||||
|
||||
private static Settings getSSLSettingsForPEMFiles(String keyPath, String password, List<String> certificateFiles,
|
||||
List<String> trustedCertificates, boolean sslTransportEnabled,
|
||||
boolean hostnameVerificationEnabled, boolean hostnameVerificationResolveNameEnabled,
|
||||
boolean transportClient) {
|
||||
Settings.Builder builder = Settings.builder();
|
||||
final String sslEnabledSetting =
|
||||
randomFrom(ShieldNettyTransport.SSL_SETTING.getKey(), ShieldNettyTransport.DEPRECATED_SSL_SETTING.getKey());
|
||||
builder.put(sslEnabledSetting, sslTransportEnabled);
|
||||
|
||||
if (transportClient == false) {
|
||||
builder.put(ShieldNettyHttpServerTransport.SSL_SETTING.getKey(), false);
|
||||
}
|
||||
|
||||
if (sslTransportEnabled) {
|
||||
builder.put("xpack.security.ssl.key.path", resolveResourcePath(keyPath))
|
||||
.put("xpack.security.ssl.key.password", password)
|
||||
.put("xpack.security.ssl.cert", Strings.arrayToCommaDelimitedString(resolvePathsToString(certificateFiles)))
|
||||
.put(randomFrom(ShieldNettyTransport.HOSTNAME_VERIFICATION_SETTING.getKey(),
|
||||
ShieldNettyTransport.DEPRECATED_HOSTNAME_VERIFICATION_SETTING.getKey()), hostnameVerificationEnabled)
|
||||
.put(ShieldNettyTransport.HOSTNAME_VERIFICATION_RESOLVE_NAME_SETTING.getKey(), hostnameVerificationResolveNameEnabled);
|
||||
|
||||
if (trustedCertificates.isEmpty() == false) {
|
||||
builder.put("xpack.security.ssl.ca", Strings.arrayToCommaDelimitedString(resolvePathsToString(trustedCertificates)));
|
||||
}
|
||||
}
|
||||
return builder.build();
|
||||
}
|
||||
|
||||
static String[] resolvePathsToString(List<String> resourcePaths) {
|
||||
List<String> resolvedPaths = new ArrayList<>(resourcePaths.size());
|
||||
for (String resource : resourcePaths) {
|
||||
resolvedPaths.add(resolveResourcePath(resource).toString());
|
||||
}
|
||||
return resolvedPaths.toArray(new String[resolvedPaths.size()]);
|
||||
}
|
||||
|
||||
static Path resolveResourcePath(String resourcePathToStore) {
|
||||
try {
|
||||
Path path = PathUtils.get(ShieldSettingsSource.class.getResource(resourcePathToStore).toURI());
|
||||
if (Files.notExists(path)) {
|
||||
throw new ElasticsearchException("path does not exist: " + path);
|
||||
}
|
||||
return path;
|
||||
} catch (URISyntaxException e) {
|
||||
throw new ElasticsearchException("exception while reading the store", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Binary file not shown.
Binary file not shown.
|
@ -12,4 +12,6 @@ grant {
|
|||
permission java.lang.RuntimePermission "setContextClassLoader";
|
||||
permission java.lang.RuntimePermission "getClassLoader";
|
||||
|
||||
// bouncy castle
|
||||
permission java.security.SecurityPermission "putProviderProperty.BC";
|
||||
};
|
||||
|
|
|
@ -1,440 +0,0 @@
|
|||
SOFTWARE END USER LICENSE AGREEMENT
|
||||
|
||||
READ THIS AGREEMENT CAREFULLY, WHICH CONSTITUTES A LEGALLY BINDING AGREEMENT AND GOVERNS YOUR USE OF
|
||||
ELASTICSEARCH’S PROPRIETARY SOFTWARE. BY INSTALLING AND/OR USING SUCH SOFTWARE, YOU ARE INDICATING THAT YOU AGREE TO THE
|
||||
TERMS AND CONDITIONS SET FORTH IN THIS AGREEMENT. IF YOU DO NOT AGREE WITH SUCH TERMS AND CONDITIONS, YOU MAY NOT
|
||||
INSTALL OR USE ANY OF THE SOFTWARE.
|
||||
|
||||
This END USER LICENSE AGREEMENT (this “Agreement") is entered into by and between the applicable Elasticsearch
|
||||
entity referenced in Attachment 1 hereto (“Elasticsearch”) and the person or entity (“You”) that has downloaded any of
|
||||
Elasticsearch’s proprietary software to which this Agreement is attached or in connection with which this Agreement is
|
||||
presented to You (collectively, the “Software”). This Agreement is effective upon the earlier of the date on the
|
||||
commencement of any License granted pursuant to Section 1.1. below (as applicable, the “Effective Date”).
|
||||
|
||||
1. SOFTWARE LICENSE AND RESTRICTIONS
|
||||
1.1 License Grants.
|
||||
(a) Trial Version License. Subject to the terms and conditions of this Agreement, Elasticsearch agrees to
|
||||
grant, and does hereby grant to You, for a period of thirty (30) days from the date on which You first install the
|
||||
Software (the “Trial Term”), a License to the to use the Eligible Features and Functions of the Software that are
|
||||
applicable to the Trial Version of the Software. You understand and agree that upon the expiration of a Trial Term,
|
||||
You will no longer be able to use the Software, unless you either (i) purchase a Subscription, in which case You will
|
||||
receive a License under Section 1.1(b) below to use the Eligible Features and Functions of the Software that are
|
||||
applicable to the Subscription that You purchase, (ii) undertake the Registration of Your use of the Software with
|
||||
Elasticsearch, in which case You will receive a License under Section 1.1(c) below to the Basic Version of the Software
|
||||
or (iii) obtain from Elasticsearch written consent (e-mail sufficient) to extend the Trial Term, which may be granted by
|
||||
Elasticsearch in its sole and absolute discretion.
|
||||
(b) Subscription License. Subject to the terms and conditions of this Agreement and complete payment of any and
|
||||
all applicable Subscription fees, Elasticsearch agrees to grant, and does hereby grant to You during the Subscription
|
||||
Term, and for the restricted scope of this Agreement, a License (i) to use the Eligible Features and Functions of the
|
||||
Software that are applicable to the Subscription level that You have purchased, (ii) for the number of Nodes (as defined
|
||||
in the Elasticsearch Support Services Policy) and (iii) for the specific project for which you have purchased a
|
||||
Subscription. The level of Subscription, the number of Nodes and specific project for which you have purchased such
|
||||
Subscription, are set forth on the applicable ordering document entered into by Elasticsearch and You for the purchase
|
||||
of the applicable Subscription (“Order Form”).
|
||||
(c) Basic Version License. Subject to the terms and conditions of this Agreement, and in consideration of the
|
||||
Registration of Your use the Software, Elasticsearch agrees to grant, and does hereby grant to You, for a period of one
|
||||
(1) year from the date of Registration (“Basic Term”), a License to use the Eligible Features and Functions of the
|
||||
Software that are applicable to the Basic Version of the Software.
|
||||
1.2 Reservation of Rights; Restrictions. As between Elasticsearch and You, Elasticsearch owns all right title and
|
||||
interest in and to the Software and any derivative works thereof, and except as expressly set forth in Section 1.1
|
||||
above, no other license to the Software is granted to You by implication, estoppel or otherwise. You agree not to: (i)
|
||||
reverse engineer or decompile, decrypt, disassemble or otherwise reduce any Software or any portion thereof to
|
||||
human-readable form, except and only to the extent any such restriction is prohibited by applicable law, (ii) deploy the
|
||||
Software on more Nodes (as defined in Elasticsearch’s Support Services Policy) than are permitted under the applicable
|
||||
License grant in Section 1.1 above (iii) where You have purchased a Subscription, use the Software in connection with
|
||||
any project other than the project for which you have purchased such Subscription, as identified on the applicable Order
|
||||
Form, (iv) prepare derivative works from, modify, copy or use the Software in any manner except as expressly permitted
|
||||
in this Agreement; (v) except as expressly permitted in Section 1.1 above, transfer, sell, rent, lease, distribute,
|
||||
sublicense, loan or otherwise transfer the Software in whole or in part to any third party; (vi) except as may be
|
||||
expressly permitted on an applicable Order Form, use the Software for providing time-sharing services, any
|
||||
software-as-a-service offering (“SaaS”), service bureau services or as part of an application services provider or other
|
||||
service offering; (vii) circumvent the limitations on use of the Software that are imposed or preserved by any License
|
||||
Key, (viii) alter or remove any proprietary notices in the Software; or (ix) make available to any third party any
|
||||
analysis of the results of operation of the Software, including benchmarking results, without the prior written consent
|
||||
of Elasticsearch. The Software may contain or be provided with open source libraries, components, utilities and other
|
||||
open source software (collectively, “Open Source Software”), which Open Source Software may have applicable license
|
||||
terms as identified on a website designated by Elasticsearch or otherwise provided with the Software or Documentation.
|
||||
Notwithstanding anything to the contrary herein, use of the Open Source Software shall be subject to the license terms
|
||||
and conditions applicable to such Open Source Software, to the extent required by the applicable licensor (which terms
|
||||
shall not restrict the license rights granted to You hereunder, but may contain additional rights).
|
||||
1.3 Audit Rights. You agree that, unless such right is waived in writing by Elasticsearch, Elasticsearch shall have the
|
||||
right, upon fifteen (15) days’ notice to You, to audit Your use of the Software for compliance with any quantitative
|
||||
limitations on Your use of the Software that are set forth in the applicable Order Form. You agree to provide
|
||||
Elasticsearch with the necessary access to the Software to conduct such an audit either (i) remotely, or (ii) if remote
|
||||
performance is not possible, at Your facilities, during normal business hours and no more than one (1) time in any
|
||||
twelve (12) month period. In the event any such audit reveals that You have used the Software in excess of the
|
||||
applicable quantitative limitations, You agree to solely for Your internal business operations, a limited,
|
||||
non-exclusive, non-transferable, fully paid up, right and license (without the right to grant or authorize sublicenses)
|
||||
promptly pay to Elasticsearch an amount equal to the difference between the fees actually paid and the fees that You
|
||||
should have paid to remain in compliance with such quantitative limitations. This Section 1.3 shall survive for a
|
||||
period of two (2) years from the termination or expiration of this Agreement.
|
||||
1.4 Cluster Metadata. You understand and agree that once deployed, and on a daily basis, the Software may provide
|
||||
metadata to Elasticsearch about Your cluster statistics and associates that metadata with Your IP address. However, no
|
||||
other information is provided to Elasticsearch by the Software, including any information about the data You process or
|
||||
store in connection with your use of the Software. Instructions for disabling this feature are contained in the
|
||||
Software, however leaving this feature active enables Elasticsearch to gather cluster statistics and provide an improved
|
||||
level of support to You.
|
||||
|
||||
2. TERM AND TERMINATION
|
||||
2.1 Term. Unless earlier terminated under Section 2.2 below, this Agreement shall commence on the Effective Date, and
|
||||
shall continue in force for the term of the last to expire applicable license set forth in Section 1.1 above.
|
||||
2.2 Termination. Either party may, upon written notice to the other party, terminate this Agreement for material breach
|
||||
by the other party automatically and without any other formality, if such party has failed to cure such material breach
|
||||
within thirty (30) days of receiving written notice of such material breach from the non-breaching party.
|
||||
Notwithstanding the foregoing, this Agreement shall automatically terminate in the event that You intentionally breach
|
||||
the scope of the license granted in Section 1.1 of this Agreement, provided that Elasticsearch reserves the right to
|
||||
retroactively waive such automatic termination upon written notice to You.
|
||||
2.3 Post Termination or Expiration. Upon termination or expiration of this Agreement, for any reason, You shall
|
||||
promptly cease the use of the Software and Documentation and destroy (and certify to Elasticsearch in writing the fact
|
||||
of such destruction), or return to Elasticsearch, all copies of the Software and Documentation then in Your possession
|
||||
or under Your control.
|
||||
2.4 Survival. Sections 2.3, 2.4, 3, 4 and 5 (as any such Sections may be modified by Attachment 1, if applicable) shall
|
||||
survive any termination or expiration of this Agreement.
|
||||
3. LIMITED WARRANTY AND DISCLAIMER OF WARRANTIES
|
||||
3.1 Limited Performance Warranty. Subject to You purchasing a Subscription, Elasticsearch warrants that during the
|
||||
applicable Subscription Term, the Software will perform in all material respects in accordance with the Documentation.
|
||||
In the event of a breach of the foregoing warranty, Elasticsearch’s sole obligation, and Your exclusive remedy shall be
|
||||
for Elasticsearch to (i) correct any failure(s) of the Software to perform in all material respects in accordance with
|
||||
the Documentation or (ii) if Elasticsearch is unable to provide such a correction within thirty (30) days of receipt of
|
||||
notice of the applicable non-conformity, promptly refund to Customer any pre-paid, unused fees paid by You to
|
||||
Elasticsearch for the applicable Subscription. The warranty set forth in this Section 3.1 does not apply if the
|
||||
applicable Software or any portion thereof: (a) has been altered, except by or on behalf Elasticsearch; (b) has not been
|
||||
used, installed, operated, repaired, or maintained in accordance with this Agreement and/or the Documentation; (c) has
|
||||
been subjected to abnormal physical or electrical stress, misuse, negligence, or accident; or (d) is used on equipment,
|
||||
products, or systems not meeting specifications identified by Elasticsearch in the Documentation. Additionally, the
|
||||
warranties set forth herein only apply when notice of a warranty claim is provided to Elasticsearch within the
|
||||
applicable warranty period specified herein and do not apply to any bug, defect or error caused by or attributable to
|
||||
software or hardware not supplied by Elasticsearch.
|
||||
3.2 Malicious Code. Elasticsearch represents and warrants that prior to making it available for delivery to You,
|
||||
Elasticsearch will use standard industry practices including, without limitation, the use of an updated commercial
|
||||
anti-virus program, to test the Software for Malicious Code and remove any Malicious Code it discovers. In the event of
|
||||
a breach of the foregoing warranty, Elasticsearch’s sole obligation, and Your exclusive remedy shall be for
|
||||
Elasticsearch to replace the Software with Software that does not contain any Malicious Code.
|
||||
3.3 Warranty Disclaimer. TO THE MAXIMUM EXTENT PERMITTED UNDER APPLICABLE LAW, THE SOFTWARE IS PROVIDED “AS IS” WITHOUT
|
||||
WARRANTY OF ANY KIND, AND ELASTICSEARCH AND ITS LICENSORS MAKE NO WARRANTIES WHETHER EXPRESSED, IMPLIED OR STATUTORY
|
||||
REGARDING OR RELATING TO THE SOFTWARE OR DOCUMENTATION. TO THE MAXIMUM EXTENT PERMITTED UNDER APPLICABLE LAW,
|
||||
ELASTICSEARCH AND ITS LICENSORS SPECIFICALLY DISCLAIM ALL IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
|
||||
PARTICULAR PURPOSE AND NON-INFRINGEMENT WITH RESPECT TO THE SOFTWARE AND DOCUMENTATION, AND WITH RESPECT TO THE USE OF
|
||||
THE FOREGOING. FURTHER, ELASTICSEARCH DOES NOT WARRANT RESULTS OF USE OR THAT THE SOFTWARE WILL BE ERROR FREE OR THAT
|
||||
THE USE OF THE SOFTWARE WILL BE UNINTERRUPTED.
|
||||
4. LIMITATION OF LIABILITY
|
||||
The provisions of this Section 4 apply if You have not purchased a Subscription. If you have purchased a Subscription,
|
||||
then the limitations of liability set forth in the applicable Subscription Agreement will apply in lieu of those set
|
||||
forth in this Section 4.
|
||||
4.1 Disclaimer of Certain Damages. IN NO EVENT SHALL YOU OR ELASTICSEARCH OR ITS LICENSORS BE LIABLE FOR ANY LOSS OF
|
||||
PROFITS, LOSS OF USE, BUSINESS INTERRUPTION, LOSS OF DATA, COST OF SUBSTITUTE GOODS OR SERVICES, OR FOR ANY INDIRECT,
|
||||
SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES OF ANY KIND IN CONNECTION WITH OR ARISING OUT OF THE USE OR INABILITY TO
|
||||
USE THE SOFTWARE, OR THE PERFORMANCE OF OR FAILURE TO PERFORM THIS AGREEMENT, WHETHER ALLEGED AS A BREACH OF CONTRACT OR
|
||||
TORTIOUS CONDUCT, INCLUDING NEGLIGENCE, EVEN IF THE RESPONSIBLE PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
|
||||
DAMAGES. THE LIMITATIONS OF LIABILITY SET FORTH IN THIS SECTION 4.1 SHALL NOT APPLY TO A BREACH THROUGH GROSS NEGLIGENCE
|
||||
OR INTENTIONAL MISCONDUCT BY YOU OF THE SCOPE OF THE LICENSE GRANTED IN SECTION 1.1 OR TO ANY OTHER LIABILITY THAT
|
||||
CANNOT BE EXCLUDED OR LIMITED UNDER APPLICABLE LAW.
|
||||
4.2 Damages Cap. IN NO EVENT SHALL ELASTICSEARCH’S OR ITS LICENSORS’ AGGREGATE, CUMULATIVE LIABILITY UNDER THIS
|
||||
AGREEMENT EXCEED ONE THOUSAND DOLLARS ($1,000).
|
||||
4.3 YOU AGREE THAT THE FOREGOING LIMITATIONS, EXCLUSIONS AND DISCLAIMERS ARE A REASONABLE ALLOCATION OF THE RISK BETWEEN
|
||||
THE PARTIES AND WILL APPLY TO THE MAXIMUM EXTENT PERMITTED BY APPLICABLE LAW, EVEN IF ANY REMEDY FAILS IN ITS ESSENTIAL
|
||||
PURPOSE.
|
||||
5. DEFINITIONS
|
||||
The following terms have the meanings ascribed:
|
||||
5.1 “License” means a limited, non-exclusive, non-transferable, fully paid up, right and license (without the right to
|
||||
grant or authorize sublicenses) solely for Your internal business operations to (i) install and use, in object code
|
||||
format, the applicable Eligible Features and Functions of the Software, (ii) use, and distribute internally a reasonable
|
||||
number of copies of the Documentation, provided that You must include on such copies all Marks and Notices; (iii) permit
|
||||
Contractors to use the Software and Documentation as set forth in (i) and (ii) above, provided that such use must be
|
||||
solely for Your benefit, and You shall be responsible for all acts and omissions of such Contractors in connection with
|
||||
their use of the Software that are contrary to the terms and conditions of this Agreement..
|
||||
5.2 “License Key” means an alphanumeric code that enables the Eligible Features and Functions of the Software.
|
||||
5.3 “Basic Version” means that version of the Software available for use without the purchase of a Qualifying
|
||||
Subscription, but which does require Registration.
|
||||
5.4 “Contractor” means third party contractors performing services on Your behalf.
|
||||
5.5 “Documentation” means the published end user documentation provided by Elasticsearch with the Software.
|
||||
5.6 “Eligible Features and Functions” means those features and functions of the Software that are eligible for use with
|
||||
respect to a particular version of the Software or level of the Subscription. A list of the Eligible Features and
|
||||
Functions that correspond to each version of the Software and Subscription levels may be found at
|
||||
https://www.elastic.co/subscriptions.
|
||||
5.7 “Malicious Code” means any code that is designed to harm, or otherwise disrupt in any unauthorized manner, the
|
||||
operation of a recipient’s computer programs or computer systems or destroy or damage recipient’s data. For clarity,
|
||||
Malicious Code shall not include any software bugs or errors handled through Support Services, or any standard features
|
||||
of functions of the Software and/or any License Key that are intended to enforce the temporal and other limitations on
|
||||
the scope of the use of the Software to the scope of the license purchased by You.
|
||||
5.8 “Marks and Notices” means all Elasticsearch trademarks, trade names, logos and notices present on the Documentation
|
||||
as originally provided by Elasticsearch.
|
||||
5.9 “Registration” means Elasticsearch’s then-current process under which You may register Your use of the Software with
|
||||
Elasticsearch by providing certain information to Elasticsearch regarding your use of the Software.
|
||||
5.10 “Subscription” means the right to receive Support Services and a License to the Software.
|
||||
5.11 “Subscription Term” means the period of time for which You have purchased a Subscription.
|
||||
5.12 “Trial Version” means that version of the Software available for use without the purchase of a Qualifying
|
||||
Subscription and without Registration.
|
||||
6. MISCELLANEOUS
|
||||
This Agreement, including Attachment 1 hereto, which is hereby incorporated herein by this reference, completely and
|
||||
exclusively states the entire agreement of the parties regarding the subject matter herein, and it supersedes, and its
|
||||
terms govern, all prior proposals, agreements, or other communications between the parties, oral or written, regarding
|
||||
such subject matter. For the avoidance of doubt, the parties hereby expressly acknowledge and agree that if You issue
|
||||
any purchase order or similar document in connection with its purchase of a license to the Software, You will do so only
|
||||
for Your internal, administrative purposes and not with the intent to provide any contractual terms. This Agreement may
|
||||
not be modified except by a subsequently dated, written amendment that expressly amends this Agreement and which is
|
||||
signed on behalf of Elasticsearch and You, by duly authorized representatives. If any provision hereof is held
|
||||
unenforceable, this Agreement will continue without said provision and be interpreted to reflect the original intent of
|
||||
the parties.
|
||||
|
||||
|
||||
ATTACHMENT 1
|
||||
ADDITIONAL TERMS AND CONDITIONS
|
||||
|
||||
A. The following additional terms and conditions apply to all Customers with principal offices in the United States
|
||||
of America:
|
||||
|
||||
(1) Applicable Elasticsearch Entity. The entity providing the license is Elasticsearch, Inc., a Delaware corporation.
|
||||
|
||||
(2) Government Rights. The Software product is "Commercial Computer Software," as that term is defined in 48 C.F.R.
|
||||
2.101, and as the term is used in 48 C.F.R. Part 12, and is a Commercial Item comprised of "commercial computer
|
||||
software" and "commercial computer software documentation". If acquired by or on behalf of a civilian agency, the U.S.
|
||||
Government acquires this commercial computer software and/or commercial computer software documentation subject to the
|
||||
terms of this Agreement, as specified in 48 C.F.R. 12.212 (Computer Software) and 12.211 (Technical Data) of the Federal
|
||||
Acquisition Regulation ("FAR") and its successors. If acquired by or on behalf of any agency within the Department of
|
||||
Defense ("DOD"), the U.S. Government acquires this commercial computer software and/or commercial computer software
|
||||
documentation subject to the terms of the Elasticsearch Software License Agreement as specified in 48 C.F.R. 227.7202-3
|
||||
and 48 C.F.R. 227.7202-4 of the DOD FAR Supplement ("DFARS") and its successors, and consistent with 48 C.F.R. 227.7202.
|
||||
This U.S. Government Rights clause, consistent with 48 C.F.R. 12.212 and 48 C.F.R. 227.7202 is in lieu of, and
|
||||
supersedes, any other FAR, DFARS, or other clause or provision that addresses Government rights in computer software,
|
||||
computer software documentation or technical data related to the Software under this Agreement and in any Subcontract
|
||||
under which this commercial computer software and commercial computer software documentation is acquired or licensed.
|
||||
|
||||
(3) Export Control. You acknowledge that the goods, software and technology acquired from Elasticsearch are subject
|
||||
to U.S. export control laws and regulations, including but not limited to the International Traffic In Arms Regulations
|
||||
(“ITAR”) (22 C.F.R. Parts 120-130 (2010)); the Export Administration Regulations ("EAR") (15 C.F.R. Parts 730-774
|
||||
(2010)); the U.S. antiboycott regulations in the EAR and U.S. Department of the Treasury regulations; the economic
|
||||
sanctions regulations and guidelines of the U.S. Department of the Treasury, Office of Foreign Assets Control, and the
|
||||
USA Patriot Act (Title III of Pub. L. 107-56, signed into law October 26, 2001), as amended. You are now and will
|
||||
remain in the future compliant with all such export control laws and regulations, and will not export, re-export,
|
||||
otherwise transfer any Elasticsearch goods, software or technology or disclose any Elasticsearch software or technology
|
||||
to any person contrary to such laws or regulations. You acknowledge that remote access to the Software may in certain
|
||||
circumstances be considered a re-export of Software, and accordingly, may not be granted in contravention of U.S. export
|
||||
control laws and regulations.
|
||||
(4) Governing Law, Jurisdiction and Venue.
|
||||
(a) Customers in California. If Customer is located in California (as determined by the Customer address on the
|
||||
applicable Order Form, or for a trial license under 1.1(a), the location of person who installed the Software), this
|
||||
Agreement will be governed by the laws of the State of California, without regard to its conflict of laws principles,
|
||||
and all suits hereunder will be brought solely in Federal Court for the Northern District of California, or if that
|
||||
court lacks subject matter jurisdiction, in any California State Court located in Santa Clara County.
|
||||
(b) Customers Outside of California. If Customer is located anywhere other than California (as determined by the
|
||||
Customer address on the applicable Order Form, or for a trial license under 1.1(a), the location of person who installed
|
||||
the Software), this Agreement will be governed by the laws of the State of Delaware, without regard to its conflict of
|
||||
laws principles, and all suits hereunder will be brought solely in Federal Court for the District of Delaware, or if
|
||||
that court lacks subject matter jurisdiction, in any Delaware State Court located in Wilmington, Delaware.
|
||||
(c) All Customers. This Agreement shall not be governed by the 1980 UN Convention on Contracts for the International
|
||||
Sale of Goods. The parties hereby irrevocably waive any and all claims and defenses either might otherwise have in any
|
||||
action or proceeding in any of the applicable courts set forth in (a) or (b) above, based upon any alleged lack of
|
||||
personal jurisdiction, improper venue, forum non conveniens, or any similar claim or defense.
|
||||
(d) Equitable Relief. A breach or threatened breach, by either party of Section 4 may cause irreparable harm for
|
||||
which the non-breaching party shall be entitled to seek injunctive relief without being required to post a bond.
|
||||
|
||||
B. The following additional terms and conditions apply to all Customers with principal offices in Canada:
|
||||
|
||||
(1) Applicable Elasticsearch Entity. The entity providing the license is Elasticsearch B.C. Ltd., a corporation
|
||||
incorporated under laws of the Province of British Columbia.
|
||||
|
||||
(2) Export Control. You acknowledge that the goods, software and technology acquired from Elasticsearch are subject
|
||||
to the restrictions and controls set out in Section A(3) above as well as those imposed by the Export and Import Permits
|
||||
Act (Canada) and the regulations thereunder and that you will comply with all applicable laws and regulations. Without
|
||||
limitation, You acknowledge that the Marvel Software, or any portion thereof, will not be exported: (a) to any country
|
||||
on Canada's Area Control List; (b) to any country subject to UN Security Council embargo or action; or (c) contrary to
|
||||
Canada's Export Control List Item 5505. You are now and will remain in the future compliant with all such export control
|
||||
laws and regulations, and will not export, re-export, otherwise transfer any Elasticsearch goods, software or technology
|
||||
or disclose any Elasticsearch software or technology to any person contrary to such laws or regulations. You will not
|
||||
export or re-export the Marvel Software, or any portion thereof, directly or indirectly, in violation of the Canadian
|
||||
export administration laws and regulations to any country or end user, or to any end user who you know or have reason to
|
||||
know will utilize them in the design, development or production of nuclear, chemical or biological weapons. You further
|
||||
acknowledge that the Marvel Software product may include technical data subject to such Canadian export regulations.
|
||||
Elasticsearch does not represent that the Marvel Software is appropriate or available for use in all countries.
|
||||
Elasticsearch prohibits accessing materials from countries or states where contents are illegal. You are using the
|
||||
Marvel Software on your own initiative and you are responsible for compliance with all applicable laws. You hereby agree
|
||||
to indemnify Elasticsearch and its affiliates from any claims, actions, liability or expenses (including reasonable
|
||||
lawyers' fees) resulting from Your failure to act in accordance with the acknowledgements, agreements, and
|
||||
representations in this Section B(2).
|
||||
(3) Governing Law and Dispute Resolution. This Agreement shall be governed by the Province of Ontario and the
|
||||
federal laws of Canada applicable therein without regard to conflict of laws provisions. The parties hereby irrevocably
|
||||
waive any and all claims and defenses either might otherwise have in any such action or proceeding in any of such courts
|
||||
based upon any alleged lack of personal jurisdiction, improper venue, forum non conveniens or any similar claim or
|
||||
defense. Any dispute, claim or controversy arising out of or relating to this Agreement or the existence, breach,
|
||||
termination, enforcement, interpretation or validity thereof, including the determination of the scope or applicability
|
||||
of this agreement to arbitrate, (each, a “Dispute”), which the parties are unable to resolve after good faith
|
||||
negotiations, shall be submitted first to the upper management level of the parties. The parties, through their upper
|
||||
management level representatives shall meet within thirty (30) days of the Dispute being referred to them and if the
|
||||
parties are unable to resolve such Dispute within thirty (30) days of meeting, the parties agree to seek to resolve the
|
||||
Dispute through mediation with ADR Chambers in the City of Toronto, Ontario, Canada before pursuing any other
|
||||
proceedings. The costs of the mediator shall be shared equally by the parties. If the Dispute has not been resolved
|
||||
within thirty (30) days of the notice to desire to mediate, any party may terminate the mediation and proceed to
|
||||
arbitration and the matter shall be referred to and finally resolved by arbitration at ADR Chambers pursuant to the
|
||||
general ADR Chambers Rules for Arbitration in the City of Toronto, Ontario, Canada. The arbitration shall proceed in
|
||||
accordance with the provisions of the Arbitration Act (Ontario). The arbitral panel shall consist of three (3)
|
||||
arbitrators, selected as follows: each party shall appoint one (1) arbitrator; and those two (2) arbitrators shall
|
||||
discuss and select a chairman. If the two (2) party-appointed arbitrators are unable to agree on the chairman, the
|
||||
chairman shall be selected in accordance with the applicable rules of the arbitration body. Each arbitrator shall be
|
||||
independent of each of the parties. The arbitrators shall have the authority to grant specific performance and to
|
||||
allocate between the parties the costs of arbitration (including service fees, arbitrator fees and all other fees
|
||||
related to the arbitration) in such equitable manner as the arbitrators may determine. The prevailing party in any
|
||||
arbitration shall be entitled to receive reimbursement of its reasonable expenses incurred in connection therewith.
|
||||
Judgment upon the award so rendered may be entered in a court having jurisdiction or application may be made to such
|
||||
court for judicial acceptance of any award and an order of enforcement, as the case may be. Notwithstanding the
|
||||
foregoing, Elasticsearch shall have the right to institute an action in a court of proper jurisdiction for preliminary
|
||||
injunctive relief pending a final decision by the arbitrator, provided that a permanent injunction and damages shall
|
||||
only be awarded by the arbitrator. The language to be used in the arbitral proceedings shall be English.
|
||||
(4) Language. Any translation of this Agreement is done for local requirements and in the event of a dispute
|
||||
between the English and any non-English version, the English version of this Agreement shall govern. At the request of
|
||||
the parties, the official language of this Agreement and all communications and documents relating hereto is the English
|
||||
language, and the English-language version shall govern all interpretation of the Agreement. À la demande des parties,
|
||||
la langue officielle de la présente convention ainsi que toutes communications et tous documents s'y rapportant est la
|
||||
langue anglaise, et la version anglaise est celle qui régit toute interprétation de la présente convention.
|
||||
(5) Warranty Disclaimer. For Customers with principal offices in the Province of Québec, the following new sentence
|
||||
is to be added to the end of Section 3.3: “SOME JURISDICTIONS DO NOT ALLOW LIMITATIONS OR EXCLUSIONS OF CERTAIN TYPES OF
|
||||
DAMAGES AND/OR WARRANTIES AND CONDITIONS. THE LIMITATIONS, EXCLUSIONS AND DISCLAIMERS SET FORTH IN THIS AGREEMENT SHALL
|
||||
NOT APPLY IF AND ONLY IF AND TO THE EXTENT THAT THE LAWS OF A COMPETENT JURISDICTION REQUIRE LIABILITIES BEYOND AND
|
||||
DESPITE THESE LIMITATIONS, EXCLUSIONS AND DISCLAIMERS.”
|
||||
(6) Limitation of Liability. For Customers with principal offices in the Province of Québec, the following new
|
||||
sentence is to be added to the end of Section 4.1: “SOME JURISDICTIONS DO NOT ALLOW LIMITATIONS OR EXCLUSIONS OF CERTAIN
|
||||
TYPES OF DAMAGES AND/OR WARRANTIES AND CONDITIONS. THE LIMITATIONS, EXCLUSIONS AND DISCLAIMERS SET FORTH IN THIS
|
||||
AGREEMENT SHALL NOT APPLY IF AND ONLY IF AND TO THE EXTENT THAT THE LAWS OF A COMPETENT JURISDICTION REQUIRE LIABILITIES
|
||||
BEYOND AND DESPITE THESE LIMITATIONS, EXCLUSIONS AND DISCLAIMERS.”
|
||||
|
||||
C. The following additional terms and conditions apply to all Customers with principal offices outside of the United
|
||||
States of America and Canada:
|
||||
|
||||
(1) Applicable Elasticsearch Entity. The entity providing the license in Germany is Elasticsearch Gmbh; in France is
|
||||
Elasticsearch SARL, in the United Kingdom is Elasticsearch Ltd, in Australia is Elasticsearch Pty Ltd., in Japan is
|
||||
Elasticsearch KK, in Sweden is Elasticsearch AB, in Norway is Elasticsearch AS and in all other countries is
|
||||
Elasticsearch BV.
|
||||
|
||||
(2) Choice of Law. This Agreement shall be governed by and construed in accordance with the laws of the State of New
|
||||
York, without reference to or application of choice of law rules or principles. Notwithstanding any choice of law
|
||||
provision or otherwise, the Uniform Computer Information Transactions Act (UCITA) and the United Nations Convention on
|
||||
the International Sale of Goods shall not apply.
|
||||
|
||||
(3) Arbitration. Any dispute, claim or controversy arising out of or relating to this Agreement or the existence,
|
||||
breach, termination, enforcement, interpretation or validity thereof, including the determination of the scope or
|
||||
applicability of this agreement to arbitrate, (each, a “Dispute”) shall be referred to and finally resolved by
|
||||
arbitration under the rules and at the location identified below. The arbitral panel shall consist of three (3)
|
||||
arbitrators, selected as follows: each party shall appoint one (1) arbitrator; and those two (2) arbitrators shall
|
||||
discuss and select a chairman. If the two party-appointed arbitrators are unable to agree on the chairman, the chairman
|
||||
shall be selected in accordance with the applicable rules of the arbitration body. Each arbitrator shall be independent
|
||||
of each of the parties. The arbitrators shall have the authority to grant specific performance and to allocate between
|
||||
the parties the costs of arbitration (including service fees, arbitrator fees and all other fees related to the
|
||||
arbitration) in such equitable manner as the arbitrators may determine. The prevailing party in any arbitration shall
|
||||
be entitled to receive reimbursement of its reasonable expenses incurred in connection therewith. Judgment upon the
|
||||
award so rendered may be entered in a court having jurisdiction or application may be made to such court for judicial
|
||||
acceptance of any award and an order of enforcement, as the case may be. Notwithstanding the foregoing, Elasticsearch
|
||||
shall have the right to institute an action in a court of proper jurisdiction for preliminary injunctive relief pending
|
||||
a final decision by the arbitrator, provided that a permanent injunction and damages shall only be awarded by the
|
||||
arbitrator. The language to be used in the arbitral proceedings shall be English.
|
||||
|
||||
In addition, the following terms only apply to Customers with principal offices within Europe, the Middle East or Africa
|
||||
(EMEA):
|
||||
|
||||
Arbitration Rules and Location. Any Dispute shall be referred to and finally resolved by arbitration under the London
|
||||
Court of International Arbitration (“LCIA”) Rules (which Rules are deemed to be incorporated by reference into this
|
||||
clause) on the basis that the governing law is the law of the State of New York, USA. The seat, or legal place, of
|
||||
arbitration shall be London, England.
|
||||
|
||||
(b) In addition, the following terms only apply to Customers with principal offices within Asia Pacific, Australia &
|
||||
New Zealand:
|
||||
|
||||
Arbitration Rules and Location. Any Dispute shall be referred to and finally resolved by arbitration under the Rules of
|
||||
Conciliation and Arbitration of the International Chamber of Commerce (“ICC”) in force on the date when the notice of
|
||||
arbitration is submitted in accordance with such Rules (which Rules are deemed to be incorporated by reference into this
|
||||
clause) on the basis that the governing law is the law of the State of New York, USA. The seat, or legal place, of
|
||||
arbitration shall be Singapore.
|
||||
|
||||
(c) In addition, the following terms only apply to Customers with principal offices within the Americas (excluding
|
||||
North America):
|
||||
|
||||
Arbitration Rules and Location. Any Dispute shall be referred to and finally resolved by arbitration under
|
||||
International Dispute Resolution Procedures of the American Arbitration Association (“AAA”) in force on the date when
|
||||
the notice of arbitration is submitted in accordance with such Procedures (which Procedures are deemed to be
|
||||
incorporated by reference into this clause) on the basis that the governing law is the law of the State of New York,
|
||||
USA. The seat, or legal place, of arbitration shall be New York, New York, USA.
|
||||
|
||||
(4) In addition, for Customers with principal offices within the UK, the following new sentence is added to the end
|
||||
of Section 4.1:
|
||||
|
||||
Nothing in this Agreement shall have effect so as to limit or exclude a party’s liability for death or personal injury
|
||||
caused by negligence or for fraud including fraudulent misrepresentation and this Section 4.1 shall take effect subject
|
||||
to this provision.
|
||||
|
||||
(5) In addition, for Customers with principal offices within France, Sections 1.2, 3 and 4.1 of the Agreement are
|
||||
deleted and replaced with the following new Sections 1.2, 3.3 and 4.1:
|
||||
1.2 Reservation of Rights; Restrictions. Elasticsearch owns all right title and interest in and to the Software and
|
||||
any derivative works thereof, and except as expressly set forth in Section 1.1 above, no other license to the Software
|
||||
is granted to You by implication, or otherwise. You agree not to prepare derivative works from, modify, copy or use the
|
||||
Software in any manner except as expressly permitted in this Agreement; provided that You may copy the Software for
|
||||
archival purposes, only where such software is provided on a non-durable medium; and You may decompile the Software,
|
||||
where necessary for interoperability purposes and where necessary for the correction of errors making the software unfit
|
||||
for its intended purpose, if such right is not reserved by Elasticsearch as editor of the Software. Pursuant to article
|
||||
L122-6-1 of the French intellectual property code, Elasticsearch reserves the right to correct any bugs as necessary for
|
||||
the Software to serve its intended purpose. You agree not to: (i) transfer, sell, rent, lease, distribute, sublicense,
|
||||
loan or otherwise transfer the Software in whole or in part to any third party; (ii) use the Software for providing
|
||||
time-sharing services, any software-as-a-service offering (“SaaS”), service bureau services or as part of an application
|
||||
services provider or other service offering; (iii) alter or remove any proprietary notices in the Software; or (iv) make
|
||||
available to any third party any analysis of the results of operation of the Software, including benchmarking results,
|
||||
without the prior written consent of Elasticsearch.
|
||||
3.3 Warranty Disclaimer. TO THE MAXIMUM EXTENT PERMITTED UNDER APPLICABLE LAW, THE SOFTWARE IS PROVIDED “AS IS”
|
||||
WITHOUT WARRANTY OF ANY KIND, AND ELASTICSEARCH AND ITS LICENSORS MAKE NO WARRANTIES WHETHER EXPRESSED, IMPLIED OR
|
||||
STATUTORY REGARDING OR RELATING TO THE SOFTWARE OR DOCUMENTATION. TO THE MAXIMUM EXTENT PERMITTED UNDER APPLICABLE LAW,
|
||||
ELASTICSEARCH AND ITS LICENSORS SPECIFICALLY DISCLAIM ALL IMPLIED WARRANTIES OF FITNESS FOR A PARTICULAR PURPOSE WITH
|
||||
RESPECT TO THE SOFTWARE AND DOCUMENTATION, AND WITH RESPECT TO THE USE OF THE FOREGOING. FURTHER, ELASTICSEARCH DOES
|
||||
NOT WARRANT RESULTS OF USE OR THAT THE SOFTWARE WILL BE ERROR FREE OR THAT THE USE OF THE SOFTWARE WILL BE
|
||||
UNINTERRUPTED.
|
||||
4.1 Disclaimer of Certain Damages. IN NO EVENT SHALL YOU OR ELASTICSEARCH OR ITS LICENSORS BE LIABLE FOR ANY LOSS OF
|
||||
PROFITS, LOSS OF USE, BUSINESS INTERRUPTION, LOSS OF DATA, COST OF SUBSTITUTE GOODS OR SERVICES, OR FOR ANY INDIRECT OR
|
||||
UNFORESEEABLE DAMAGES OF ANY KIND IN CONNECTION WITH OR ARISING OUT OF THE USE OR INABILITY TO USE THE SOFTWARE, OR THE
|
||||
PERFORMANCE OF OR FAILURE TO PERFORM THIS AGREEMENT, WHETHER ALLEGED AS A BREACH OF CONTRACT OR TORTIOUS CONDUCT,
|
||||
INCLUDING NEGLIGENCE. THE LIMITATIONS OF LIABILITY SET FORTH IN THIS SECTION 4.1 SHALL NOT APPLY TO A BREACH, THROUGH
|
||||
GROSS NEGLIGENCE OR INTENTIONAL MISCONDUCT BY YOU, OF THE SCOPE OF THE LICENSE GRANTED IN SECTION 1.1, OR IN CASE OF
|
||||
DEATH OR PERSONAL INJURY.
|
||||
(6) In addition, for Customers with principal offices within Australia, Sections 4.1, 4.2 and 4.3 of the Agreement
|
||||
are deleted and replaced with the following new Sections 4.1, 4.2 and 4.3:
|
||||
4.1 Disclaimer of Certain Damages. Subject to clause 4.3, a party is not liable for Consequential Loss however
|
||||
caused (including by the negligence of that party) suffered or incurred by the other party in connection with this
|
||||
agreement. “Consequential Loss” means loss of revenues, loss of reputation, indirect loss, loss of profits,
|
||||
consequential loss, loss of actual or anticipated savings, indirect loss, lost opportunities, including opportunities to
|
||||
enter into arrangements with third parties, loss or damage in connection with claims against by third parties, or loss
|
||||
or corruption or data.
|
||||
4.2 Damages Cap. SUBJECT TO CLAUSES 4.1 AND 4.3, ANY LIABILITY OF ELASTICSEARCH FOR ANY LOSS OR DAMAGE, HOWEVER
|
||||
CAUSED (INCLUDING BY THE NEGLIGENCE OF ELASTICSEARCH), SUFFERED BY YOU IN CONNECTION WITH THIS AGREEMENT IS LIMITED TO
|
||||
THE AMOUNT YOU PAID, IN THE TWELVE (12) MONTHS IMMEDIATELY PRIOR TO THE EVENT GIVING RISE TO LIABILITY, UNDER THE
|
||||
ELASTICSEARCH SUPPORT SERVICES AGREEMENT IN CONNECTION WITH WHICH YOU OBTAINED THE LICENSE TO USE THE SOFTWARE. THE
|
||||
LIMITATION SET OUT IN THIS SECTION 4.2 IS AN AGGREGATE LIMIT FOR ALL CLAIMS, WHENEVER MADE.
|
||||
4.3 Limitation and Disclaimer Exceptions. If the Competition and Consumer Act 2010 (Cth) or any other legislation or
|
||||
any other legislation states that there is a guarantee in relation to any good or service supplied by Elasticsearch in
|
||||
connection with this agreement, and Elasticsearch’s liability for failing to comply with that guarantee cannot be
|
||||
excluded but may be limited, Sections 4.1 and 4.2 do not apply to that liability and instead Elasticsearch’s liability
|
||||
for such failure is limited (at Elasticsearch’s election) to, in the case of a supply of goods, the Elasticsearch
|
||||
replacing the goods or supplying equivalent goods or repairing the goods, or in the case of a supply of services,
|
||||
Elasticsearch supplying the services again or paying the cost of having the services supplied again.
|
||||
(7) In addition, for Customers with principal offices within Japan, Sections 1.2, 3 and 4.1 of the Agreement are
|
||||
deleted and replaced with the following new Sections 1.2, 3.3 and 4.1:
|
||||
1.2 Reservation of Rights; Restrictions. As between Elasticsearch and You, Elasticsearch owns all right title and
|
||||
interest in and to the Software and any derivative works thereof, and except as expressly set forth in Section 1.1
|
||||
above, no other license to the Software is granted to You by implication or otherwise. You agree not to: (i) prepare
|
||||
derivative works from, modify, copy or use the Software in any manner except as expressly permitted in this Agreement or
|
||||
applicable law; (ii) transfer, sell, rent, lease, distribute, sublicense, loan or otherwise transfer the Software in
|
||||
whole or in part to any third party; (iii) use the Software for providing time-sharing services, any
|
||||
software-as-a-service offering (“SaaS”), service bureau services or as part of an application services provider or other
|
||||
service offering; (iv) alter or remove any proprietary notices in the Software; or (v) make available to any third party
|
||||
any analysis of the results of operation of the Software, including benchmarking results, without the prior written
|
||||
consent of Elasticsearch.
|
||||
3.3 Warranty Disclaimer. TO THE MAXIMUM EXTENT PERMITTED UNDER APPLICABLE LAW, THE SOFTWARE IS PROVIDED “AS IS”
|
||||
WITHOUT WARRANTY OF ANY KIND, AND ELASTICSEARCH AND ITS LICENSORS MAKE NO WARRANTIES WHETHER EXPRESSED, IMPLIED OR
|
||||
STATUTORY REGARDING OR RELATING TO THE SOFTWARE OR DOCUMENTATION. TO THE MAXIMUM EXTENT PERMITTED UNDER APPLICABLE LAW,
|
||||
ELASTICSEARCH AND ITS LICENSORS SPECIFICALLY DISCLAIM ALL IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
|
||||
PARTICULAR PURPOSE AND NON-INFRINGEMENT WITH RESPECT TO THE SOFTWARE AND DOCUMENTATION, AND WITH RESPECT TO THE USE OF
|
||||
THE FOREGOING. FURTHER, ELASTICSEARCH DOES NOT WARRANT RESULTS OF USE OR THAT THE SOFTWARE WILL BE ERROR FREE OR THAT
|
||||
THE USE OF THE SOFTWARE WILL BE UNINTERRUPTED.
|
||||
4.1 Disclaimer of Certain Damages. IN NO EVENT SHALL YOU OR ELASTICSEARCH OR ITS LICENSORS BE LIABLE FOR ANY LOSS OF
|
||||
PROFITS, LOSS OF USE, BUSINESS INTERRUPTION, LOSS OF DATA, COST OF SUBSTITUTE GOODS OR SERVICES, OR FOR ANY
|
||||
SPECIALINDIRECT, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES OF ANY KIND IN CONNECTION WITH OR ARISING OUT OF THE USE
|
||||
OR INABILITY TO USE THE SOFTWARE, OR THE PERFORMANCE OF OR FAILURE TO PERFORM THIS AGREEMENT, WHETHER ALLEGED AS A
|
||||
BREACH OF CONTRACT OR TORTIOUS CONDUCT, INCLUDING NEGLIGENCE, EVEN IF THE RESPONSIBLE PARTY HAS BEEN ADVISED OF THE
|
||||
POSSIBILITY OF SUCH DAMAGES. THE LIMITATIONS OF LIABILITY SET FORTH IN THIS SECTION 4.1 SHALL NOT APPLY TO A BREACH
|
||||
THROUGH GROSS NEGLIGENCE OR INTENTIONAL MISCONDUCT BY YOU OF THE SCOPE OF THE LICENSE GRANTED IN SECTION 1.1 OR TO ANY
|
||||
OTHER LIABILITY THAT CANNOT BE EXCLUDED OR LIMITED UNDER APPLICABLE LAW.
|
||||
|
|
@ -1,52 +0,0 @@
|
|||
Elasticsearch Watcher
|
||||
Copyright 2009-2015 Elastic
|
||||
|
||||
---
|
||||
This product includes software developed by The Apache Software
|
||||
Foundation (http://www.apache.org/).
|
||||
|
||||
|
||||
---
|
||||
This product contains software distributed under
|
||||
Common Development and Distribution License 1.0 (CDDL)
|
||||
|
||||
JavaMail API 1.5.3
|
||||
https://java.net/projects/javamail/pages/Home
|
||||
https://java.net/projects/javamail/pages/License
|
||||
|
||||
JavaBeans Activation Framework 1.1.1
|
||||
http://www.oracle.com/technetwork/articles/java/index-135046.html
|
||||
|
||||
---
|
||||
|
||||
This product contains software developed by Mike Samuel. The
|
||||
following is the copyright and notice text for this software:
|
||||
|
||||
Copyright (c) 2011, Mike Samuel
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions
|
||||
are met:
|
||||
|
||||
Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
Neither the name of the OWASP nor the names of its contributors may
|
||||
be used to endorse or promote products derived from this software
|
||||
without specific prior written permission.
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
|
||||
FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
|
||||
COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
||||
BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
|
||||
ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
POSSIBILITY OF SUCH DAMAGE.
|
||||
|
Loading…
Reference in New Issue