mirror of
https://github.com/valitydev/opendistro-security-ssl.git
synced 2024-11-06 00:45:16 +00:00
Open Distro for Elasticsearch Security SSL initial release
This commit is contained in:
commit
cf5050404f
16
.github/ISSUE_TEMPLATE.md
vendored
Normal file
16
.github/ISSUE_TEMPLATE.md
vendored
Normal file
@ -0,0 +1,16 @@
|
||||
<!--
|
||||
|
||||
Github is a place only for reporting bugs or feature requests.
|
||||
If you report a bug please include always the following informations:
|
||||
|
||||
* Security plugin and Elasticsearch version
|
||||
* JVM version and operating system version
|
||||
* Number of nodes in your cluster
|
||||
* Description of the bug
|
||||
|
||||
These informations are optional but are very valueable and
|
||||
typically would lead to get bugs fixed faster:
|
||||
|
||||
* Steps to reproduce
|
||||
* Logfiles on DEBUG level
|
||||
-->
|
8
.github/PULL_REQUEST_TEMPLATE.md
vendored
Normal file
8
.github/PULL_REQUEST_TEMPLATE.md
vendored
Normal file
@ -0,0 +1,8 @@
|
||||
<!--
|
||||
|
||||
Issue #, if available:
|
||||
|
||||
Description of changes:
|
||||
|
||||
By submitting this pull request, I confirm that my contribution is made under the terms of the Apache 2.0 license.
|
||||
-->
|
46
.gitignore
vendored
Normal file
46
.gitignore
vendored
Normal file
@ -0,0 +1,46 @@
|
||||
logstash*/
|
||||
target/
|
||||
test-output/
|
||||
*.tar.gz
|
||||
*gen-*conf*
|
||||
netty*jar
|
||||
logstash*/
|
||||
|
||||
/build.gradle
|
||||
*.log
|
||||
.externalToolBuilders
|
||||
maven-eclipse.xml
|
||||
|
||||
## eclipse ignores (use 'mvn eclipse:eclipse' to build eclipse projects)
|
||||
## The only configuration files which are not ignored are certain files in
|
||||
## .settings (as listed below) since these files ensure common coding
|
||||
## style across Eclipse and IDEA.
|
||||
## Other files (.project, .classpath) should be generated through Maven which
|
||||
## will correctly set the classpath based on the declared dependencies.
|
||||
.project
|
||||
.classpath
|
||||
eclipse-build
|
||||
*/.project
|
||||
*/.classpath
|
||||
*/eclipse-build
|
||||
/.settings/
|
||||
!/.settings/org.eclipse.core.resources.prefs
|
||||
!/.settings/org.eclipse.jdt.core.prefs
|
||||
!/.settings/org.eclipse.jdt.ui.prefs
|
||||
!/.settings/org.eclipse.jdt.groovy.core.prefs
|
||||
bin
|
||||
tomcat.*
|
||||
elasticsearch-*/
|
||||
*node_key.key
|
||||
securekey.key
|
||||
/target/
|
||||
.DS_Store
|
||||
data/
|
||||
example-pki-scripts/**/*.jks
|
||||
example-pki-scripts/**/*.p12
|
||||
example-pki-scripts/**/*.pem
|
||||
example-pki-scripts/**/db/
|
||||
example-pki-scripts/**/*.csr
|
||||
example-pki-scripts/**/*.crt
|
||||
example-pki-scripts/**/*.key
|
||||
.vagrant/
|
4
CODE_OF_CONDUCT.md
Normal file
4
CODE_OF_CONDUCT.md
Normal file
@ -0,0 +1,4 @@
|
||||
## Code of Conduct
|
||||
This project has adopted the [Amazon Open Source Code of Conduct](https://aws.github.io/code-of-conduct).
|
||||
For more information see the [Code of Conduct FAQ](https://aws.github.io/code-of-conduct-faq) or contact
|
||||
opensource-codeofconduct@amazon.com with any additional questions or comments.
|
61
CONTRIBUTING.md
Normal file
61
CONTRIBUTING.md
Normal file
@ -0,0 +1,61 @@
|
||||
# Contributing Guidelines
|
||||
|
||||
Thank you for your interest in contributing to our project. Whether it's a bug report, new feature, correction, or additional
|
||||
documentation, we greatly value feedback and contributions from our community.
|
||||
|
||||
Please read through this document before submitting any issues or pull requests to ensure we have all the necessary
|
||||
information to effectively respond to your bug report or contribution.
|
||||
|
||||
|
||||
## Reporting Bugs/Feature Requests
|
||||
|
||||
We welcome you to use the GitHub issue tracker to report bugs or suggest features.
|
||||
|
||||
When filing an issue, please check [existing open](https://github.com/OpenDistro/elasticsearch-security-ssl/issues), or [recently closed](https://github.com/OpenDistro/elasticsearch-security-ssl/issues?utf8=%E2%9C%93&q=is%3Aissue%20is%3Aclosed%20), issues to make sure somebody else hasn't already
|
||||
reported the issue. Please try to include as much information as you can. Details like these are incredibly useful:
|
||||
|
||||
* A reproducible test case or series of steps
|
||||
* The version of our code being used
|
||||
* Any modifications you've made relevant to the bug
|
||||
* Anything unusual about your environment or deployment
|
||||
|
||||
|
||||
## Contributing via Pull Requests
|
||||
Contributions via pull requests are much appreciated. Before sending us a pull request, please ensure that:
|
||||
|
||||
1. You are working against the latest source on the *master* branch.
|
||||
2. You check existing open, and recently merged, pull requests to make sure someone else hasn't addressed the problem already.
|
||||
3. You open an issue to discuss any significant work - we would hate for your time to be wasted.
|
||||
|
||||
To send us a pull request, please:
|
||||
|
||||
1. Fork the repository.
|
||||
2. Modify the source; please focus on the specific change you are contributing. If you also reformat all the code, it will be hard for us to focus on your change.
|
||||
3. Ensure local tests pass.
|
||||
4. Commit to your fork using clear commit messages.
|
||||
5. Send us a pull request, answering any default questions in the pull request interface.
|
||||
6. Pay attention to any automated CI failures reported in the pull request, and stay involved in the conversation.
|
||||
|
||||
GitHub provides additional document on [forking a repository](https://help.github.com/articles/fork-a-repo/) and
|
||||
[creating a pull request](https://help.github.com/articles/creating-a-pull-request/).
|
||||
|
||||
|
||||
## Finding contributions to work on
|
||||
Looking at the existing issues is a great way to find something to contribute on. As our projects, by default, use the default GitHub issue labels (enhancement/bug/duplicate/help wanted/invalid/question/wontfix), looking at any ['help wanted'](https://github.com/OpenDistro/elasticsearch-security-ssl/labels/help%20wanted) issues is a great place to start.
|
||||
|
||||
|
||||
## Code of Conduct
|
||||
This project has adopted the [Amazon Open Source Code of Conduct](https://aws.github.io/code-of-conduct).
|
||||
For more information see the [Code of Conduct FAQ](https://aws.github.io/code-of-conduct-faq) or contact
|
||||
opensource-codeofconduct@amazon.com with any additional questions or comments.
|
||||
|
||||
|
||||
## Security issue notifications
|
||||
If you discover a potential security issue in this project we ask that you notify AWS/Amazon Security via our [vulnerability reporting page](http://aws.amazon.com/security/vulnerability-reporting/). Please do **not** create a public github issue.
|
||||
|
||||
|
||||
## Licensing
|
||||
|
||||
See the [LICENSE](https://github.com/OpenDistro/elasticsearch-security-ssl/blob/master/LICENSE) file for our project's licensing. We will ask you to confirm the licensing of your contribution.
|
||||
|
||||
We may ask you to sign a [Contributor License Agreement (CLA)](http://en.wikipedia.org/wiki/Contributor_License_Agreement) for larger changes.
|
202
LICENSE
Normal file
202
LICENSE
Normal file
@ -0,0 +1,202 @@
|
||||
|
||||
Apache License
|
||||
Version 2.0, January 2004
|
||||
http://www.apache.org/licenses/
|
||||
|
||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||
|
||||
1. Definitions.
|
||||
|
||||
"License" shall mean the terms and conditions for use, reproduction,
|
||||
and distribution as defined by Sections 1 through 9 of this document.
|
||||
|
||||
"Licensor" shall mean the copyright owner or entity authorized by
|
||||
the copyright owner that is granting the License.
|
||||
|
||||
"Legal Entity" shall mean the union of the acting entity and all
|
||||
other entities that control, are controlled by, or are under common
|
||||
control with that entity. For the purposes of this definition,
|
||||
"control" means (i) the power, direct or indirect, to cause the
|
||||
direction or management of such entity, whether by contract or
|
||||
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||
|
||||
"You" (or "Your") shall mean an individual or Legal Entity
|
||||
exercising permissions granted by this License.
|
||||
|
||||
"Source" form shall mean the preferred form for making modifications,
|
||||
including but not limited to software source code, documentation
|
||||
source, and configuration files.
|
||||
|
||||
"Object" form shall mean any form resulting from mechanical
|
||||
transformation or translation of a Source form, including but
|
||||
not limited to compiled object code, generated documentation,
|
||||
and conversions to other media types.
|
||||
|
||||
"Work" shall mean the work of authorship, whether in Source or
|
||||
Object form, made available under the License, as indicated by a
|
||||
copyright notice that is included in or attached to the work
|
||||
(an example is provided in the Appendix below).
|
||||
|
||||
"Derivative Works" shall mean any work, whether in Source or Object
|
||||
form, that is based on (or derived from) the Work and for which the
|
||||
editorial revisions, annotations, elaborations, or other modifications
|
||||
represent, as a whole, an original work of authorship. For the purposes
|
||||
of this License, Derivative Works shall not include works that remain
|
||||
separable from, or merely link (or bind by name) to the interfaces of,
|
||||
the Work and Derivative Works thereof.
|
||||
|
||||
"Contribution" shall mean any work of authorship, including
|
||||
the original version of the Work and any modifications or additions
|
||||
to that Work or Derivative Works thereof, that is intentionally
|
||||
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||
or by an individual or Legal Entity authorized to submit on behalf of
|
||||
the copyright owner. For the purposes of this definition, "submitted"
|
||||
means any form of electronic, verbal, or written communication sent
|
||||
to the Licensor or its representatives, including but not limited to
|
||||
communication on electronic mailing lists, source code control systems,
|
||||
and issue tracking systems that are managed by, or on behalf of, the
|
||||
Licensor for the purpose of discussing and improving the Work, but
|
||||
excluding communication that is conspicuously marked or otherwise
|
||||
designated in writing by the copyright owner as "Not a Contribution."
|
||||
|
||||
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||
on behalf of whom a Contribution has been received by Licensor and
|
||||
subsequently incorporated within the Work.
|
||||
|
||||
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
copyright license to reproduce, prepare Derivative Works of,
|
||||
publicly display, publicly perform, sublicense, and distribute the
|
||||
Work and such Derivative Works in Source or Object form.
|
||||
|
||||
3. Grant of Patent License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
(except as stated in this section) patent license to make, have made,
|
||||
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||
where such license applies only to those patent claims licensable
|
||||
by such Contributor that are necessarily infringed by their
|
||||
Contribution(s) alone or by combination of their Contribution(s)
|
||||
with the Work to which such Contribution(s) was submitted. If You
|
||||
institute patent litigation against any entity (including a
|
||||
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||
or a Contribution incorporated within the Work constitutes direct
|
||||
or contributory patent infringement, then any patent licenses
|
||||
granted to You under this License for that Work shall terminate
|
||||
as of the date such litigation is filed.
|
||||
|
||||
4. Redistribution. You may reproduce and distribute copies of the
|
||||
Work or Derivative Works thereof in any medium, with or without
|
||||
modifications, and in Source or Object form, provided that You
|
||||
meet the following conditions:
|
||||
|
||||
(a) You must give any other recipients of the Work or
|
||||
Derivative Works a copy of this License; and
|
||||
|
||||
(b) You must cause any modified files to carry prominent notices
|
||||
stating that You changed the files; and
|
||||
|
||||
(c) You must retain, in the Source form of any Derivative Works
|
||||
that You distribute, all copyright, patent, trademark, and
|
||||
attribution notices from the Source form of the Work,
|
||||
excluding those notices that do not pertain to any part of
|
||||
the Derivative Works; and
|
||||
|
||||
(d) If the Work includes a "NOTICE" text file as part of its
|
||||
distribution, then any Derivative Works that You distribute must
|
||||
include a readable copy of the attribution notices contained
|
||||
within such NOTICE file, excluding those notices that do not
|
||||
pertain to any part of the Derivative Works, in at least one
|
||||
of the following places: within a NOTICE text file distributed
|
||||
as part of the Derivative Works; within the Source form or
|
||||
documentation, if provided along with the Derivative Works; or,
|
||||
within a display generated by the Derivative Works, if and
|
||||
wherever such third-party notices normally appear. The contents
|
||||
of the NOTICE file are for informational purposes only and
|
||||
do not modify the License. You may add Your own attribution
|
||||
notices within Derivative Works that You distribute, alongside
|
||||
or as an addendum to the NOTICE text from the Work, provided
|
||||
that such additional attribution notices cannot be construed
|
||||
as modifying the License.
|
||||
|
||||
You may add Your own copyright statement to Your modifications and
|
||||
may provide additional or different license terms and conditions
|
||||
for use, reproduction, or distribution of Your modifications, or
|
||||
for any such Derivative Works as a whole, provided Your use,
|
||||
reproduction, and distribution of the Work otherwise complies with
|
||||
the conditions stated in this License.
|
||||
|
||||
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||
any Contribution intentionally submitted for inclusion in the Work
|
||||
by You to the Licensor shall be under the terms and conditions of
|
||||
this License, without any additional terms or conditions.
|
||||
Notwithstanding the above, nothing herein shall supersede or modify
|
||||
the terms of any separate license agreement you may have executed
|
||||
with Licensor regarding such Contributions.
|
||||
|
||||
6. Trademarks. This License does not grant permission to use the trade
|
||||
names, trademarks, service marks, or product names of the Licensor,
|
||||
except as required for reasonable and customary use in describing the
|
||||
origin of the Work and reproducing the content of the NOTICE file.
|
||||
|
||||
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||
agreed to in writing, Licensor provides the Work (and each
|
||||
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
implied, including, without limitation, any warranties or conditions
|
||||
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||
appropriateness of using or redistributing the Work and assume any
|
||||
risks associated with Your exercise of permissions under this License.
|
||||
|
||||
8. Limitation of Liability. In no event and under no legal theory,
|
||||
whether in tort (including negligence), contract, or otherwise,
|
||||
unless required by applicable law (such as deliberate and grossly
|
||||
negligent acts) or agreed to in writing, shall any Contributor be
|
||||
liable to You for damages, including any direct, indirect, special,
|
||||
incidental, or consequential damages of any character arising as a
|
||||
result of this License or out of the use or inability to use the
|
||||
Work (including but not limited to damages for loss of goodwill,
|
||||
work stoppage, computer failure or malfunction, or any and all
|
||||
other commercial damages or losses), even if such Contributor
|
||||
has been advised of the possibility of such damages.
|
||||
|
||||
9. Accepting Warranty or Additional Liability. While redistributing
|
||||
the Work or Derivative Works thereof, You may choose to offer,
|
||||
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||
or other liability obligations and/or rights consistent with this
|
||||
License. However, in accepting such obligations, You may act only
|
||||
on Your own behalf and on Your sole responsibility, not on behalf
|
||||
of any other Contributor, and only if You agree to indemnify,
|
||||
defend, and hold each Contributor harmless for any liability
|
||||
incurred by, or claims asserted against, such Contributor by reason
|
||||
of your accepting any such warranty or additional liability.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
APPENDIX: How to apply the Apache License to your work.
|
||||
|
||||
To apply the Apache License to your work, attach the following
|
||||
boilerplate notice, with the fields enclosed by brackets "[]"
|
||||
replaced with your own identifying information. (Don't include
|
||||
the brackets!) The text should be enclosed in the appropriate
|
||||
comment syntax for the file format. We also recommend that a
|
||||
file or class name and description of purpose be included on the
|
||||
same "printed page" as the copyright notice for easier
|
||||
identification within third-party archives.
|
||||
|
||||
Copyright [yyyy] [name of copyright owner]
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
10
NOTICE.txt
Normal file
10
NOTICE.txt
Normal file
@ -0,0 +1,10 @@
|
||||
floragunn GmbH Copyright 2015-2018 floragunn GmbH
|
||||
|
||||
Copyright 2019 Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
||||
|
||||
This product includes software developed by The Apache Software
|
||||
Foundation (http://www.apache.org/).
|
||||
|
||||
This product includes software developed by Mort Bay Consulting Pty. Ltd.
|
||||
|
||||
See THIRD-PARTY.txt for additional third party licenses used by this product.
|
20
README.md
Normal file
20
README.md
Normal file
@ -0,0 +1,20 @@
|
||||
# Open Distro For Elasticsearch Security SSL
|
||||
|
||||
Open Distro For Elasticsearch Security SSL is a free and open source plugin for Elasticsearch which provides SSL/TLS support for Elasticsearch.
|
||||
|
||||
## Features
|
||||
* Node-to-node encryption through SSL/TLS (Transport layer)
|
||||
* Secure REST layer through HTTPS (SSL/TLS)
|
||||
* Supports JDK SSL and OpenSSL
|
||||
* Works with Kibana, Logstash and Beats
|
||||
|
||||
## Documentation
|
||||
Please refer to the [Official documentation] for detailed information on installing and configuring opendistro-elasticsearch-security-ssl plugin.
|
||||
|
||||
## License
|
||||
|
||||
Open Distro For Elasticsearch Security SSL is licensed under the Apache 2.0 license.
|
||||
|
||||
## Legal
|
||||
Open Distro For Elasticsearch Security SSL
|
||||
Copyright 2019- Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
52
THIRD-PARTY.txt
Normal file
52
THIRD-PARTY.txt
Normal file
@ -0,0 +1,52 @@
|
||||
|
||||
Lists of 50 third-party dependencies.
|
||||
(The Apache Software License, Version 2.0) HPPC Collections (com.carrotsearch:hppc:0.7.1 - http://labs.carrotsearch.com/hppc.html/hppc)
|
||||
(The Apache Software License, Version 2.0) Jackson-core (com.fasterxml.jackson.core:jackson-core:2.8.10 - https://github.com/FasterXML/jackson-core)
|
||||
(The Apache Software License, Version 2.0) Jackson dataformat: CBOR (com.fasterxml.jackson.dataformat:jackson-dataformat-cbor:2.8.10 - http://github.com/FasterXML/jackson-dataformats-binary)
|
||||
(The Apache Software License, Version 2.0) Jackson dataformat: Smile (com.fasterxml.jackson.dataformat:jackson-dataformat-smile:2.8.10 - http://github.com/FasterXML/jackson-dataformats-binary)
|
||||
(The Apache Software License, Version 2.0) Jackson-dataformat-YAML (com.fasterxml.jackson.dataformat:jackson-dataformat-yaml:2.8.10 - https://github.com/FasterXML/jackson)
|
||||
(The Apache Software License, Version 2.0) T-Digest (com.tdunning:t-digest:3.0 - https://github.com/tdunning/t-digest)
|
||||
(The Apache Software License, Version 2.0) Apache Commons Codec (commons-codec:commons-codec:1.9 - http://commons.apache.org/proper/commons-codec/)
|
||||
(Apache License, Version 2.0) Apache Commons IO (commons-io:commons-io:2.6 - http://commons.apache.org/proper/commons-io/)
|
||||
(The Apache Software License, Version 2.0) Apache Commons Logging (commons-logging:commons-logging:1.2 - http://commons.apache.org/proper/commons-logging/)
|
||||
(Apache License, Version 2.0) Netty/Buffer (io.netty:netty-buffer:4.1.16.Final - http://netty.io/netty-buffer/)
|
||||
(Apache License, Version 2.0) Netty/Codec (io.netty:netty-codec:4.1.16.Final - http://netty.io/netty-codec/)
|
||||
(Apache License, Version 2.0) Netty/Codec/HTTP (io.netty:netty-codec-http:4.1.16.Final - http://netty.io/netty-codec-http/)
|
||||
(Apache License, Version 2.0) Netty/Common (io.netty:netty-common:4.1.16.Final - http://netty.io/netty-common/)
|
||||
(Apache License, Version 2.0) Netty/Handler (io.netty:netty-handler:4.1.16.Final - http://netty.io/netty-handler/)
|
||||
(Apache License, Version 2.0) Netty/Resolver (io.netty:netty-resolver:4.1.16.Final - http://netty.io/netty-resolver/)
|
||||
(Apache License, Version 2.0) Netty/TomcatNative [OpenSSL - Dynamic] (io.netty:netty-tcnative:2.0.7.Final - https://github.com/netty/netty-tcnative/netty-tcnative/)
|
||||
(Apache License, Version 2.0) Netty/Transport (io.netty:netty-transport:4.1.16.Final - http://netty.io/netty-transport/)
|
||||
(Apache 2) Joda-Time (joda-time:joda-time:2.9.9 - http://www.joda.org/joda-time/)
|
||||
(Eclipse Public License 1.0) JUnit (junit:junit:4.12 - http://junit.org)
|
||||
(The MIT License) JOpt Simple (net.sf.jopt-simple:jopt-simple:5.0.2 - http://pholser.github.io/jopt-simple)
|
||||
(Apache License, Version 2.0) Apache HttpClient Fluent API (org.apache.httpcomponents:fluent-hc:4.5.3 - http://hc.apache.org/httpcomponents-client)
|
||||
(Apache License, Version 2.0) Apache HttpClient (org.apache.httpcomponents:httpclient:4.5.3 - http://hc.apache.org/httpcomponents-client)
|
||||
(Apache License, Version 2.0) Apache HttpCore (org.apache.httpcomponents:httpcore:4.4.6 - http://hc.apache.org/httpcomponents-core-ga)
|
||||
(Apache License, Version 2.0) Apache Log4j API (org.apache.logging.log4j:log4j-api:2.9.1 - https://logging.apache.org/log4j/2.x/log4j-api/)
|
||||
(Apache License, Version 2.0) Apache Log4j Core (org.apache.logging.log4j:log4j-core:2.9.1 - https://logging.apache.org/log4j/2.x/log4j-core/)
|
||||
(Apache 2) Lucene Common Analyzers (org.apache.lucene:lucene-analyzers-common:7.2.1 - http://lucene.apache.org/lucene-parent/lucene-analyzers-common)
|
||||
(Apache 2) Lucene Memory (org.apache.lucene:lucene-backward-codecs:7.2.1 - http://lucene.apache.org/lucene-parent/lucene-backward-codecs)
|
||||
(Apache 2) Lucene Core (org.apache.lucene:lucene-core:7.2.1 - http://lucene.apache.org/lucene-parent/lucene-core)
|
||||
(Apache 2) Lucene Grouping (org.apache.lucene:lucene-grouping:7.2.1 - http://lucene.apache.org/lucene-parent/lucene-grouping)
|
||||
(Apache 2) Lucene Highlighter (org.apache.lucene:lucene-highlighter:7.2.1 - http://lucene.apache.org/lucene-parent/lucene-highlighter)
|
||||
(Apache 2) Lucene Join (org.apache.lucene:lucene-join:7.2.1 - http://lucene.apache.org/lucene-parent/lucene-join)
|
||||
(Apache 2) Lucene Memory (org.apache.lucene:lucene-memory:7.2.1 - http://lucene.apache.org/lucene-parent/lucene-memory)
|
||||
(Apache 2) Lucene Miscellaneous (org.apache.lucene:lucene-misc:7.2.1 - http://lucene.apache.org/lucene-parent/lucene-misc)
|
||||
(Apache 2) Lucene Queries (org.apache.lucene:lucene-queries:7.2.1 - http://lucene.apache.org/lucene-parent/lucene-queries)
|
||||
(Apache 2) Lucene QueryParsers (org.apache.lucene:lucene-queryparser:7.2.1 - http://lucene.apache.org/lucene-parent/lucene-queryparser)
|
||||
(Apache 2) Lucene Sandbox (org.apache.lucene:lucene-sandbox:7.2.1 - http://lucene.apache.org/lucene-parent/lucene-sandbox)
|
||||
(Apache 2) Lucene Spatial (org.apache.lucene:lucene-spatial:7.2.1 - http://lucene.apache.org/lucene-parent/lucene-spatial)
|
||||
(Apache 2) Lucene Spatial Extras (org.apache.lucene:lucene-spatial-extras:7.2.1 - http://lucene.apache.org/lucene-parent/lucene-spatial-extras)
|
||||
(Apache 2) Lucene Spatial 3D (org.apache.lucene:lucene-spatial3d:7.2.1 - http://lucene.apache.org/lucene-parent/lucene-spatial3d)
|
||||
(Apache 2) Lucene Suggest (org.apache.lucene:lucene-suggest:7.2.1 - http://lucene.apache.org/lucene-parent/lucene-suggest)
|
||||
(The Apache Software License, Version 2.0) server (org.elasticsearch:elasticsearch:6.2.0 - https://github.com/elastic/elasticsearch)
|
||||
(The Apache Software License, Version 2.0) cli (org.elasticsearch:elasticsearch-cli:6.2.0 - https://github.com/elastic/elasticsearch)
|
||||
(The Apache Software License, Version 2.0) elasticsearch-core (org.elasticsearch:elasticsearch-core:6.2.0 - https://github.com/elastic/elasticsearch)
|
||||
(The Apache Software License, Version 2.0) Elastic JNA Distribution (org.elasticsearch:jna:4.5.1 - https://github.com/java-native-access/jna)
|
||||
(The Apache Software License, Version 2.0) Elasticsearch SecureSM (org.elasticsearch:securesm:1.2 - http://nexus.sonatype.org/oss-repository-hosting.html/securesm)
|
||||
(The Apache Software License, Version 2.0) transport-netty4 (org.elasticsearch.plugin:transport-netty4-client:6.2.0 - https://github.com/elastic/elasticsearch)
|
||||
(New BSD License) Hamcrest All (org.hamcrest:hamcrest-all:1.3 - https://github.com/hamcrest/JavaHamcrest/hamcrest-all)
|
||||
(New BSD License) Hamcrest Core (org.hamcrest:hamcrest-core:1.3 - https://github.com/hamcrest/JavaHamcrest/hamcrest-core)
|
||||
(Public Domain, per Creative Commons CC0) HdrHistogram (org.hdrhistogram:HdrHistogram:2.1.9 - http://hdrhistogram.github.io/HdrHistogram/)
|
||||
(Apache License, Version 2.0) SnakeYAML (org.yaml:snakeyaml:1.17 - http://www.snakeyaml.org)
|
149
opendistrosecurity-ssl-config-template.yml
Normal file
149
opendistrosecurity-ssl-config-template.yml
Normal file
@ -0,0 +1,149 @@
|
||||
#############################################################################################
|
||||
# OPEN DISTRO SECURITY SSL #
|
||||
# Configuration #
|
||||
#############################################################################################
|
||||
|
||||
|
||||
#############################################################################################
|
||||
# Transport layer SSL #
|
||||
# #
|
||||
#############################################################################################
|
||||
# Enable or disable node-to-node ssl encryption (default: true)
|
||||
#opendistro_security.ssl.transport.enabled: false
|
||||
# JKS or PKCS12 (default: JKS)
|
||||
#opendistro_security.ssl.transport.keystore_type: PKCS12
|
||||
# Relative path to the keystore file (mandatory, this stores the server certificates), must be placed under the config/ dir
|
||||
#opendistro_security.ssl.transport.keystore_filepath: keystore_node1.jks
|
||||
# Alias name (default: first alias which could be found)
|
||||
#opendistro_security.ssl.transport.keystore_alias: my_alias
|
||||
# Keystore password (default: changeit)
|
||||
#opendistro_security.ssl.transport.keystore_password: changeit
|
||||
|
||||
# JKS or PKCS12 (default: JKS)
|
||||
#opendistro_security.ssl.transport.truststore_type: PKCS12
|
||||
# Relative path to the truststore file (mandatory, this stores the client/root certificates), must be placed under the config/ dir
|
||||
#opendistro_security.ssl.transport.truststore_filepath: truststore.jks
|
||||
# Alias name (default: trust all aliases)
|
||||
#opendistro_security.ssl.transport.truststore_alias: my_alias
|
||||
# Truststore password (default: changeit)
|
||||
#opendistro_security.ssl.transport.truststore_password: changeit
|
||||
# Enforce hostname verification (default: true)
|
||||
#opendistro_security.ssl.transport.enforce_hostname_verification: true
|
||||
# If hostname verification is enabled specify if hostname should be resolved (default: true)
|
||||
#opendistro_security.ssl.transport.resolve_hostname: true
|
||||
# Use native Open SSL instead of JDK SSL if available (default: true)
|
||||
#opendistro_security.ssl.transport.enable_openssl_if_available: false
|
||||
|
||||
# As an alternative to JKS/PCKS12 based configuration
|
||||
# you can also use X.509 PEM certificates and PKCS #8 keys.
|
||||
# This, for example, makes it pretty easy to configure letsencrypt certificates.
|
||||
|
||||
# Relative path to the certificates key file (PKCS #8), must be placed under the config/ dir
|
||||
#opendistro_security.ssl.transport.pemkey_filepath: privkey.pem
|
||||
# Key password (omit this setting if the key has no password)
|
||||
#opendistro_security.ssl.transport.pemkey_password: "secret"
|
||||
# X509 node certificate chain in PEM format, must be placed under the config/ dir
|
||||
#opendistro_security.ssl.transport.pemcert_filepath: fullchain.pem
|
||||
# Trusted certificates
|
||||
#opendistro_security.ssl.transport.pemtrustedcas_filepath: chain.pem
|
||||
|
||||
|
||||
# Enabled SSL cipher suites for transport protocol (only Java format is supported)
|
||||
# WARNING: Expert setting, do only use if you know what you are doing
|
||||
# If you set wrong values here this this could be a security risk
|
||||
#opendistro_security.ssl.transport.enabled_ciphers:
|
||||
# - "TLS_DHE_RSA_WITH_AES_256_CBC_SHA"
|
||||
# - "TLS_DHE_DSS_WITH_AES_128_CBC_SHA256"
|
||||
|
||||
# Enabled SSL protocols for transport protocol (only Java format is supported)
|
||||
# WARNING: Expert setting, do only use if you know what you are doing
|
||||
# If you set wrong values here this this could be a security risk
|
||||
#opendistro_security.ssl.transport.enabled_protocols:
|
||||
# - "TLSv1.2"
|
||||
|
||||
#############################################################################################
|
||||
# HTTP/REST layer SSL #
|
||||
# #
|
||||
#############################################################################################
|
||||
# Enable or disable rest layer security - https, (default: false)
|
||||
#opendistro_security.ssl.http.enabled: true
|
||||
# JKS or PKCS12 (default: JKS)
|
||||
#opendistro_security.ssl.http.keystore_type: PKCS12
|
||||
# Relative path to the keystore file (this stores the server certificates), must be placed under the config/ dir
|
||||
#opendistro_security.ssl.http.keystore_filepath: keystore_https_node1.jks
|
||||
# Alias name (default: first alias which could be found)
|
||||
#opendistro_security.ssl.http.keystore_alias: my_alias
|
||||
# Keystore password (default: changeit)
|
||||
#opendistro_security.ssl.http.keystore_password: changeit
|
||||
# Do the clients (typically the browser or the proxy) have to authenticate themself to the http server, default is OPTIONAL
|
||||
# To enforce authentication use REQUIRE, to completely disable client certificates use NONE
|
||||
#opendistro_security.ssl.http.clientauth_mode: REQUIRE
|
||||
# JKS or PKCS12 (default: JKS)
|
||||
#opendistro_security.ssl.http.truststore_type: PKCS12
|
||||
# Relative path to the truststore file (this stores the client certificates), must be placed under the config/ dir
|
||||
#opendistro_security.ssl.http.truststore_filepath: truststore_https.jks
|
||||
# Alias name (default: first alias which could be found)
|
||||
#opendistro_security.ssl.http.truststore_alias: my_alias
|
||||
# Truststore password (default: changeit)
|
||||
#opendistro_security.ssl.http.truststore_password: changeit
|
||||
# Use native Open SSL instead of JDK SSL if available (default: true)
|
||||
#opendistro_security.ssl.http.enable_openssl_if_available: false
|
||||
|
||||
# As an alternative to JKS/PCKS12 based configuration
|
||||
# you can also use X.509 PEM certificates and PKCS #8 keys.
|
||||
# This, for example, makes it pretty easy to configure letsencrypt certificates.
|
||||
|
||||
# Relative path to the certificates key file (PKCS #8), must be placed under the config/ dir
|
||||
#opendistro_security.ssl.http.pemkey_filepath: privkey.pem
|
||||
# Key password (omit this setting if the key has no password)
|
||||
#opendistro_security.ssl.http.pemkey_password: "secret"
|
||||
# X509 node certificate chain in PEM format, must be placed under the config/ dir
|
||||
#opendistro_security.ssl.http.pemcert_filepath: fullchain.pem
|
||||
# Trusted certificates
|
||||
#opendistro_security.ssl.http.pemtrustedcas_filepath: chain.pem
|
||||
|
||||
# Enabled SSL cipher suites for http protocol (only Java format is supported)
|
||||
# WARNING: Expert setting, do only use if you know what you are doing
|
||||
# If you set wrong values here this this could be a security risk
|
||||
#opendistro_security.ssl.http.enabled_ciphers:
|
||||
# - "TLS_DHE_RSA_WITH_AES_256_CBC_SHA"
|
||||
# - "TLS_DHE_DSS_WITH_AES_128_CBC_SHA256"
|
||||
|
||||
# Enabled SSL protocols for http protocol (only Java format is supported)
|
||||
# WARNING: Expert setting, do only use if you know what you are doing
|
||||
# If you set wrong values here this this could be a security risk
|
||||
#opendistro_security.ssl.http.enabled_protocols:
|
||||
# - "TLSv1.2"
|
||||
|
||||
# Enables the usage of custom SSLContext's for Transport clients
|
||||
# This setting does only apply to Transport clients
|
||||
# WARNING: Expert setting, do only use if you know what you are doing
|
||||
# If you set wrong values here this this could be a security risk
|
||||
#opendistro_security.ssl.client.external_context_id: myid
|
||||
|
||||
# Class name of a class which is in classpath and implements com.amazon.opendistroforelasticsearch.security.ssl.transport.PrincipalExtractor
|
||||
# used to resolve the string representation of an principal from a x509 certificate
|
||||
# WARNING: Expert setting, do only use if you know what you are doing
|
||||
# If you set wrong values here this this could be a security risk
|
||||
#opendistro_security.ssl.transport.principal_extractor_class: com.example.security.MyPrincipalExtractor
|
||||
|
||||
# CRL validation of HTTP client certificates
|
||||
# WARNING: Expert setting, do only use if you know what you are doing
|
||||
# If you set wrong values here this this could be a security risk
|
||||
# Set to true to enable CRL validation (default is false)
|
||||
#opendistro_security.ssl.http.crl.validate: true
|
||||
# File based static revocation list, by default this is null
|
||||
# if null then either OCSP or CRLDP needs to be enabled
|
||||
# CRL file must be in config/ dir, so this path is relative here
|
||||
#opendistro_security.ssl.http.crl.file_path: mycrl.crl
|
||||
# Default is false (means we prefer OCSP over static CRL file)
|
||||
#opendistro_security.ssl.http.crl.prefer_crlfile_over_ocsp: true
|
||||
# Default is true (means we do not validate intermediate certificates)
|
||||
#opendistro_security.ssl.http.crl.check_only_end_entities: false
|
||||
# Default is false (means we use OCSP if available)
|
||||
#opendistro_security.ssl.http.crl.disable_ocsp: true
|
||||
# Default is false (means we use CRLDP if available)
|
||||
#opendistro_security.ssl.http.crl.disable_crldp: true
|
||||
# Sets the time (as unix epoch timestamp) for which the validity of the certification path should be determined
|
||||
# If not set of set to -1 then the current time will be used
|
||||
#opendistro_security.ssl.http.crl.validation_date: 1496070074
|
25
plugin-descriptor.properties
Normal file
25
plugin-descriptor.properties
Normal file
@ -0,0 +1,25 @@
|
||||
#
|
||||
# 'description': simple summary of the plugin
|
||||
description=Provides SSL for Elasticsearch 6
|
||||
#
|
||||
# 'version': plugin's version
|
||||
version=0.7.0.0
|
||||
#
|
||||
# 'name': the plugin name
|
||||
name=opendistro_security-ssl
|
||||
#
|
||||
# 'classname': the name of the class to load, fully-qualified.
|
||||
classname=com.amazon.opendistroforelasticsearch.security.ssl.OpenDistroSecuritySSLPlugin
|
||||
#
|
||||
# 'java.version' version of java the code is built against
|
||||
# use the system property java.specification.version
|
||||
# version string must be a sequence of nonnegative decimal integers
|
||||
# separated by "."'s and may have leading zeros
|
||||
java.version=1.8
|
||||
#
|
||||
# 'elasticsearch.version' version of elasticsearch compiled against
|
||||
# You will have to release a new version of the plugin for each new
|
||||
# elasticsearch release. This version is checked when the plugin
|
||||
# is loaded so Elasticsearch will refuse to start in the presence of
|
||||
# plugins with the incorrect elasticsearch.version.
|
||||
elasticsearch.version=6.5.4
|
55
plugin-security.policy
Normal file
55
plugin-security.policy
Normal file
@ -0,0 +1,55 @@
|
||||
/*
|
||||
* Copyright 2015-2017 floragunn GmbH
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
* Portions Copyright 2019 Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License").
|
||||
* You may not use this file except in compliance with the License.
|
||||
* A copy of the License is located at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* or in the "license" file accompanying this file. This file is distributed
|
||||
* on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
|
||||
* express or implied. See the License for the specific language governing
|
||||
* permissions and limitations under the License.
|
||||
*/
|
||||
|
||||
|
||||
//grant codeBase "${codebase.opendistro_security_ssl-0.7.0.0.jar}" {
|
||||
grant {
|
||||
//below permissions are needed for netty native open ssl support
|
||||
permission java.lang.RuntimePermission "loadLibrary.*";
|
||||
permission java.lang.RuntimePermission "getClassLoader";
|
||||
permission java.lang.RuntimePermission "accessClassInPackage.sun.misc";
|
||||
permission java.lang.reflect.ReflectPermission "suppressAccessChecks";
|
||||
permission java.security.SecurityPermission "getProperty.ssl.KeyManagerFactory.algorithm";
|
||||
permission java.lang.RuntimePermission "accessDeclaredMembers";
|
||||
permission java.lang.RuntimePermission "accessClassInPackage.sun.security.x509";
|
||||
permission java.lang.RuntimePermission "accessClassInPackage.sun.nio.ch";
|
||||
permission java.io.FilePermission "/proc/sys/net/core/somaxconn","read";
|
||||
permission java.util.PropertyPermission "sun.nio.ch.bugLevel", "write";
|
||||
permission java.util.PropertyPermission "jdk.tls.rejectClientInitiatedRenegotiation", "write";
|
||||
|
||||
permission java.security.SecurityPermission "setProperty.ocsp.enable";
|
||||
permission java.util.PropertyPermission "com.sun.security.enableCRLDP", "write";
|
||||
permission java.util.PropertyPermission "es.set.netty.runtime.available.processors", "write";
|
||||
|
||||
permission java.net.NetPermission "getNetworkInformation";
|
||||
permission java.net.SocketPermission "*", "connect,accept,resolve";
|
||||
};
|
207
pom.xml
Normal file
207
pom.xml
Normal file
@ -0,0 +1,207 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!--
|
||||
~ Copyright 2015-2018 _floragunn_ GmbH
|
||||
~ Licensed under the Apache License, Version 2.0 (the "License");
|
||||
~ you may not use this file except in compliance with the License.
|
||||
~ You may obtain a copy of the License at
|
||||
~
|
||||
~ http://www.apache.org/licenses/LICENSE-2.0
|
||||
~
|
||||
~ Unless required by applicable law or agreed to in writing, software
|
||||
~ distributed under the License is distributed on an "AS IS" BASIS,
|
||||
~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
~ See the License for the specific language governing permissions and
|
||||
~ limitations under the License.
|
||||
-->
|
||||
|
||||
<!--
|
||||
~ Portions Copyright 2019 Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
||||
~
|
||||
~ Licensed under the Apache License, Version 2.0 (the "License").
|
||||
~ You may not use this file except in compliance with the License.
|
||||
~ A copy of the License is located at
|
||||
~
|
||||
~ http://www.apache.org/licenses/LICENSE-2.0
|
||||
~
|
||||
~ or in the "license" file accompanying this file. This file is distributed
|
||||
~ on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
|
||||
~ express or implied. See the License for the specific language governing
|
||||
~ permissions and limitations under the License.
|
||||
-->
|
||||
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<parent>
|
||||
<groupId>com.amazon.opendistroforelasticsearch</groupId>
|
||||
<artifactId>opendistro_security_parent</artifactId>
|
||||
<version>0.7.0.0</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>opendistro_security_ssl</artifactId>
|
||||
<version>0.7.0.0</version>
|
||||
<packaging>jar</packaging>
|
||||
|
||||
<name>Open Distro Security SSL</name>
|
||||
<description>Provides SSL Security for Elasticsearch 6</description>
|
||||
<url>https://github.com/mauve-hedgehog/opendistro-elasticsearch-security-ssl</url>
|
||||
<inceptionYear>2015</inceptionYear>
|
||||
|
||||
<licenses>
|
||||
<license>
|
||||
<name>The Apache Software License, Version 2.0</name>
|
||||
<url>http://www.apache.org/licenses/LICENSE-2.0.txt</url>
|
||||
<distribution>repo</distribution>
|
||||
</license>
|
||||
</licenses>
|
||||
|
||||
<properties>
|
||||
<elasticsearch.version>6.5.4</elasticsearch.version>
|
||||
|
||||
<!-- deps -->
|
||||
<netty-native.version>2.0.15.Final</netty-native.version>
|
||||
<log4j.version>2.11.1</log4j.version>
|
||||
</properties>
|
||||
|
||||
<scm>
|
||||
<url>https://github.com/mauve-hedgehog/opendistro-elasticsearch-security-ssl</url>
|
||||
<connection>scm:git:git@github.com:mauve-hedgehog/opendistro-elasticsearch-security-ssl.git</connection>
|
||||
<developerConnection>scm:git:git@github.com:mauve-hedgehog/opendistro-elasticsearch-security-ssl.git</developerConnection>
|
||||
<tag>v0.7.0.0</tag>
|
||||
</scm>
|
||||
|
||||
<issueManagement>
|
||||
<system>GitHub</system>
|
||||
<url>https://github.com/mauve-hedgehog/opendistro-elasticsearch-security-ssl/issues</url>
|
||||
</issueManagement>
|
||||
|
||||
<contributors />
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.elasticsearch</groupId>
|
||||
<artifactId>elasticsearch</artifactId>
|
||||
<version>${elasticsearch.version}</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.apache.logging.log4j</groupId>
|
||||
<artifactId>log4j-core</artifactId>
|
||||
<version>${log4j.version}</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.elasticsearch.plugin</groupId>
|
||||
<artifactId>transport-netty4-client</artifactId>
|
||||
<version>${elasticsearch.version}</version>
|
||||
<exclusions>
|
||||
<exclusion>
|
||||
<artifactId>jna</artifactId>
|
||||
<groupId>org.elasticsearch</groupId>
|
||||
</exclusion>
|
||||
<exclusion>
|
||||
<artifactId>jts</artifactId>
|
||||
<groupId>com.vividsolutions</groupId>
|
||||
</exclusion>
|
||||
<exclusion>
|
||||
<artifactId>log4j-api</artifactId>
|
||||
<groupId>org.apache.logging.log4j</groupId>
|
||||
</exclusion>
|
||||
<exclusion>
|
||||
<artifactId>spatial4j</artifactId>
|
||||
<groupId>org.locationtech.spatial4j</groupId>
|
||||
</exclusion>
|
||||
</exclusions>
|
||||
</dependency>
|
||||
|
||||
<!-- Only test scoped dependencies hereafter -->
|
||||
<dependency>
|
||||
<groupId>commons-io</groupId>
|
||||
<artifactId>commons-io</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.hamcrest</groupId>
|
||||
<artifactId>hamcrest-all</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>junit</groupId>
|
||||
<artifactId>junit</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.apache.httpcomponents</groupId>
|
||||
<artifactId>fluent-hc</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-jar-plugin</artifactId>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-compiler-plugin</artifactId>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-surefire-plugin</artifactId>
|
||||
</plugin>
|
||||
</plugins>
|
||||
<extensions>
|
||||
<extension>
|
||||
<groupId>com.gkatzioura.maven.cloud</groupId>
|
||||
<artifactId>s3-storage-wagon</artifactId>
|
||||
<version>1.8</version>
|
||||
</extension>
|
||||
</extensions>
|
||||
</build>
|
||||
|
||||
<profiles>
|
||||
<profile>
|
||||
<id>with-static-openssl-linux-non-fedora</id>
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>com.floragunn</groupId>
|
||||
<artifactId>search-guard-static-tcnative-beta</artifactId>
|
||||
<version>1.1.0j-${netty-native.version}-non-fedora-linux-x86_64</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</profile>
|
||||
<profile>
|
||||
<id>with-static-openssl-linux-fedora</id>
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>com.floragunn</groupId>
|
||||
<artifactId>search-guard-static-tcnative-beta</artifactId>
|
||||
<version>1.1.0j-${netty-native.version}-fedora-linux-x86_64</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</profile>
|
||||
<profile>
|
||||
<id>with-dynamic-openssl</id>
|
||||
<activation>
|
||||
<activeByDefault>true</activeByDefault>
|
||||
</activation>
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>io.netty</groupId>
|
||||
<artifactId>netty-tcnative</artifactId>
|
||||
<version>${netty-native.version}</version>
|
||||
<classifier>${os.detected.classifier}</classifier>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</profile>
|
||||
</profiles>
|
||||
</project>
|
33
src/main/assemblies/plugin.xml
Normal file
33
src/main/assemblies/plugin.xml
Normal file
@ -0,0 +1,33 @@
|
||||
<?xml version="1.0"?>
|
||||
<assembly>
|
||||
<id>plugin</id>
|
||||
<formats>
|
||||
<format>zip</format>
|
||||
</formats>
|
||||
<includeBaseDirectory>false</includeBaseDirectory>
|
||||
<dependencySets>
|
||||
<dependencySet>
|
||||
<useStrictFiltering>true</useStrictFiltering>
|
||||
<outputDirectory>${file.separator}</outputDirectory>
|
||||
<useProjectArtifact>true</useProjectArtifact>
|
||||
<useTransitiveFiltering>true</useTransitiveFiltering>
|
||||
</dependencySet>
|
||||
<dependencySet>
|
||||
<useStrictFiltering>true</useStrictFiltering>
|
||||
<outputDirectory>${file.separator}</outputDirectory>
|
||||
<includes>
|
||||
<include>com.amazon:opendistro_security_ssl</include>
|
||||
</includes>
|
||||
</dependencySet>
|
||||
</dependencySets>
|
||||
<fileSets>
|
||||
<fileSet>
|
||||
<outputDirectory>${file.separator}</outputDirectory>
|
||||
<includes>
|
||||
<include>plugin-descriptor.properties</include>
|
||||
<include>plugin-security.policy</include>
|
||||
</includes>
|
||||
</fileSet>
|
||||
</fileSets>
|
||||
</assembly>
|
||||
|
@ -0,0 +1,827 @@
|
||||
/*
|
||||
* Copyright 2015-2018 _floragunn_ GmbH
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Portions Copyright 2019 Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License").
|
||||
* You may not use this file except in compliance with the License.
|
||||
* A copy of the License is located at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* or in the "license" file accompanying this file. This file is distributed
|
||||
* on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
|
||||
* express or implied. See the License for the specific language governing
|
||||
* permissions and limitations under the License.
|
||||
*/
|
||||
|
||||
package com.amazon.opendistroforelasticsearch.security.ssl;
|
||||
|
||||
import io.netty.buffer.PooledByteBufAllocator;
|
||||
import io.netty.handler.ssl.ApplicationProtocolConfig;
|
||||
import io.netty.handler.ssl.ClientAuth;
|
||||
import io.netty.handler.ssl.OpenSsl;
|
||||
import io.netty.handler.ssl.SslContext;
|
||||
import io.netty.handler.ssl.SslContextBuilder;
|
||||
import io.netty.handler.ssl.SslProvider;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.LinkOption;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.Paths;
|
||||
import java.security.AccessController;
|
||||
import java.security.KeyStore;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
import java.security.PrivateKey;
|
||||
import java.security.PrivilegedActionException;
|
||||
import java.security.PrivilegedExceptionAction;
|
||||
import java.security.cert.X509Certificate;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
import java.util.Set;
|
||||
|
||||
import javax.crypto.Cipher;
|
||||
import javax.net.ssl.SSLContext;
|
||||
import javax.net.ssl.SSLEngine;
|
||||
import javax.net.ssl.SSLException;
|
||||
import javax.net.ssl.SSLParameters;
|
||||
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
import org.elasticsearch.ElasticsearchException;
|
||||
import org.elasticsearch.ElasticsearchSecurityException;
|
||||
import org.elasticsearch.SpecialPermission;
|
||||
import org.elasticsearch.common.settings.Settings;
|
||||
import org.elasticsearch.env.Environment;
|
||||
|
||||
import com.amazon.opendistroforelasticsearch.security.ssl.util.ExceptionUtils;
|
||||
import com.amazon.opendistroforelasticsearch.security.ssl.util.SSLCertificateHelper;
|
||||
import com.amazon.opendistroforelasticsearch.security.ssl.util.SSLConfigConstants;
|
||||
|
||||
public class DefaultOpenDistroSecurityKeyStore implements OpenDistroSecurityKeyStore {
|
||||
|
||||
private static final String DEFAULT_STORE_TYPE = "JKS";
|
||||
|
||||
private void printJCEWarnings() {
|
||||
try {
|
||||
final int aesMaxKeyLength = Cipher.getMaxAllowedKeyLength("AES");
|
||||
|
||||
if (aesMaxKeyLength < 256) {
|
||||
log.info("AES-256 not supported, max key length for AES is " + aesMaxKeyLength + " bit."
|
||||
+ " (This is not an issue, it just limits possible encryption strength. To enable AES 256, install 'Java Cryptography Extension (JCE) Unlimited Strength Jurisdiction Policy Files')");
|
||||
}
|
||||
} catch (final NoSuchAlgorithmException e) {
|
||||
log.error("AES encryption not supported (Security 1). " + e);
|
||||
}
|
||||
}
|
||||
|
||||
private final Settings settings;
|
||||
private final Logger log = LogManager.getLogger(this.getClass());
|
||||
public final SslProvider sslHTTPProvider;
|
||||
public final SslProvider sslTransportServerProvider;
|
||||
public final SslProvider sslTransportClientProvider;
|
||||
private final boolean httpSSLEnabled;
|
||||
private final boolean transportSSLEnabled;
|
||||
|
||||
private List<String> enabledHttpCiphersJDKProvider;
|
||||
private List<String> enabledHttpCiphersOpenSSLProvider;
|
||||
private List<String> enabledTransportCiphersJDKProvider;
|
||||
private List<String> enabledTransportCiphersOpenSSLProvider;
|
||||
|
||||
private List<String> enabledHttpProtocolsJDKProvider;
|
||||
private List<String> enabledHttpProtocolsOpenSSLProvider;
|
||||
private List<String> enabledTransportProtocolsJDKProvider;
|
||||
private List<String> enabledTransportProtocolsOpenSSLProvider;
|
||||
|
||||
private SslContext httpSslContext;
|
||||
private SslContext transportServerSslContext;
|
||||
private SslContext transportClientSslContext;
|
||||
private final Environment env;
|
||||
|
||||
public DefaultOpenDistroSecurityKeyStore(final Settings settings, final Path configPath) {
|
||||
super();
|
||||
this.settings = settings;
|
||||
Environment _env;
|
||||
try {
|
||||
_env = new Environment(settings, configPath);
|
||||
} catch (IllegalStateException e) {
|
||||
_env = null;
|
||||
}
|
||||
env = _env;
|
||||
httpSSLEnabled = settings.getAsBoolean(SSLConfigConstants.OPENDISTRO_SECURITY_SSL_HTTP_ENABLED,
|
||||
SSLConfigConstants.OPENDISTRO_SECURITY_SSL_HTTP_ENABLED_DEFAULT);
|
||||
transportSSLEnabled = settings.getAsBoolean(SSLConfigConstants.OPENDISTRO_SECURITY_SSL_TRANSPORT_ENABLED,
|
||||
SSLConfigConstants.OPENDISTRO_SECURITY_SSL_TRANSPORT_ENABLED_DEFAULT);
|
||||
final boolean useOpenSSLForHttpIfAvailable = settings
|
||||
.getAsBoolean(SSLConfigConstants.OPENDISTRO_SECURITY_SSL_HTTP_ENABLE_OPENSSL_IF_AVAILABLE, true);
|
||||
final boolean useOpenSSLForTransportIfAvailable = settings
|
||||
.getAsBoolean(SSLConfigConstants.OPENDISTRO_SECURITY_SSL_TRANSPORT_ENABLE_OPENSSL_IF_AVAILABLE, true);
|
||||
|
||||
boolean openSSLInfoLogged = false;
|
||||
|
||||
if (httpSSLEnabled && useOpenSSLForHttpIfAvailable) {
|
||||
sslHTTPProvider = SslContext.defaultServerProvider();
|
||||
logOpenSSLInfos();
|
||||
openSSLInfoLogged = true;
|
||||
} else if (httpSSLEnabled) {
|
||||
sslHTTPProvider = SslProvider.JDK;
|
||||
} else {
|
||||
sslHTTPProvider = null;
|
||||
}
|
||||
|
||||
if (transportSSLEnabled && useOpenSSLForTransportIfAvailable) {
|
||||
sslTransportClientProvider = SslContext.defaultClientProvider();
|
||||
sslTransportServerProvider = SslContext.defaultServerProvider();
|
||||
if (!openSSLInfoLogged) {
|
||||
logOpenSSLInfos();
|
||||
}
|
||||
} else if (transportSSLEnabled) {
|
||||
sslTransportClientProvider = sslTransportServerProvider = SslProvider.JDK;
|
||||
} else {
|
||||
sslTransportClientProvider = sslTransportServerProvider = null;
|
||||
}
|
||||
|
||||
initEnabledSSLCiphers();
|
||||
initSSLConfig();
|
||||
printJCEWarnings();
|
||||
|
||||
log.info("TLS Transport Client Provider : {}", sslTransportClientProvider);
|
||||
log.info("TLS Transport Server Provider : {}", sslTransportServerProvider);
|
||||
log.info("TLS HTTP Provider : {}", sslHTTPProvider);
|
||||
|
||||
log.debug("sslTransportClientProvider:{} with ciphers {}", sslTransportClientProvider,
|
||||
getEnabledSSLCiphers(sslTransportClientProvider, false));
|
||||
log.debug("sslTransportServerProvider:{} with ciphers {}", sslTransportServerProvider,
|
||||
getEnabledSSLCiphers(sslTransportServerProvider, false));
|
||||
log.debug("sslHTTPProvider:{} with ciphers {}", sslHTTPProvider, getEnabledSSLCiphers(sslHTTPProvider, true));
|
||||
|
||||
log.info("Enabled TLS protocols for transport layer : {}",
|
||||
Arrays.toString(getEnabledSSLProtocols(sslTransportServerProvider, false)));
|
||||
log.info("Enabled TLS protocols for HTTP layer : {}",
|
||||
Arrays.toString(getEnabledSSLProtocols(sslHTTPProvider, true)));
|
||||
|
||||
|
||||
log.debug("sslTransportClientProvider:{} with protocols {}", sslTransportClientProvider,
|
||||
getEnabledSSLProtocols(sslTransportClientProvider, false));
|
||||
log.debug("sslTransportServerProvider:{} with protocols {}", sslTransportServerProvider,
|
||||
getEnabledSSLProtocols(sslTransportServerProvider, false));
|
||||
log.debug("sslHTTPProvider:{} with protocols {}", sslHTTPProvider, getEnabledSSLProtocols(sslHTTPProvider, true));
|
||||
|
||||
if (transportSSLEnabled && (getEnabledSSLCiphers(sslTransportClientProvider, false).isEmpty()
|
||||
|| getEnabledSSLCiphers(sslTransportServerProvider, false).isEmpty())) {
|
||||
throw new ElasticsearchSecurityException("no valid cipher suites for transport protocol");
|
||||
}
|
||||
|
||||
if (httpSSLEnabled && getEnabledSSLCiphers(sslHTTPProvider, true).isEmpty()) {
|
||||
throw new ElasticsearchSecurityException("no valid cipher suites for https");
|
||||
}
|
||||
|
||||
if (transportSSLEnabled && getEnabledSSLCiphers(sslTransportServerProvider, false).isEmpty()) {
|
||||
throw new ElasticsearchSecurityException("no ssl protocols for transport protocol");
|
||||
}
|
||||
|
||||
if (transportSSLEnabled && getEnabledSSLCiphers(sslTransportClientProvider, false).isEmpty()) {
|
||||
throw new ElasticsearchSecurityException("no ssl protocols for transport protocol");
|
||||
}
|
||||
|
||||
if (httpSSLEnabled && getEnabledSSLCiphers(sslHTTPProvider, true).isEmpty()) {
|
||||
throw new ElasticsearchSecurityException("no ssl protocols for https");
|
||||
}
|
||||
}
|
||||
|
||||
private String resolve(String propName, boolean mustBeValid) {
|
||||
|
||||
final String originalPath = settings.get(propName, null);
|
||||
String path = originalPath;
|
||||
log.debug("Value for {} is {}", propName, originalPath);
|
||||
|
||||
if (env != null && originalPath != null && originalPath.length() > 0) {
|
||||
path = env.configFile().resolve(originalPath).toAbsolutePath().toString();
|
||||
log.debug("Resolved {} to {} against {}", originalPath, path, env.configFile().toAbsolutePath().toString());
|
||||
}
|
||||
|
||||
if (mustBeValid) {
|
||||
checkPath(path, propName);
|
||||
}
|
||||
|
||||
if ("".equals(path)) {
|
||||
path = null;
|
||||
}
|
||||
|
||||
return path;
|
||||
}
|
||||
|
||||
private void initSSLConfig() {
|
||||
|
||||
if (env == null) {
|
||||
log.info("No config directory, key- and truststore files are resolved absolutely");
|
||||
} else {
|
||||
log.info("Config directory is {}/, from there the key- and truststore files are resolved relatively",
|
||||
env.configFile().toAbsolutePath());
|
||||
}
|
||||
|
||||
if (transportSSLEnabled) {
|
||||
|
||||
final String rawKeyStoreFilePath = settings
|
||||
.get(SSLConfigConstants.OPENDISTRO_SECURITY_SSL_TRANSPORT_KEYSTORE_FILEPATH, null);
|
||||
final String rawPemCertFilePath = settings
|
||||
.get(SSLConfigConstants.OPENDISTRO_SECURITY_SSL_TRANSPORT_PEMCERT_FILEPATH, null);
|
||||
|
||||
if (rawKeyStoreFilePath != null) {
|
||||
|
||||
final String keystoreFilePath = resolve(SSLConfigConstants.OPENDISTRO_SECURITY_SSL_TRANSPORT_KEYSTORE_FILEPATH,
|
||||
true);
|
||||
final String keystoreType = settings.get(SSLConfigConstants.OPENDISTRO_SECURITY_SSL_TRANSPORT_KEYSTORE_TYPE,
|
||||
DEFAULT_STORE_TYPE);
|
||||
final String keystorePassword = settings.get(
|
||||
SSLConfigConstants.OPENDISTRO_SECURITY_SSL_TRANSPORT_KEYSTORE_PASSWORD,
|
||||
SSLConfigConstants.DEFAULT_STORE_PASSWORD);
|
||||
final String keystoreAlias = settings.get(SSLConfigConstants.OPENDISTRO_SECURITY_SSL_TRANSPORT_KEYSTORE_ALIAS,
|
||||
null);
|
||||
|
||||
final String truststoreFilePath = resolve(
|
||||
SSLConfigConstants.OPENDISTRO_SECURITY_SSL_TRANSPORT_TRUSTSTORE_FILEPATH, true);
|
||||
|
||||
if (settings.get(SSLConfigConstants.OPENDISTRO_SECURITY_SSL_TRANSPORT_TRUSTSTORE_FILEPATH, null) == null) {
|
||||
throw new ElasticsearchException(SSLConfigConstants.OPENDISTRO_SECURITY_SSL_TRANSPORT_TRUSTSTORE_FILEPATH
|
||||
+ " must be set if transport ssl is requested.");
|
||||
}
|
||||
|
||||
final String truststoreType = settings.get(SSLConfigConstants.OPENDISTRO_SECURITY_SSL_TRANSPORT_TRUSTSTORE_TYPE,
|
||||
DEFAULT_STORE_TYPE);
|
||||
final String truststorePassword = settings.get(
|
||||
SSLConfigConstants.OPENDISTRO_SECURITY_SSL_TRANSPORT_TRUSTSTORE_PASSWORD,
|
||||
SSLConfigConstants.DEFAULT_STORE_PASSWORD);
|
||||
final String truststoreAlias = settings
|
||||
.get(SSLConfigConstants.OPENDISTRO_SECURITY_SSL_TRANSPORT_TRUSTSTORE_ALIAS, null);
|
||||
|
||||
try {
|
||||
|
||||
final KeyStore ks = KeyStore.getInstance(keystoreType);
|
||||
ks.load(new FileInputStream(new File(keystoreFilePath)),
|
||||
(keystorePassword == null || keystorePassword.length() == 0) ? null
|
||||
: keystorePassword.toCharArray());
|
||||
|
||||
final X509Certificate[] transportKeystoreCert = SSLCertificateHelper.exportServerCertChain(ks,
|
||||
keystoreAlias);
|
||||
final PrivateKey transportKeystoreKey = SSLCertificateHelper.exportDecryptedKey(ks, keystoreAlias,
|
||||
(keystorePassword == null || keystorePassword.length() == 0) ? null
|
||||
: keystorePassword.toCharArray());
|
||||
|
||||
if (transportKeystoreKey == null) {
|
||||
throw new ElasticsearchException(
|
||||
"No key found in " + keystoreFilePath + " with alias " + keystoreAlias);
|
||||
}
|
||||
|
||||
if (transportKeystoreCert != null && transportKeystoreCert.length > 0) {
|
||||
|
||||
// TODO create sensitive log property
|
||||
/*
|
||||
* for (int i = 0; i < transportKeystoreCert.length; i++) { X509Certificate
|
||||
* x509Certificate = transportKeystoreCert[i];
|
||||
*
|
||||
* if(x509Certificate != null) {
|
||||
* log.info("Transport keystore subject DN no. {} {}",i,x509Certificate.
|
||||
* getSubjectX500Principal()); } }
|
||||
*/
|
||||
} else {
|
||||
throw new ElasticsearchException(
|
||||
"No certificates found in " + keystoreFilePath + " with alias " + keystoreAlias);
|
||||
}
|
||||
|
||||
final KeyStore ts = KeyStore.getInstance(truststoreType);
|
||||
ts.load(new FileInputStream(new File(truststoreFilePath)),
|
||||
(truststorePassword == null || truststorePassword.length() == 0) ? null
|
||||
: truststorePassword.toCharArray());
|
||||
|
||||
final X509Certificate[] trustedTransportCertificates = SSLCertificateHelper
|
||||
.exportRootCertificates(ts, truststoreAlias);
|
||||
|
||||
if (trustedTransportCertificates == null) {
|
||||
throw new ElasticsearchException("No truststore configured for server");
|
||||
}
|
||||
|
||||
transportServerSslContext = buildSSLServerContext(transportKeystoreKey, transportKeystoreCert,
|
||||
trustedTransportCertificates, getEnabledSSLCiphers(this.sslTransportServerProvider, false),
|
||||
this.sslTransportServerProvider, ClientAuth.REQUIRE);
|
||||
transportClientSslContext = buildSSLClientContext(transportKeystoreKey, transportKeystoreCert,
|
||||
trustedTransportCertificates, getEnabledSSLCiphers(sslTransportClientProvider, false),
|
||||
sslTransportClientProvider);
|
||||
|
||||
} catch (final Exception e) {
|
||||
logExplanation(e);
|
||||
throw new ElasticsearchSecurityException(
|
||||
"Error while initializing transport SSL layer: " + e.toString(), e);
|
||||
}
|
||||
|
||||
} else if (rawPemCertFilePath != null) {
|
||||
|
||||
final String pemCertFilePath = resolve(SSLConfigConstants.OPENDISTRO_SECURITY_SSL_TRANSPORT_PEMCERT_FILEPATH,
|
||||
true);
|
||||
final String pemKey = resolve(SSLConfigConstants.OPENDISTRO_SECURITY_SSL_TRANSPORT_PEMKEY_FILEPATH, true);
|
||||
final String trustedCas = resolve(SSLConfigConstants.OPENDISTRO_SECURITY_SSL_TRANSPORT_PEMTRUSTEDCAS_FILEPATH,
|
||||
true);
|
||||
|
||||
try {
|
||||
|
||||
transportServerSslContext = buildSSLServerContext(new File(pemKey), new File(pemCertFilePath),
|
||||
new File(trustedCas),
|
||||
settings.get(SSLConfigConstants.OPENDISTRO_SECURITY_SSL_TRANSPORT_PEMKEY_PASSWORD),
|
||||
getEnabledSSLCiphers(this.sslTransportServerProvider, false),
|
||||
this.sslTransportServerProvider, ClientAuth.REQUIRE);
|
||||
transportClientSslContext = buildSSLClientContext(new File(pemKey), new File(pemCertFilePath),
|
||||
new File(trustedCas),
|
||||
settings.get(SSLConfigConstants.OPENDISTRO_SECURITY_SSL_TRANSPORT_PEMKEY_PASSWORD),
|
||||
getEnabledSSLCiphers(sslTransportClientProvider, false), sslTransportClientProvider);
|
||||
|
||||
} catch (final Exception e) {
|
||||
logExplanation(e);
|
||||
throw new ElasticsearchSecurityException(
|
||||
"Error while initializing transport SSL layer from PEM: " + e.toString(), e);
|
||||
}
|
||||
|
||||
} else {
|
||||
throw new ElasticsearchException(SSLConfigConstants.OPENDISTRO_SECURITY_SSL_TRANSPORT_KEYSTORE_FILEPATH + " or "
|
||||
+ SSLConfigConstants.OPENDISTRO_SECURITY_SSL_TRANSPORT_PEMKEY_FILEPATH
|
||||
+ " must be set if transport ssl is reqested.");
|
||||
}
|
||||
}
|
||||
|
||||
final boolean client = !"node".equals(this.settings.get(OpenDistroSecuritySSLPlugin.CLIENT_TYPE));
|
||||
|
||||
if (!client && httpSSLEnabled) {
|
||||
|
||||
final String rawKeystoreFilePath = settings.get(SSLConfigConstants.OPENDISTRO_SECURITY_SSL_HTTP_KEYSTORE_FILEPATH,
|
||||
null);
|
||||
final String rawPemCertFilePath = settings.get(SSLConfigConstants.OPENDISTRO_SECURITY_SSL_HTTP_PEMCERT_FILEPATH,
|
||||
null);
|
||||
final ClientAuth httpClientAuthMode = ClientAuth.valueOf(settings
|
||||
.get(SSLConfigConstants.OPENDISTRO_SECURITY_SSL_HTTP_CLIENTAUTH_MODE, ClientAuth.OPTIONAL.toString()));
|
||||
|
||||
if (rawKeystoreFilePath != null) {
|
||||
|
||||
final String keystoreFilePath = resolve(SSLConfigConstants.OPENDISTRO_SECURITY_SSL_HTTP_KEYSTORE_FILEPATH,
|
||||
true);
|
||||
final String keystoreType = settings.get(SSLConfigConstants.OPENDISTRO_SECURITY_SSL_HTTP_KEYSTORE_TYPE,
|
||||
DEFAULT_STORE_TYPE);
|
||||
final String keystorePassword = settings.get(SSLConfigConstants.OPENDISTRO_SECURITY_SSL_HTTP_KEYSTORE_PASSWORD,
|
||||
SSLConfigConstants.DEFAULT_STORE_PASSWORD);
|
||||
final String keystoreAlias = settings.get(SSLConfigConstants.OPENDISTRO_SECURITY_SSL_HTTP_KEYSTORE_ALIAS, null);
|
||||
|
||||
log.info("HTTPS client auth mode {}", httpClientAuthMode);
|
||||
|
||||
if (settings.get(SSLConfigConstants.OPENDISTRO_SECURITY_SSL_HTTP_KEYSTORE_FILEPATH, null) == null) {
|
||||
throw new ElasticsearchException(SSLConfigConstants.OPENDISTRO_SECURITY_SSL_HTTP_KEYSTORE_FILEPATH
|
||||
+ " must be set if https is reqested.");
|
||||
}
|
||||
|
||||
if (httpClientAuthMode == ClientAuth.REQUIRE) {
|
||||
|
||||
if (settings.get(SSLConfigConstants.OPENDISTRO_SECURITY_SSL_HTTP_TRUSTSTORE_FILEPATH, null) == null) {
|
||||
throw new ElasticsearchException(SSLConfigConstants.OPENDISTRO_SECURITY_SSL_HTTP_TRUSTSTORE_FILEPATH
|
||||
+ " must be set if http ssl and client auth is reqested.");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
try {
|
||||
|
||||
final KeyStore ks = KeyStore.getInstance(keystoreType);
|
||||
try (FileInputStream fin = new FileInputStream(new File(keystoreFilePath))) {
|
||||
ks.load(fin, (keystorePassword == null || keystorePassword.length() == 0) ? null
|
||||
: keystorePassword.toCharArray());
|
||||
}
|
||||
|
||||
final X509Certificate[] httpKeystoreCert = SSLCertificateHelper.exportServerCertChain(ks,
|
||||
keystoreAlias);
|
||||
final PrivateKey httpKeystoreKey = SSLCertificateHelper.exportDecryptedKey(ks, keystoreAlias,
|
||||
(keystorePassword == null || keystorePassword.length() == 0) ? null
|
||||
: keystorePassword.toCharArray());
|
||||
|
||||
if (httpKeystoreKey == null) {
|
||||
throw new ElasticsearchException(
|
||||
"No key found in " + keystoreFilePath + " with alias " + keystoreAlias);
|
||||
}
|
||||
|
||||
if (httpKeystoreCert != null && httpKeystoreCert.length > 0) {
|
||||
|
||||
// TODO create sensitive log property
|
||||
/*
|
||||
* for (int i = 0; i < httpKeystoreCert.length; i++) { X509Certificate
|
||||
* x509Certificate = httpKeystoreCert[i];
|
||||
*
|
||||
* if(x509Certificate != null) {
|
||||
* log.info("HTTP keystore subject DN no. {} {}",i,x509Certificate.
|
||||
* getSubjectX500Principal()); } }
|
||||
*/
|
||||
} else {
|
||||
throw new ElasticsearchException(
|
||||
"No certificates found in " + keystoreFilePath + " with alias " + keystoreAlias);
|
||||
}
|
||||
|
||||
X509Certificate[] trustedHTTPCertificates = null;
|
||||
|
||||
if (settings.get(SSLConfigConstants.OPENDISTRO_SECURITY_SSL_HTTP_TRUSTSTORE_FILEPATH, null) != null) {
|
||||
|
||||
final String truststoreFilePath = resolve(
|
||||
SSLConfigConstants.OPENDISTRO_SECURITY_SSL_HTTP_TRUSTSTORE_FILEPATH, true);
|
||||
|
||||
final String truststoreType = settings
|
||||
.get(SSLConfigConstants.OPENDISTRO_SECURITY_SSL_HTTP_TRUSTSTORE_TYPE, DEFAULT_STORE_TYPE);
|
||||
final String truststorePassword = settings.get(
|
||||
SSLConfigConstants.OPENDISTRO_SECURITY_SSL_HTTP_TRUSTSTORE_PASSWORD,
|
||||
SSLConfigConstants.DEFAULT_STORE_PASSWORD);
|
||||
final String truststoreAlias = settings
|
||||
.get(SSLConfigConstants.OPENDISTRO_SECURITY_SSL_HTTP_TRUSTSTORE_ALIAS, null);
|
||||
|
||||
final KeyStore ts = KeyStore.getInstance(truststoreType);
|
||||
try (FileInputStream fin = new FileInputStream(new File(truststoreFilePath))) {
|
||||
ts.load(fin, (truststorePassword == null || truststorePassword.length() == 0) ? null
|
||||
: truststorePassword.toCharArray());
|
||||
}
|
||||
trustedHTTPCertificates = SSLCertificateHelper.exportRootCertificates(ts, truststoreAlias);
|
||||
}
|
||||
|
||||
httpSslContext = buildSSLServerContext(httpKeystoreKey, httpKeystoreCert, trustedHTTPCertificates,
|
||||
getEnabledSSLCiphers(this.sslHTTPProvider, true), sslHTTPProvider, httpClientAuthMode);
|
||||
|
||||
} catch (final Exception e) {
|
||||
logExplanation(e);
|
||||
throw new ElasticsearchSecurityException("Error while initializing HTTP SSL layer: " + e.toString(),
|
||||
e);
|
||||
}
|
||||
|
||||
} else if (rawPemCertFilePath != null) {
|
||||
|
||||
final String trustedCas = resolve(SSLConfigConstants.OPENDISTRO_SECURITY_SSL_HTTP_PEMTRUSTEDCAS_FILEPATH,
|
||||
false);
|
||||
|
||||
if (httpClientAuthMode == ClientAuth.REQUIRE) {
|
||||
|
||||
// if(trustedCas == null ||
|
||||
// trustedCas.equals(env.config-File().toAbsolutePath().toString())) {
|
||||
// throw new
|
||||
// ElasticsearchException(SSLConfigConstants.OPENDISTRO_SECURITY_SSL_HTTP_PEMTRUSTEDCAS_FILEPATH
|
||||
// + " must be set if http ssl and client auth is reqested.");
|
||||
// }
|
||||
|
||||
checkPath(trustedCas, SSLConfigConstants.OPENDISTRO_SECURITY_SSL_HTTP_PEMTRUSTEDCAS_FILEPATH);
|
||||
|
||||
}
|
||||
|
||||
final String pemCertFilePath = resolve(SSLConfigConstants.OPENDISTRO_SECURITY_SSL_HTTP_PEMCERT_FILEPATH, true);
|
||||
final String pemKey = resolve(SSLConfigConstants.OPENDISTRO_SECURITY_SSL_HTTP_PEMKEY_FILEPATH, true);
|
||||
|
||||
try {
|
||||
httpSslContext = buildSSLServerContext(new File(pemKey), new File(pemCertFilePath),
|
||||
trustedCas == null ? null : new File(trustedCas),
|
||||
settings.get(SSLConfigConstants.OPENDISTRO_SECURITY_SSL_HTTP_PEMKEY_PASSWORD),
|
||||
getEnabledSSLCiphers(this.sslHTTPProvider, true), sslHTTPProvider, httpClientAuthMode);
|
||||
} catch (final Exception e) {
|
||||
logExplanation(e);
|
||||
throw new ElasticsearchSecurityException(
|
||||
"Error while initializing http SSL layer from PEM: " + e.toString(), e);
|
||||
}
|
||||
|
||||
} else {
|
||||
throw new ElasticsearchException(SSLConfigConstants.OPENDISTRO_SECURITY_SSL_HTTP_KEYSTORE_FILEPATH + " or "
|
||||
+ SSLConfigConstants.OPENDISTRO_SECURITY_SSL_HTTP_PEMKEY_FILEPATH
|
||||
+ " must be set if http ssl is reqested.");
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
public SSLEngine createHTTPSSLEngine() throws SSLException {
|
||||
|
||||
final SSLEngine engine = httpSslContext.newEngine(PooledByteBufAllocator.DEFAULT);
|
||||
engine.setEnabledProtocols(getEnabledSSLProtocols(this.sslHTTPProvider, true));
|
||||
return engine;
|
||||
|
||||
}
|
||||
|
||||
public SSLEngine createServerTransportSSLEngine() throws SSLException {
|
||||
|
||||
final SSLEngine engine = transportServerSslContext.newEngine(PooledByteBufAllocator.DEFAULT);
|
||||
engine.setEnabledProtocols(getEnabledSSLProtocols(this.sslTransportServerProvider, false));
|
||||
return engine;
|
||||
|
||||
}
|
||||
|
||||
public SSLEngine createClientTransportSSLEngine(final String peerHost, final int peerPort) throws SSLException {
|
||||
|
||||
if (peerHost != null) {
|
||||
final SSLEngine engine = transportClientSslContext.newEngine(PooledByteBufAllocator.DEFAULT, peerHost,
|
||||
peerPort);
|
||||
|
||||
final SSLParameters sslParams = new SSLParameters();
|
||||
sslParams.setEndpointIdentificationAlgorithm("HTTPS");
|
||||
engine.setSSLParameters(sslParams);
|
||||
engine.setEnabledProtocols(getEnabledSSLProtocols(this.sslTransportClientProvider, false));
|
||||
return engine;
|
||||
} else {
|
||||
final SSLEngine engine = transportClientSslContext.newEngine(PooledByteBufAllocator.DEFAULT);
|
||||
engine.setEnabledProtocols(getEnabledSSLProtocols(this.sslTransportClientProvider, false));
|
||||
return engine;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getHTTPProviderName() {
|
||||
return sslHTTPProvider == null ? null : sslHTTPProvider.toString();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getTransportServerProviderName() {
|
||||
return sslTransportServerProvider == null ? null : sslTransportServerProvider.toString();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getTransportClientProviderName() {
|
||||
return sslTransportClientProvider == null ? null : sslTransportClientProvider.toString();
|
||||
}
|
||||
|
||||
private void logOpenSSLInfos() {
|
||||
if (OpenSsl.isAvailable()) {
|
||||
log.info("OpenSSL " + OpenSsl.versionString() + " (" + OpenSsl.version() + ") available");
|
||||
|
||||
if (OpenSsl.version() < 0x10002000L) {
|
||||
log.warn(
|
||||
"Outdated OpenSSL version detected. You should update to 1.0.2k or later. Currently installed: "
|
||||
+ OpenSsl.versionString());
|
||||
}
|
||||
|
||||
if (!OpenSsl.supportsHostnameValidation()) {
|
||||
log.warn("Your OpenSSL version " + OpenSsl.versionString()
|
||||
+ " does not support hostname verification. You should update to 1.0.2k or later.");
|
||||
}
|
||||
|
||||
log.debug("OpenSSL available ciphers " + OpenSsl.availableOpenSslCipherSuites());
|
||||
} else {
|
||||
log.info("OpenSSL not available (this is not an error, we simply fallback to built-in JDK SSL) because of "
|
||||
+ OpenSsl.unavailabilityCause());
|
||||
}
|
||||
}
|
||||
|
||||
private List<String> getEnabledSSLCiphers(final SslProvider provider, boolean http) {
|
||||
if (provider == null) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
if (http) {
|
||||
return provider == SslProvider.JDK ? enabledHttpCiphersJDKProvider : enabledHttpCiphersOpenSSLProvider;
|
||||
} else {
|
||||
return provider == SslProvider.JDK ? enabledTransportCiphersJDKProvider
|
||||
: enabledTransportCiphersOpenSSLProvider;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private String[] getEnabledSSLProtocols(final SslProvider provider, boolean http) {
|
||||
if (provider == null) {
|
||||
return new String[0];
|
||||
}
|
||||
|
||||
if (http) {
|
||||
return (provider == SslProvider.JDK ? enabledHttpProtocolsJDKProvider : enabledHttpProtocolsOpenSSLProvider).toArray(new String[0]);
|
||||
} else {
|
||||
return (provider == SslProvider.JDK ? enabledTransportProtocolsJDKProvider
|
||||
: enabledTransportProtocolsOpenSSLProvider).toArray(new String[0]);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private void initEnabledSSLCiphers() {
|
||||
|
||||
final List<String> secureHttpSSLCiphers = SSLConfigConstants.getSecureSSLCiphers(settings, true);
|
||||
final List<String> secureTransportSSLCiphers = SSLConfigConstants.getSecureSSLCiphers(settings, false);
|
||||
final List<String> secureHttpSSLProtocols = Arrays.asList(SSLConfigConstants.getSecureSSLProtocols(settings, true));
|
||||
final List<String> secureTransportSSLProtocols = Arrays.asList(SSLConfigConstants.getSecureSSLProtocols(settings, false));
|
||||
|
||||
if (OpenSsl.isAvailable()) {
|
||||
final Set<String> openSSLSecureHttpCiphers = new HashSet<>();
|
||||
for (final String secure : secureHttpSSLCiphers) {
|
||||
if (OpenSsl.isCipherSuiteAvailable(secure)) {
|
||||
openSSLSecureHttpCiphers.add(secure);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
log.debug("OPENSSL "+OpenSsl.versionString()+" supports the following ciphers (java-style) {}", OpenSsl.availableJavaCipherSuites());
|
||||
log.debug("OPENSSL "+OpenSsl.versionString()+" supports the following ciphers (openssl-style) {}", OpenSsl.availableOpenSslCipherSuites());
|
||||
|
||||
enabledHttpCiphersOpenSSLProvider = Collections
|
||||
.unmodifiableList(new ArrayList<String>(openSSLSecureHttpCiphers));
|
||||
} else {
|
||||
enabledHttpCiphersOpenSSLProvider = Collections.emptyList();
|
||||
}
|
||||
|
||||
if (OpenSsl.isAvailable()) {
|
||||
final Set<String> openSSLSecureTransportCiphers = new HashSet<>();
|
||||
for (final String secure : secureTransportSSLCiphers) {
|
||||
if (OpenSsl.isCipherSuiteAvailable(secure)) {
|
||||
openSSLSecureTransportCiphers.add(secure);
|
||||
}
|
||||
}
|
||||
|
||||
enabledTransportCiphersOpenSSLProvider = Collections
|
||||
.unmodifiableList(new ArrayList<String>(openSSLSecureTransportCiphers));
|
||||
} else {
|
||||
enabledTransportCiphersOpenSSLProvider = Collections.emptyList();
|
||||
}
|
||||
|
||||
if(OpenSsl.isAvailable() && OpenSsl.version() > 0x10101009L) {
|
||||
enabledHttpProtocolsOpenSSLProvider = new ArrayList(Arrays.asList("TLSv1.3","TLSv1.2","TLSv1.1"));
|
||||
enabledHttpProtocolsOpenSSLProvider.retainAll(secureHttpSSLProtocols);
|
||||
enabledTransportProtocolsOpenSSLProvider = new ArrayList(Arrays.asList("TLSv1.3","TLSv1.2","TLSv1.1"));
|
||||
enabledTransportProtocolsOpenSSLProvider.retainAll(secureTransportSSLProtocols);
|
||||
|
||||
log.info("OpenSSL supports TLSv1.3");
|
||||
|
||||
} else if(OpenSsl.isAvailable()){
|
||||
enabledHttpProtocolsOpenSSLProvider = new ArrayList(Arrays.asList("TLSv1.2","TLSv1.1"));
|
||||
enabledHttpProtocolsOpenSSLProvider.retainAll(secureHttpSSLProtocols);
|
||||
enabledTransportProtocolsOpenSSLProvider = new ArrayList(Arrays.asList("TLSv1.2","TLSv1.1"));
|
||||
enabledTransportProtocolsOpenSSLProvider.retainAll(secureTransportSSLProtocols);
|
||||
} else {
|
||||
enabledHttpProtocolsOpenSSLProvider = Collections.emptyList();
|
||||
enabledTransportProtocolsOpenSSLProvider = Collections.emptyList();
|
||||
}
|
||||
|
||||
SSLEngine engine = null;
|
||||
List<String> jdkSupportedCiphers = null;
|
||||
List<String> jdkSupportedProtocols = null;
|
||||
try {
|
||||
final SSLContext serverContext = SSLContext.getInstance("TLS");
|
||||
serverContext.init(null, null, null);
|
||||
engine = serverContext.createSSLEngine();
|
||||
jdkSupportedCiphers = Arrays.asList(engine.getEnabledCipherSuites());
|
||||
jdkSupportedProtocols = Arrays.asList(engine.getEnabledProtocols());
|
||||
log.debug("JVM supports the following {} protocols {}", jdkSupportedProtocols.size(),
|
||||
jdkSupportedProtocols);
|
||||
log.debug("JVM supports the following {} ciphers {}", jdkSupportedCiphers.size(),
|
||||
jdkSupportedCiphers);
|
||||
|
||||
if(jdkSupportedProtocols.contains("TLSv1.3")) {
|
||||
log.info("JVM supports TLSv1.3");
|
||||
}
|
||||
|
||||
} catch (final Throwable e) {
|
||||
log.error("Unable to determine supported ciphers due to " + e, e);
|
||||
} finally {
|
||||
if (engine != null) {
|
||||
try {
|
||||
engine.closeInbound();
|
||||
} catch (SSLException e) {
|
||||
log.debug("Unable to close inbound ssl engine", e);
|
||||
}
|
||||
engine.closeOutbound();
|
||||
}
|
||||
}
|
||||
|
||||
if(jdkSupportedCiphers == null || jdkSupportedCiphers.isEmpty() || jdkSupportedProtocols == null || jdkSupportedProtocols.isEmpty()) {
|
||||
throw new ElasticsearchException("Unable to determine supported ciphers or protocols");
|
||||
}
|
||||
|
||||
enabledHttpCiphersJDKProvider = new ArrayList<String>(jdkSupportedCiphers);
|
||||
enabledHttpCiphersJDKProvider.retainAll(secureHttpSSLCiphers);
|
||||
|
||||
enabledTransportCiphersJDKProvider = new ArrayList<String>(jdkSupportedCiphers);
|
||||
enabledTransportCiphersJDKProvider.retainAll(secureTransportSSLCiphers);
|
||||
|
||||
enabledHttpProtocolsJDKProvider = new ArrayList<String>(jdkSupportedProtocols);
|
||||
enabledHttpProtocolsJDKProvider.retainAll(secureHttpSSLProtocols);
|
||||
|
||||
enabledTransportProtocolsJDKProvider = new ArrayList<String>(jdkSupportedProtocols);
|
||||
enabledTransportProtocolsJDKProvider.retainAll(secureTransportSSLProtocols);
|
||||
}
|
||||
|
||||
private SslContext buildSSLServerContext(final PrivateKey _key, final X509Certificate[] _cert,
|
||||
final X509Certificate[] _trustedCerts, final Iterable<String> ciphers, final SslProvider sslProvider,
|
||||
final ClientAuth authMode) throws SSLException {
|
||||
|
||||
final SslContextBuilder _sslContextBuilder = SslContextBuilder.forServer(_key, _cert).ciphers(ciphers)
|
||||
.applicationProtocolConfig(ApplicationProtocolConfig.DISABLED)
|
||||
.clientAuth(Objects.requireNonNull(authMode)) // https://github.com/netty/netty/issues/4722
|
||||
.sessionCacheSize(0).sessionTimeout(0).sslProvider(sslProvider);
|
||||
|
||||
if (_trustedCerts != null && _trustedCerts.length > 0) {
|
||||
_sslContextBuilder.trustManager(_trustedCerts);
|
||||
}
|
||||
|
||||
return buildSSLContext0(_sslContextBuilder);
|
||||
}
|
||||
|
||||
private SslContext buildSSLServerContext(final File _key, final File _cert, final File _trustedCerts,
|
||||
final String pwd, final Iterable<String> ciphers, final SslProvider sslProvider, final ClientAuth authMode)
|
||||
throws SSLException {
|
||||
|
||||
final SslContextBuilder _sslContextBuilder = SslContextBuilder.forServer(_cert, _key, pwd).ciphers(ciphers)
|
||||
.applicationProtocolConfig(ApplicationProtocolConfig.DISABLED)
|
||||
.clientAuth(Objects.requireNonNull(authMode)) // https://github.com/netty/netty/issues/4722
|
||||
.sessionCacheSize(0).sessionTimeout(0).sslProvider(sslProvider);
|
||||
|
||||
if (_trustedCerts != null) {
|
||||
_sslContextBuilder.trustManager(_trustedCerts);
|
||||
}
|
||||
|
||||
return buildSSLContext0(_sslContextBuilder);
|
||||
}
|
||||
|
||||
private SslContext buildSSLClientContext(final PrivateKey _key, final X509Certificate[] _cert,
|
||||
final X509Certificate[] _trustedCerts, final Iterable<String> ciphers, final SslProvider sslProvider)
|
||||
throws SSLException {
|
||||
|
||||
final SslContextBuilder _sslClientContextBuilder = SslContextBuilder.forClient().ciphers(ciphers)
|
||||
.applicationProtocolConfig(ApplicationProtocolConfig.DISABLED).sessionCacheSize(0).sessionTimeout(0)
|
||||
.sslProvider(sslProvider).trustManager(_trustedCerts).keyManager(_key, _cert);
|
||||
|
||||
return buildSSLContext0(_sslClientContextBuilder);
|
||||
|
||||
}
|
||||
|
||||
private SslContext buildSSLClientContext(final File _key, final File _cert, final File _trustedCerts,
|
||||
final String pwd, final Iterable<String> ciphers, final SslProvider sslProvider) throws SSLException {
|
||||
|
||||
final SslContextBuilder _sslClientContextBuilder = SslContextBuilder.forClient().ciphers(ciphers)
|
||||
.applicationProtocolConfig(ApplicationProtocolConfig.DISABLED).sessionCacheSize(0).sessionTimeout(0)
|
||||
.sslProvider(sslProvider).trustManager(_trustedCerts).keyManager(_cert, _key, pwd);
|
||||
|
||||
return buildSSLContext0(_sslClientContextBuilder);
|
||||
|
||||
}
|
||||
|
||||
private SslContext buildSSLContext0(final SslContextBuilder sslContextBuilder) throws SSLException {
|
||||
|
||||
final SecurityManager sm = System.getSecurityManager();
|
||||
|
||||
if (sm != null) {
|
||||
sm.checkPermission(new SpecialPermission());
|
||||
}
|
||||
|
||||
SslContext sslContext = null;
|
||||
try {
|
||||
sslContext = AccessController.doPrivileged(new PrivilegedExceptionAction<SslContext>() {
|
||||
@Override
|
||||
public SslContext run() throws Exception {
|
||||
return sslContextBuilder.build();
|
||||
}
|
||||
});
|
||||
} catch (final PrivilegedActionException e) {
|
||||
throw (SSLException) e.getCause();
|
||||
}
|
||||
|
||||
return sslContext;
|
||||
}
|
||||
|
||||
private void logExplanation(Exception e) {
|
||||
if (ExceptionUtils.findMsg(e, "not contain valid private key") != null) {
|
||||
log.error("Your keystore or PEM does not contain a key. "
|
||||
+ "If you specified a key password, try removing it. "
|
||||
+ "If you did not specify a key password, perhaps you need to if the key is in fact password-protected. "
|
||||
+ "Maybe you just confused keys and certificates.");
|
||||
}
|
||||
|
||||
if (ExceptionUtils.findMsg(e, "not contain valid certificates") != null) {
|
||||
log.error("Your keystore or PEM does not contain a certificate. Maybe you confused keys and certificates.");
|
||||
}
|
||||
}
|
||||
|
||||
private static void checkPath(String keystoreFilePath, String fileNameLogOnly) {
|
||||
|
||||
if (keystoreFilePath == null || keystoreFilePath.length() == 0) {
|
||||
throw new ElasticsearchException("Empty file path for " + fileNameLogOnly);
|
||||
}
|
||||
|
||||
if (Files.isDirectory(Paths.get(keystoreFilePath), LinkOption.NOFOLLOW_LINKS)) {
|
||||
throw new ElasticsearchException(
|
||||
"Is a directory: " + keystoreFilePath + " Expected a file for " + fileNameLogOnly);
|
||||
}
|
||||
|
||||
if (!Files.isReadable(Paths.get(keystoreFilePath))) {
|
||||
throw new ElasticsearchException("Unable to read " + keystoreFilePath + " (" + Paths.get(keystoreFilePath)
|
||||
+ "). Please make sure this files exists and is readable regarding to permissions. Property: "
|
||||
+ fileNameLogOnly);
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,152 @@
|
||||
/*
|
||||
* Copyright 2015-2018 _floragunn_ GmbH
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Portions Copyright 2019 Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License").
|
||||
* You may not use this file except in compliance with the License.
|
||||
* A copy of the License is located at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* or in the "license" file accompanying this file. This file is distributed
|
||||
* on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
|
||||
* express or implied. See the License for the specific language governing
|
||||
* permissions and limitations under the License.
|
||||
*/
|
||||
|
||||
package com.amazon.opendistroforelasticsearch.security.ssl;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
import javax.net.ssl.SSLContext;
|
||||
import javax.net.ssl.SSLEngine;
|
||||
import javax.net.ssl.SSLException;
|
||||
import javax.net.ssl.SSLParameters;
|
||||
|
||||
import org.elasticsearch.ElasticsearchException;
|
||||
import org.elasticsearch.common.settings.Settings;
|
||||
|
||||
import com.amazon.opendistroforelasticsearch.security.ssl.util.SSLConfigConstants;
|
||||
|
||||
public class ExternalOpenDistroSecurityKeyStore implements OpenDistroSecurityKeyStore {
|
||||
|
||||
private static final String EXTERNAL = "EXTERNAL";
|
||||
private static final Map<String, SSLContext> contextMap = new ConcurrentHashMap<String, SSLContext>();
|
||||
private final SSLContext externalSslContext;
|
||||
private final Settings settings;
|
||||
|
||||
public ExternalOpenDistroSecurityKeyStore(final Settings settings) {
|
||||
this.settings = Objects.requireNonNull(settings);
|
||||
final String externalContextId = settings
|
||||
.get(SSLConfigConstants.OPENDISTRO_SECURITY_SSL_CLIENT_EXTERNAL_CONTEXT_ID, null);
|
||||
|
||||
if(externalContextId == null || externalContextId.length() == 0) {
|
||||
throw new ElasticsearchException("no external ssl context id was set");
|
||||
}
|
||||
|
||||
externalSslContext = contextMap.get(externalContextId);
|
||||
|
||||
if(externalSslContext == null) {
|
||||
throw new ElasticsearchException("no external ssl context for id "+externalContextId);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public SSLEngine createHTTPSSLEngine() throws SSLException {
|
||||
throw new SSLException("not implemented");
|
||||
}
|
||||
|
||||
@Override
|
||||
public SSLEngine createServerTransportSSLEngine() throws SSLException {
|
||||
throw new SSLException("not implemented");
|
||||
}
|
||||
|
||||
@Override
|
||||
public SSLEngine createClientTransportSSLEngine(final String peerHost, final int peerPort) throws SSLException {
|
||||
if (peerHost != null) {
|
||||
final SSLEngine engine = externalSslContext.createSSLEngine(peerHost, peerPort);
|
||||
final SSLParameters sslParams = new SSLParameters();
|
||||
sslParams.setEndpointIdentificationAlgorithm("HTTPS");
|
||||
engine.setSSLParameters(sslParams);
|
||||
engine.setEnabledProtocols(evalSecure(engine.getEnabledProtocols(), SSLConfigConstants.getSecureSSLProtocols(settings, false)));
|
||||
engine.setEnabledCipherSuites(evalSecure(engine.getEnabledCipherSuites(), SSLConfigConstants.getSecureSSLCiphers(settings, false).toArray(new String[0])));
|
||||
engine.setUseClientMode(true);
|
||||
return engine;
|
||||
} else {
|
||||
final SSLEngine engine = externalSslContext.createSSLEngine();
|
||||
engine.setEnabledProtocols(evalSecure(engine.getEnabledProtocols(), SSLConfigConstants.getSecureSSLProtocols(settings, false)));
|
||||
engine.setEnabledCipherSuites(evalSecure(engine.getEnabledCipherSuites(), SSLConfigConstants.getSecureSSLCiphers(settings, false).toArray(new String[0])));
|
||||
engine.setUseClientMode(true);
|
||||
return engine;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getHTTPProviderName() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getTransportServerProviderName() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getTransportClientProviderName() {
|
||||
return EXTERNAL;
|
||||
}
|
||||
|
||||
public static void registerExternalSslContext(String id, SSLContext externalSsslContext) {
|
||||
contextMap.put(Objects.requireNonNull(id), Objects.requireNonNull(externalSsslContext));
|
||||
}
|
||||
|
||||
public static boolean hasExternalSslContext(Settings settings) {
|
||||
|
||||
final String externalContextId = settings
|
||||
.get(SSLConfigConstants.OPENDISTRO_SECURITY_SSL_CLIENT_EXTERNAL_CONTEXT_ID, null);
|
||||
|
||||
if(externalContextId == null || externalContextId.length() == 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return contextMap.containsKey(externalContextId);
|
||||
}
|
||||
|
||||
public static boolean hasExternalSslContext(String id) {
|
||||
return contextMap.containsKey(id);
|
||||
}
|
||||
|
||||
public static void removeExternalSslContext(String id) {
|
||||
contextMap.remove(id);
|
||||
}
|
||||
|
||||
public static void removeAllExternalSslContexts() {
|
||||
contextMap.clear();
|
||||
}
|
||||
|
||||
private String[] evalSecure(String[] engineEnabled, String[] secure) {
|
||||
List<String> tmp = new ArrayList<>(Arrays.asList(engineEnabled));
|
||||
tmp.retainAll(Arrays.asList(secure));
|
||||
return tmp.toArray(new String[0]);
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,48 @@
|
||||
/*
|
||||
* Copyright 2015-2018 _floragunn_ GmbH
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Portions Copyright 2019 Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License").
|
||||
* You may not use this file except in compliance with the License.
|
||||
* A copy of the License is located at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* or in the "license" file accompanying this file. This file is distributed
|
||||
* on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
|
||||
* express or implied. See the License for the specific language governing
|
||||
* permissions and limitations under the License.
|
||||
*/
|
||||
|
||||
package com.amazon.opendistroforelasticsearch.security.ssl;
|
||||
|
||||
import javax.net.ssl.SSLEngine;
|
||||
import javax.net.ssl.SSLException;
|
||||
|
||||
public interface OpenDistroSecurityKeyStore {
|
||||
|
||||
public SSLEngine createHTTPSSLEngine() throws SSLException;
|
||||
|
||||
public SSLEngine createServerTransportSSLEngine() throws SSLException;
|
||||
|
||||
public SSLEngine createClientTransportSSLEngine(String peerHost, int peerPort) throws SSLException;
|
||||
|
||||
public String getHTTPProviderName();
|
||||
public String getTransportServerProviderName();
|
||||
public String getTransportClientProviderName();
|
||||
|
||||
}
|
@ -0,0 +1,385 @@
|
||||
/*
|
||||
* Copyright 2015-2018 _floragunn_ GmbH
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Portions Copyright 2019 Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License").
|
||||
* You may not use this file except in compliance with the License.
|
||||
* A copy of the License is located at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* or in the "license" file accompanying this file. This file is distributed
|
||||
* on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
|
||||
* express or implied. See the License for the specific language governing
|
||||
* permissions and limitations under the License.
|
||||
*/
|
||||
|
||||
package com.amazon.opendistroforelasticsearch.security.ssl;
|
||||
|
||||
import io.netty.handler.ssl.OpenSsl;
|
||||
import io.netty.util.internal.PlatformDependent;
|
||||
|
||||
import java.nio.file.Path;
|
||||
import java.security.AccessController;
|
||||
import java.security.PrivilegedAction;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.function.Function;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
import org.elasticsearch.ElasticsearchException;
|
||||
import org.elasticsearch.SpecialPermission;
|
||||
import org.elasticsearch.client.Client;
|
||||
import org.elasticsearch.cluster.metadata.IndexNameExpressionResolver;
|
||||
import org.elasticsearch.cluster.node.DiscoveryNodes;
|
||||
import org.elasticsearch.cluster.service.ClusterService;
|
||||
import org.elasticsearch.common.io.stream.NamedWriteableRegistry;
|
||||
import org.elasticsearch.common.network.NetworkModule;
|
||||
import org.elasticsearch.common.network.NetworkService;
|
||||
import org.elasticsearch.common.settings.ClusterSettings;
|
||||
import org.elasticsearch.common.settings.IndexScopedSettings;
|
||||
import org.elasticsearch.common.settings.Setting;
|
||||
import org.elasticsearch.common.settings.Setting.Property;
|
||||
import org.elasticsearch.common.settings.Settings;
|
||||
import org.elasticsearch.common.settings.SettingsFilter;
|
||||
import org.elasticsearch.common.util.BigArrays;
|
||||
import org.elasticsearch.common.util.PageCacheRecycler;
|
||||
import org.elasticsearch.common.util.concurrent.ThreadContext;
|
||||
import org.elasticsearch.common.xcontent.NamedXContentRegistry;
|
||||
import org.elasticsearch.env.Environment;
|
||||
import org.elasticsearch.env.NodeEnvironment;
|
||||
import org.elasticsearch.http.HttpServerTransport;
|
||||
import org.elasticsearch.http.HttpServerTransport.Dispatcher;
|
||||
import org.elasticsearch.indices.breaker.CircuitBreakerService;
|
||||
import org.elasticsearch.plugins.ActionPlugin;
|
||||
import org.elasticsearch.plugins.NetworkPlugin;
|
||||
import org.elasticsearch.plugins.Plugin;
|
||||
import org.elasticsearch.rest.RestController;
|
||||
import org.elasticsearch.rest.RestHandler;
|
||||
import org.elasticsearch.script.ScriptService;
|
||||
import org.elasticsearch.threadpool.ThreadPool;
|
||||
import org.elasticsearch.transport.Transport;
|
||||
import org.elasticsearch.transport.TransportInterceptor;
|
||||
import org.elasticsearch.watcher.ResourceWatcherService;
|
||||
|
||||
import com.amazon.opendistroforelasticsearch.security.ssl.http.netty.OpenDistroSecuritySSLNettyHttpServerTransport;
|
||||
import com.amazon.opendistroforelasticsearch.security.ssl.http.netty.ValidatingDispatcher;
|
||||
import com.amazon.opendistroforelasticsearch.security.ssl.rest.OpenDistroSecuritySSLInfoAction;
|
||||
import com.amazon.opendistroforelasticsearch.security.ssl.transport.OpenDistroSecuritySSLNettyTransport;
|
||||
import com.amazon.opendistroforelasticsearch.security.ssl.transport.OpenDistroSecuritySSLTransportInterceptor;
|
||||
import com.amazon.opendistroforelasticsearch.security.ssl.transport.PrincipalExtractor;
|
||||
import com.amazon.opendistroforelasticsearch.security.ssl.util.SSLConfigConstants;
|
||||
|
||||
//For ES5 this class has only effect when SSL only plugin is installed
|
||||
public class OpenDistroSecuritySSLPlugin extends Plugin implements ActionPlugin, NetworkPlugin {
|
||||
|
||||
protected final Logger log = LogManager.getLogger(this.getClass());
|
||||
protected static final String CLIENT_TYPE = "client.type";
|
||||
protected final boolean client;
|
||||
protected final boolean httpSSLEnabled;
|
||||
protected final boolean transportSSLEnabled;
|
||||
protected final Settings settings;
|
||||
protected final OpenDistroSecurityKeyStore odsks;
|
||||
protected PrincipalExtractor principalExtractor;
|
||||
protected final Path configPath;
|
||||
private final static SslExceptionHandler NOOP_SSL_EXCEPTION_HANDLER = new SslExceptionHandler() {};
|
||||
|
||||
public OpenDistroSecuritySSLPlugin(final Settings settings, final Path configPath) {
|
||||
this(settings, configPath, false);
|
||||
}
|
||||
|
||||
protected OpenDistroSecuritySSLPlugin(final Settings settings, final Path configPath, boolean disabled) {
|
||||
|
||||
if(disabled) {
|
||||
this.settings = null;
|
||||
this.client = false;
|
||||
this.httpSSLEnabled = false;
|
||||
this.transportSSLEnabled = false;
|
||||
this.odsks = null;
|
||||
this.configPath = null;
|
||||
|
||||
AccessController.doPrivileged(new PrivilegedAction<Object>() {
|
||||
@Override
|
||||
public Object run() {
|
||||
System.setProperty("es.set.netty.runtime.available.processors", "false");
|
||||
return null;
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
this.configPath = configPath;
|
||||
|
||||
if(this.configPath != null) {
|
||||
log.info("ES Config path is "+this.configPath.toAbsolutePath());
|
||||
} else {
|
||||
log.info("ES Config path is not set");
|
||||
}
|
||||
|
||||
final boolean allowClientInitiatedRenegotiation = settings.getAsBoolean(SSLConfigConstants.OPENDISTRO_SECURITY_SSL_ALLOW_CLIENT_INITIATED_RENEGOTIATION, false);
|
||||
final boolean rejectClientInitiatedRenegotiation = Boolean.parseBoolean(System.getProperty(SSLConfigConstants.JDK_TLS_REJECT_CLIENT_INITIATED_RENEGOTIATION));
|
||||
|
||||
if(allowClientInitiatedRenegotiation && !rejectClientInitiatedRenegotiation) {
|
||||
final String renegoMsg = "Client side initiated TLS renegotiation enabled. This can open a vulnerablity for DoS attacks through client side initiated TLS renegotiation.";
|
||||
log.warn(renegoMsg);
|
||||
System.out.println(renegoMsg);
|
||||
System.err.println(renegoMsg);
|
||||
} else {
|
||||
if(!rejectClientInitiatedRenegotiation) {
|
||||
|
||||
final SecurityManager sm = System.getSecurityManager();
|
||||
|
||||
if (sm != null) {
|
||||
sm.checkPermission(new SpecialPermission());
|
||||
}
|
||||
|
||||
AccessController.doPrivileged(new PrivilegedAction<Object>() {
|
||||
@Override
|
||||
public Object run() {
|
||||
System.setProperty(SSLConfigConstants.JDK_TLS_REJECT_CLIENT_INITIATED_RENEGOTIATION, "true");
|
||||
return null;
|
||||
}
|
||||
});
|
||||
log.debug("Client side initiated TLS renegotiation forcibly disabled. This can prevent DoS attacks. (jdk.tls.rejectClientInitiatedRenegotiation set to true).");
|
||||
} else {
|
||||
log.debug("Client side initiated TLS renegotiation already disabled.");
|
||||
}
|
||||
}
|
||||
|
||||
final SecurityManager sm = System.getSecurityManager();
|
||||
|
||||
if (sm != null) {
|
||||
sm.checkPermission(new SpecialPermission());
|
||||
}
|
||||
|
||||
//TODO check initialize native netty open ssl libs still neccessary
|
||||
AccessController.doPrivileged(new PrivilegedAction<Object>() {
|
||||
@Override
|
||||
public Object run() {
|
||||
System.setProperty("es.set.netty.runtime.available.processors", "false");
|
||||
PlatformDependent.newFixedMpscQueue(1);
|
||||
OpenSsl.isAvailable();
|
||||
return null;
|
||||
}
|
||||
});
|
||||
|
||||
this.settings = settings;
|
||||
client = !"node".equals(this.settings.get(OpenDistroSecuritySSLPlugin.CLIENT_TYPE));
|
||||
|
||||
httpSSLEnabled = settings.getAsBoolean(SSLConfigConstants.OPENDISTRO_SECURITY_SSL_HTTP_ENABLED,
|
||||
SSLConfigConstants.OPENDISTRO_SECURITY_SSL_HTTP_ENABLED_DEFAULT);
|
||||
transportSSLEnabled = settings.getAsBoolean(SSLConfigConstants.OPENDISTRO_SECURITY_SSL_TRANSPORT_ENABLED,
|
||||
SSLConfigConstants.OPENDISTRO_SECURITY_SSL_TRANSPORT_ENABLED_DEFAULT);
|
||||
|
||||
if (!httpSSLEnabled && !transportSSLEnabled) {
|
||||
log.error("SSL not activated for http and/or transport.");
|
||||
System.out.println("SSL not activated for http and/or transport.");
|
||||
System.err.println("SSL not activated for http and/or transport.");
|
||||
}
|
||||
|
||||
if(ExternalOpenDistroSecurityKeyStore.hasExternalSslContext(settings)) {
|
||||
this.odsks = new ExternalOpenDistroSecurityKeyStore(settings);
|
||||
} else {
|
||||
this.odsks = new DefaultOpenDistroSecurityKeyStore(settings, configPath);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
@Override
|
||||
public Map<String, Supplier<HttpServerTransport>> getHttpTransports(Settings settings, ThreadPool threadPool, BigArrays bigArrays,
|
||||
CircuitBreakerService circuitBreakerService, NamedWriteableRegistry namedWriteableRegistry,
|
||||
NamedXContentRegistry xContentRegistry, NetworkService networkService, Dispatcher dispatcher) {
|
||||
|
||||
final Map<String, Supplier<HttpServerTransport>> httpTransports = new HashMap<String, Supplier<HttpServerTransport>>(1);
|
||||
if (!client && httpSSLEnabled) {
|
||||
|
||||
final ValidatingDispatcher validatingDispatcher = new ValidatingDispatcher(threadPool.getThreadContext(), dispatcher, settings, configPath, NOOP_SSL_EXCEPTION_HANDLER);
|
||||
final OpenDistroSecuritySSLNettyHttpServerTransport sgsnht = new OpenDistroSecuritySSLNettyHttpServerTransport(settings, networkService, bigArrays, threadPool, odsks, xContentRegistry, validatingDispatcher, NOOP_SSL_EXCEPTION_HANDLER);
|
||||
|
||||
httpTransports.put("com.amazon.opendistroforelasticsearch.security.ssl.http.netty.OpenDistroSecuritySSLNettyHttpServerTransport", () -> sgsnht);
|
||||
|
||||
}
|
||||
return httpTransports;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<RestHandler> getRestHandlers(Settings settings, RestController restController, ClusterSettings clusterSettings,
|
||||
IndexScopedSettings indexScopedSettings, SettingsFilter settingsFilter,
|
||||
IndexNameExpressionResolver indexNameExpressionResolver, Supplier<DiscoveryNodes> nodesInCluster) {
|
||||
|
||||
final List<RestHandler> handlers = new ArrayList<RestHandler>(1);
|
||||
|
||||
if (!client) {
|
||||
handlers.add(new OpenDistroSecuritySSLInfoAction(settings, configPath, restController, odsks, Objects.requireNonNull(principalExtractor)));
|
||||
}
|
||||
|
||||
return handlers;
|
||||
}
|
||||
|
||||
|
||||
|
||||
@Override
|
||||
public List<TransportInterceptor> getTransportInterceptors(NamedWriteableRegistry namedWriteableRegistry, ThreadContext threadContext) {
|
||||
List<TransportInterceptor> interceptors = new ArrayList<TransportInterceptor>(1);
|
||||
|
||||
if(transportSSLEnabled && !client) {
|
||||
interceptors.add(new OpenDistroSecuritySSLTransportInterceptor(settings, null, null, NOOP_SSL_EXCEPTION_HANDLER));
|
||||
}
|
||||
|
||||
return interceptors;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public Map<String, Supplier<Transport>> getTransports(Settings settings, ThreadPool threadPool, BigArrays bigArrays,
|
||||
PageCacheRecycler pageCacheRecycler, CircuitBreakerService circuitBreakerService,
|
||||
NamedWriteableRegistry namedWriteableRegistry, NetworkService networkService) {
|
||||
|
||||
Map<String, Supplier<Transport>> transports = new HashMap<String, Supplier<Transport>>();
|
||||
if (transportSSLEnabled) {
|
||||
transports.put("com.amazon.opendistroforelasticsearch.security.ssl.http.netty.OpenDistroSecuritySSLNettyTransport",
|
||||
() -> new OpenDistroSecuritySSLNettyTransport(settings, threadPool, networkService, bigArrays, namedWriteableRegistry, circuitBreakerService, odsks, NOOP_SSL_EXCEPTION_HANDLER));
|
||||
}
|
||||
return transports;
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
@Override
|
||||
public Collection<Object> createComponents(Client localClient, ClusterService clusterService, ThreadPool threadPool,
|
||||
ResourceWatcherService resourceWatcherService, ScriptService scriptService, NamedXContentRegistry xContentRegistry,
|
||||
Environment environment, NodeEnvironment nodeEnvironment, NamedWriteableRegistry namedWriteableRegistry) {
|
||||
|
||||
final List<Object> components = new ArrayList<>(1);
|
||||
|
||||
if(client) {
|
||||
return components;
|
||||
}
|
||||
|
||||
final String principalExtractorClass = settings.get(SSLConfigConstants.OPENDISTRO_SECURITY_SSL_TRANSPORT_PRINCIPAL_EXTRACTOR_CLASS, null);
|
||||
|
||||
if(principalExtractorClass == null) {
|
||||
principalExtractor = new com.amazon.opendistroforelasticsearch.security.ssl.transport.DefaultPrincipalExtractor();
|
||||
} else {
|
||||
try {
|
||||
log.debug("Try to load and instantiate '{}'", principalExtractorClass);
|
||||
Class<?> principalExtractorClazz = Class.forName(principalExtractorClass);
|
||||
principalExtractor = (PrincipalExtractor) principalExtractorClazz.newInstance();
|
||||
} catch (Exception e) {
|
||||
log.error("Unable to load '{}' due to", principalExtractorClass, e);
|
||||
throw new ElasticsearchException(e);
|
||||
}
|
||||
}
|
||||
|
||||
components.add(principalExtractor);
|
||||
|
||||
return components;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Setting<?>> getSettings() {
|
||||
List<Setting<?>> settings = new ArrayList<Setting<?>>();
|
||||
settings.add(Setting.simpleString(SSLConfigConstants.OPENDISTRO_SECURITY_SSL_HTTP_CLIENTAUTH_MODE, Property.NodeScope, Property.Filtered));
|
||||
settings.add(Setting.simpleString(SSLConfigConstants.OPENDISTRO_SECURITY_SSL_HTTP_KEYSTORE_ALIAS, Property.NodeScope, Property.Filtered));
|
||||
settings.add(Setting.simpleString(SSLConfigConstants.OPENDISTRO_SECURITY_SSL_HTTP_KEYSTORE_FILEPATH, Property.NodeScope, Property.Filtered));
|
||||
settings.add(Setting.simpleString(SSLConfigConstants.OPENDISTRO_SECURITY_SSL_HTTP_KEYSTORE_PASSWORD, Property.NodeScope, Property.Filtered));
|
||||
settings.add(Setting.simpleString(SSLConfigConstants.OPENDISTRO_SECURITY_SSL_HTTP_KEYSTORE_TYPE, Property.NodeScope, Property.Filtered));
|
||||
settings.add(Setting.simpleString(SSLConfigConstants.OPENDISTRO_SECURITY_SSL_HTTP_TRUSTSTORE_ALIAS, Property.NodeScope, Property.Filtered));
|
||||
settings.add(Setting.simpleString(SSLConfigConstants.OPENDISTRO_SECURITY_SSL_HTTP_TRUSTSTORE_FILEPATH, Property.NodeScope, Property.Filtered));
|
||||
settings.add(Setting.simpleString(SSLConfigConstants.OPENDISTRO_SECURITY_SSL_HTTP_TRUSTSTORE_PASSWORD, Property.NodeScope, Property.Filtered));
|
||||
settings.add(Setting.simpleString(SSLConfigConstants.OPENDISTRO_SECURITY_SSL_HTTP_TRUSTSTORE_TYPE, Property.NodeScope, Property.Filtered));
|
||||
settings.add(Setting.boolSetting(SSLConfigConstants.OPENDISTRO_SECURITY_SSL_HTTP_ENABLE_OPENSSL_IF_AVAILABLE, true, Property.NodeScope, Property.Filtered));
|
||||
settings.add(Setting.boolSetting(SSLConfigConstants.OPENDISTRO_SECURITY_SSL_HTTP_ENABLED, SSLConfigConstants.OPENDISTRO_SECURITY_SSL_HTTP_ENABLED_DEFAULT, Property.NodeScope, Property.Filtered));
|
||||
settings.add(Setting.boolSetting(SSLConfigConstants.OPENDISTRO_SECURITY_SSL_TRANSPORT_ENABLE_OPENSSL_IF_AVAILABLE, true,Property.NodeScope, Property.Filtered));
|
||||
settings.add(Setting.boolSetting(SSLConfigConstants.OPENDISTRO_SECURITY_SSL_TRANSPORT_ENABLED, SSLConfigConstants.OPENDISTRO_SECURITY_SSL_TRANSPORT_ENABLED_DEFAULT, Property.NodeScope, Property.Filtered));
|
||||
settings.add(Setting.boolSetting(SSLConfigConstants.OPENDISTRO_SECURITY_SSL_TRANSPORT_ENFORCE_HOSTNAME_VERIFICATION, true, Property.NodeScope, Property.Filtered));
|
||||
settings.add(Setting.boolSetting(SSLConfigConstants.OPENDISTRO_SECURITY_SSL_TRANSPORT_ENFORCE_HOSTNAME_VERIFICATION_RESOLVE_HOST_NAME, true, Property.NodeScope, Property.Filtered));
|
||||
settings.add(Setting.simpleString(SSLConfigConstants.OPENDISTRO_SECURITY_SSL_TRANSPORT_KEYSTORE_ALIAS, Property.NodeScope, Property.Filtered));
|
||||
settings.add(Setting.simpleString(SSLConfigConstants.OPENDISTRO_SECURITY_SSL_TRANSPORT_KEYSTORE_FILEPATH, Property.NodeScope, Property.Filtered));
|
||||
settings.add(Setting.simpleString(SSLConfigConstants.OPENDISTRO_SECURITY_SSL_TRANSPORT_KEYSTORE_PASSWORD, Property.NodeScope, Property.Filtered));
|
||||
settings.add(Setting.simpleString(SSLConfigConstants.OPENDISTRO_SECURITY_SSL_TRANSPORT_KEYSTORE_TYPE, Property.NodeScope, Property.Filtered));
|
||||
settings.add(Setting.simpleString(SSLConfigConstants.OPENDISTRO_SECURITY_SSL_TRANSPORT_TRUSTSTORE_ALIAS, Property.NodeScope, Property.Filtered));
|
||||
settings.add(Setting.simpleString(SSLConfigConstants.OPENDISTRO_SECURITY_SSL_TRANSPORT_TRUSTSTORE_FILEPATH, Property.NodeScope, Property.Filtered));
|
||||
settings.add(Setting.simpleString(SSLConfigConstants.OPENDISTRO_SECURITY_SSL_TRANSPORT_TRUSTSTORE_PASSWORD, Property.NodeScope, Property.Filtered));
|
||||
settings.add(Setting.simpleString(SSLConfigConstants.OPENDISTRO_SECURITY_SSL_TRANSPORT_TRUSTSTORE_TYPE, Property.NodeScope, Property.Filtered));
|
||||
settings.add(Setting.listSetting(SSLConfigConstants.OPENDISTRO_SECURITY_SSL_HTTP_ENABLED_CIPHERS, Collections.emptyList(), Function.identity(), Property.NodeScope));//not filtered here
|
||||
settings.add(Setting.listSetting(SSLConfigConstants.OPENDISTRO_SECURITY_SSL_HTTP_ENABLED_PROTOCOLS, Collections.emptyList(), Function.identity(), Property.NodeScope));//not filtered here
|
||||
settings.add(Setting.listSetting(SSLConfigConstants.OPENDISTRO_SECURITY_SSL_TRANSPORT_ENABLED_CIPHERS, Collections.emptyList(), Function.identity(), Property.NodeScope));//not filtered here
|
||||
settings.add(Setting.listSetting(SSLConfigConstants.OPENDISTRO_SECURITY_SSL_TRANSPORT_ENABLED_PROTOCOLS, Collections.emptyList(), Function.identity(), Property.NodeScope));//not filtered here
|
||||
settings.add(Setting.simpleString(SSLConfigConstants.OPENDISTRO_SECURITY_SSL_CLIENT_EXTERNAL_CONTEXT_ID, Property.NodeScope, Property.Filtered));
|
||||
settings.add(Setting.simpleString(SSLConfigConstants.OPENDISTRO_SECURITY_SSL_TRANSPORT_PRINCIPAL_EXTRACTOR_CLASS, Property.NodeScope, Property.Filtered));
|
||||
|
||||
settings.add(Setting.simpleString(SSLConfigConstants.OPENDISTRO_SECURITY_SSL_TRANSPORT_PEMCERT_FILEPATH, Property.NodeScope, Property.Filtered));
|
||||
settings.add(Setting.simpleString(SSLConfigConstants.OPENDISTRO_SECURITY_SSL_TRANSPORT_PEMKEY_FILEPATH, Property.NodeScope, Property.Filtered));
|
||||
settings.add(Setting.simpleString(SSLConfigConstants.OPENDISTRO_SECURITY_SSL_TRANSPORT_PEMKEY_PASSWORD, Property.NodeScope, Property.Filtered));
|
||||
settings.add(Setting.simpleString(SSLConfigConstants.OPENDISTRO_SECURITY_SSL_TRANSPORT_PEMTRUSTEDCAS_FILEPATH, Property.NodeScope, Property.Filtered));
|
||||
|
||||
settings.add(Setting.simpleString(SSLConfigConstants.OPENDISTRO_SECURITY_SSL_HTTP_PEMCERT_FILEPATH, Property.NodeScope, Property.Filtered));
|
||||
settings.add(Setting.simpleString(SSLConfigConstants.OPENDISTRO_SECURITY_SSL_HTTP_PEMKEY_FILEPATH, Property.NodeScope, Property.Filtered));
|
||||
settings.add(Setting.simpleString(SSLConfigConstants.OPENDISTRO_SECURITY_SSL_HTTP_PEMKEY_PASSWORD, Property.NodeScope, Property.Filtered));
|
||||
settings.add(Setting.simpleString(SSLConfigConstants.OPENDISTRO_SECURITY_SSL_HTTP_PEMTRUSTEDCAS_FILEPATH, Property.NodeScope, Property.Filtered));
|
||||
|
||||
settings.add(Setting.simpleString(SSLConfigConstants.OPENDISTRO_SECURITY_SSL_HTTP_CRL_FILE, Property.NodeScope, Property.Filtered));
|
||||
settings.add(Setting.boolSetting(SSLConfigConstants.OPENDISTRO_SECURITY_SSL_HTTP_CRL_VALIDATE, false, Property.NodeScope, Property.Filtered));
|
||||
settings.add(Setting.boolSetting(SSLConfigConstants.OPENDISTRO_SECURITY_SSL_HTTP_CRL_PREFER_CRLFILE_OVER_OCSP, false, Property.NodeScope, Property.Filtered));
|
||||
settings.add(Setting.boolSetting(SSLConfigConstants.OPENDISTRO_SECURITY_SSL_HTTP_CRL_CHECK_ONLY_END_ENTITIES, true, Property.NodeScope, Property.Filtered));
|
||||
settings.add(Setting.boolSetting(SSLConfigConstants.OPENDISTRO_SECURITY_SSL_HTTP_CRL_DISABLE_CRLDP, false, Property.NodeScope, Property.Filtered));
|
||||
settings.add(Setting.boolSetting(SSLConfigConstants.OPENDISTRO_SECURITY_SSL_HTTP_CRL_DISABLE_OCSP, false, Property.NodeScope, Property.Filtered));
|
||||
settings.add(Setting.longSetting(SSLConfigConstants.OPENDISTRO_SECURITY_SSL_HTTP_CRL_VALIDATION_DATE, -1, -1, Property.NodeScope, Property.Filtered));
|
||||
return settings;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public Settings additionalSettings() {
|
||||
final Settings.Builder builder = Settings.builder();
|
||||
|
||||
if(!client && httpSSLEnabled) {
|
||||
|
||||
if(settings.get("http.compression") == null) {
|
||||
builder.put("http.compression", false);
|
||||
log.info("Disabled https compression by default to mitigate BREACH attacks. You can enable it by setting 'http.compression: true' in elasticsearch.yml");
|
||||
}
|
||||
|
||||
builder.put(NetworkModule.HTTP_TYPE_KEY, "com.amazon.opendistroforelasticsearch.security.ssl.http.netty.OpenDistroSecuritySSLNettyHttpServerTransport");
|
||||
}
|
||||
|
||||
if (transportSSLEnabled) {
|
||||
builder.put(NetworkModule.TRANSPORT_TYPE_KEY, "com.amazon.opendistroforelasticsearch.security.ssl.http.netty.OpenDistroSecuritySSLNettyTransport");
|
||||
}
|
||||
|
||||
return builder.build();
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<String> getSettingsFilter() {
|
||||
List<String> settingsFilter = new ArrayList<>();
|
||||
settingsFilter.add("opendistro_security.*");
|
||||
return settingsFilter;
|
||||
}
|
||||
}
|
@ -0,0 +1,50 @@
|
||||
/*
|
||||
* Copyright 2015-2018 _floragunn_ GmbH
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Portions Copyright 2019 Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License").
|
||||
* You may not use this file except in compliance with the License.
|
||||
* A copy of the License is located at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* or in the "license" file accompanying this file. This file is distributed
|
||||
* on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
|
||||
* express or implied. See the License for the specific language governing
|
||||
* permissions and limitations under the License.
|
||||
*/
|
||||
|
||||
package com.amazon.opendistroforelasticsearch.security.ssl;
|
||||
|
||||
import org.elasticsearch.rest.RestRequest;
|
||||
import org.elasticsearch.tasks.Task;
|
||||
import org.elasticsearch.transport.TransportRequest;
|
||||
|
||||
public interface SslExceptionHandler {
|
||||
|
||||
default void logError(Throwable t, RestRequest request, int type) {
|
||||
//no-op
|
||||
}
|
||||
|
||||
default void logError(Throwable t, boolean isRest) {
|
||||
//no-op
|
||||
}
|
||||
|
||||
default void logError(Throwable t, final TransportRequest request, String action, Task task, int type) {
|
||||
//no-op
|
||||
}
|
||||
}
|
@ -0,0 +1,116 @@
|
||||
/*
|
||||
* Copyright 2015-2018 _floragunn_ GmbH
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Portions Copyright 2019 Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License").
|
||||
* You may not use this file except in compliance with the License.
|
||||
* A copy of the License is located at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* or in the "license" file accompanying this file. This file is distributed
|
||||
* on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
|
||||
* express or implied. See the License for the specific language governing
|
||||
* permissions and limitations under the License.
|
||||
*/
|
||||
|
||||
package com.amazon.opendistroforelasticsearch.security.ssl.http.netty;
|
||||
|
||||
import io.netty.channel.Channel;
|
||||
import io.netty.channel.ChannelHandler;
|
||||
import io.netty.channel.ChannelHandlerContext;
|
||||
import io.netty.handler.codec.DecoderException;
|
||||
import io.netty.handler.ssl.NotSslRecordException;
|
||||
import io.netty.handler.ssl.SslHandler;
|
||||
|
||||
import javax.net.ssl.SSLException;
|
||||
import javax.net.ssl.SSLHandshakeException;
|
||||
|
||||
import org.elasticsearch.common.network.NetworkService;
|
||||
import org.elasticsearch.common.settings.Settings;
|
||||
import org.elasticsearch.common.util.BigArrays;
|
||||
import org.elasticsearch.common.util.concurrent.ThreadContext;
|
||||
import org.elasticsearch.common.xcontent.NamedXContentRegistry;
|
||||
import org.elasticsearch.http.netty4.Netty4HttpServerTransport;
|
||||
import org.elasticsearch.threadpool.ThreadPool;
|
||||
|
||||
import com.amazon.opendistroforelasticsearch.security.ssl.OpenDistroSecurityKeyStore;
|
||||
import com.amazon.opendistroforelasticsearch.security.ssl.SslExceptionHandler;
|
||||
|
||||
public class OpenDistroSecuritySSLNettyHttpServerTransport extends Netty4HttpServerTransport {
|
||||
|
||||
private final OpenDistroSecurityKeyStore sgks;
|
||||
private final ThreadContext threadContext;
|
||||
private final SslExceptionHandler errorHandler;
|
||||
|
||||
public OpenDistroSecuritySSLNettyHttpServerTransport(final Settings settings, final NetworkService networkService, final BigArrays bigArrays,
|
||||
final ThreadPool threadPool, final OpenDistroSecurityKeyStore sgks, final NamedXContentRegistry namedXContentRegistry, final ValidatingDispatcher dispatcher,
|
||||
final SslExceptionHandler errorHandler) {
|
||||
super(settings, networkService, bigArrays, threadPool, namedXContentRegistry, dispatcher);
|
||||
this.sgks = sgks;
|
||||
this.threadContext = threadPool.getThreadContext();
|
||||
this.errorHandler = errorHandler;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ChannelHandler configureServerChannelHandler() {
|
||||
return new SSLHttpChannelHandler(this, sgks);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected final void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
|
||||
if(this.lifecycle.started()) {
|
||||
|
||||
if(cause instanceof DecoderException && cause != null) {
|
||||
cause = cause.getCause();
|
||||
}
|
||||
|
||||
errorHandler.logError(cause, true);
|
||||
|
||||
if(cause instanceof NotSslRecordException) {
|
||||
logger.warn("Someone ({}) speaks http plaintext instead of ssl, will close the channel", ctx.channel().remoteAddress());
|
||||
ctx.channel().close();
|
||||
return;
|
||||
} else if (cause instanceof SSLException) {
|
||||
logger.error("SSL Problem "+cause.getMessage(),cause);
|
||||
ctx.channel().close();
|
||||
return;
|
||||
} else if (cause instanceof SSLHandshakeException) {
|
||||
logger.error("Problem during handshake "+cause.getMessage());
|
||||
ctx.channel().close();
|
||||
return;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
super.exceptionCaught(ctx, cause);
|
||||
}
|
||||
|
||||
protected class SSLHttpChannelHandler extends Netty4HttpServerTransport.HttpChannelHandler {
|
||||
|
||||
protected SSLHttpChannelHandler(Netty4HttpServerTransport transport, final OpenDistroSecurityKeyStore sgks) {
|
||||
super(transport, OpenDistroSecuritySSLNettyHttpServerTransport.this.detailedErrorsEnabled, OpenDistroSecuritySSLNettyHttpServerTransport.this.threadContext);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void initChannel(Channel ch) throws Exception {
|
||||
super.initChannel(ch);
|
||||
final SslHandler sslHandler = new SslHandler(OpenDistroSecuritySSLNettyHttpServerTransport.this.sgks.createHTTPSSLEngine());
|
||||
ch.pipeline().addFirst("ssl_http", sslHandler);
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,104 @@
|
||||
/*
|
||||
* Copyright 2015-2018 _floragunn_ GmbH
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Portions Copyright 2019 Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License").
|
||||
* You may not use this file except in compliance with the License.
|
||||
* A copy of the License is located at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* or in the "license" file accompanying this file. This file is distributed
|
||||
* on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
|
||||
* express or implied. See the License for the specific language governing
|
||||
* permissions and limitations under the License.
|
||||
*/
|
||||
|
||||
package com.amazon.opendistroforelasticsearch.security.ssl.http.netty;
|
||||
|
||||
import java.nio.file.Path;
|
||||
|
||||
import javax.net.ssl.SSLPeerUnverifiedException;
|
||||
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
import org.elasticsearch.ElasticsearchException;
|
||||
import org.elasticsearch.ElasticsearchSecurityException;
|
||||
import org.elasticsearch.ExceptionsHelper;
|
||||
import org.elasticsearch.common.settings.Settings;
|
||||
import org.elasticsearch.common.util.concurrent.ThreadContext;
|
||||
import org.elasticsearch.http.HttpServerTransport.Dispatcher;
|
||||
import org.elasticsearch.rest.RestChannel;
|
||||
import org.elasticsearch.rest.RestRequest;
|
||||
import org.elasticsearch.rest.RestStatus;
|
||||
|
||||
import com.amazon.opendistroforelasticsearch.security.ssl.SslExceptionHandler;
|
||||
import com.amazon.opendistroforelasticsearch.security.ssl.util.ExceptionUtils;
|
||||
import com.amazon.opendistroforelasticsearch.security.ssl.util.SSLRequestHelper;
|
||||
|
||||
public class ValidatingDispatcher implements Dispatcher {
|
||||
|
||||
private static final Logger logger = LogManager.getLogger(ValidatingDispatcher.class);
|
||||
|
||||
private final ThreadContext threadContext;
|
||||
private final Dispatcher originalDispatcher;
|
||||
private final SslExceptionHandler errorHandler;
|
||||
private final Settings settings;
|
||||
private final Path configPath;
|
||||
|
||||
public ValidatingDispatcher(final ThreadContext threadContext, final Dispatcher originalDispatcher,
|
||||
final Settings settings, final Path configPath, final SslExceptionHandler errorHandler) {
|
||||
super();
|
||||
this.threadContext = threadContext;
|
||||
this.originalDispatcher = originalDispatcher;
|
||||
this.settings = settings;
|
||||
this.configPath = configPath;
|
||||
this.errorHandler = errorHandler;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void dispatchRequest(RestRequest request, RestChannel channel, ThreadContext threadContext) {
|
||||
checkRequest(request, channel);
|
||||
originalDispatcher.dispatchRequest(request, channel, threadContext);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void dispatchBadRequest(RestRequest request, RestChannel channel, ThreadContext threadContext, Throwable cause) {
|
||||
checkRequest(request, channel);
|
||||
originalDispatcher.dispatchBadRequest(request, channel, threadContext, cause);
|
||||
}
|
||||
|
||||
protected void checkRequest(final RestRequest request, final RestChannel channel) {
|
||||
|
||||
if(SSLRequestHelper.containsBadHeader(threadContext, "_opendistro_security_ssl_")) {
|
||||
final ElasticsearchException exception = ExceptionUtils.createBadHeaderException();
|
||||
errorHandler.logError(exception, request, 1);
|
||||
throw exception;
|
||||
}
|
||||
|
||||
try {
|
||||
if(SSLRequestHelper.getSSLInfo(settings, configPath, request, null) == null) {
|
||||
logger.error("Not an SSL request");
|
||||
throw new ElasticsearchSecurityException("Not an SSL request", RestStatus.INTERNAL_SERVER_ERROR);
|
||||
}
|
||||
} catch (SSLPeerUnverifiedException e) {
|
||||
logger.error("No client certificates found but such are needed (Security 8).");
|
||||
errorHandler.logError(e, request, 0);
|
||||
throw ExceptionsHelper.convertToElastic(e);
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,136 @@
|
||||
/*
|
||||
* Copyright 2015-2018 _floragunn_ GmbH
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Portions Copyright 2019 Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License").
|
||||
* You may not use this file except in compliance with the License.
|
||||
* A copy of the License is located at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* or in the "license" file accompanying this file. This file is distributed
|
||||
* on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
|
||||
* express or implied. See the License for the specific language governing
|
||||
* permissions and limitations under the License.
|
||||
*/
|
||||
|
||||
package com.amazon.opendistroforelasticsearch.security.ssl.rest;
|
||||
|
||||
import static org.elasticsearch.rest.RestRequest.Method.GET;
|
||||
import io.netty.handler.ssl.OpenSsl;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.nio.file.Path;
|
||||
import java.security.cert.X509Certificate;
|
||||
import java.util.Arrays;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import org.elasticsearch.client.node.NodeClient;
|
||||
import org.elasticsearch.common.settings.Settings;
|
||||
import org.elasticsearch.common.xcontent.XContentBuilder;
|
||||
import org.elasticsearch.rest.BaseRestHandler;
|
||||
import org.elasticsearch.rest.BytesRestResponse;
|
||||
import org.elasticsearch.rest.RestChannel;
|
||||
import org.elasticsearch.rest.RestController;
|
||||
import org.elasticsearch.rest.RestRequest;
|
||||
import org.elasticsearch.rest.RestStatus;
|
||||
|
||||
import com.amazon.opendistroforelasticsearch.security.ssl.OpenDistroSecurityKeyStore;
|
||||
import com.amazon.opendistroforelasticsearch.security.ssl.transport.PrincipalExtractor;
|
||||
import com.amazon.opendistroforelasticsearch.security.ssl.util.SSLRequestHelper;
|
||||
import com.amazon.opendistroforelasticsearch.security.ssl.util.SSLRequestHelper.SSLInfo;
|
||||
|
||||
public class OpenDistroSecuritySSLInfoAction extends BaseRestHandler {
|
||||
|
||||
private final OpenDistroSecurityKeyStore sgks;
|
||||
final PrincipalExtractor principalExtractor;
|
||||
private final Path configPath;
|
||||
|
||||
public OpenDistroSecuritySSLInfoAction(final Settings settings, final Path configPath, final RestController controller,
|
||||
final OpenDistroSecurityKeyStore sgks, final PrincipalExtractor principalExtractor) {
|
||||
super(settings);
|
||||
this.sgks = sgks;
|
||||
this.principalExtractor = principalExtractor;
|
||||
this.configPath = configPath;
|
||||
controller.registerHandler(GET, "/_opendistro/_security/sslinfo", this);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected RestChannelConsumer prepareRequest(RestRequest request, NodeClient client) throws IOException {
|
||||
return new RestChannelConsumer() {
|
||||
|
||||
final Boolean showDn = request.paramAsBoolean("show_dn", Boolean.FALSE);
|
||||
|
||||
@Override
|
||||
public void accept(RestChannel channel) throws Exception {
|
||||
XContentBuilder builder = channel.newBuilder();
|
||||
BytesRestResponse response = null;
|
||||
|
||||
try {
|
||||
|
||||
SSLInfo sslInfo = SSLRequestHelper.getSSLInfo(settings, configPath, request, principalExtractor);
|
||||
X509Certificate[] certs = sslInfo == null?null:sslInfo.getX509Certs();
|
||||
X509Certificate[] localCerts = sslInfo == null?null:sslInfo.getLocalCertificates();
|
||||
|
||||
builder.startObject();
|
||||
|
||||
builder.field("principal", sslInfo == null?null:sslInfo.getPrincipal());
|
||||
builder.field("peer_certificates", certs != null && certs.length > 0 ? certs.length + "" : "0");
|
||||
|
||||
if(showDn == Boolean.TRUE) {
|
||||
builder.field("peer_certificates_list", certs == null?null:Arrays.stream(certs).map(c->c.getSubjectDN().getName()).collect(Collectors.toList()));
|
||||
builder.field("local_certificates_list", localCerts == null?null:Arrays.stream(localCerts).map(c->c.getSubjectDN().getName()).collect(Collectors.toList()));
|
||||
}
|
||||
|
||||
builder.field("ssl_protocol", sslInfo == null?null:sslInfo.getProtocol());
|
||||
builder.field("ssl_cipher", sslInfo == null?null:sslInfo.getCipher());
|
||||
builder.field("ssl_openssl_available", OpenSsl.isAvailable());
|
||||
builder.field("ssl_openssl_version", OpenSsl.version());
|
||||
builder.field("ssl_openssl_version_string", OpenSsl.versionString());
|
||||
Throwable openSslUnavailCause = OpenSsl.unavailabilityCause();
|
||||
builder.field("ssl_openssl_non_available_cause", openSslUnavailCause==null?"":openSslUnavailCause.toString());
|
||||
builder.field("ssl_openssl_supports_key_manager_factory", OpenSsl.supportsKeyManagerFactory());
|
||||
builder.field("ssl_openssl_supports_hostname_validation", OpenSsl.supportsHostnameValidation());
|
||||
builder.field("ssl_provider_http", sgks.getHTTPProviderName());
|
||||
builder.field("ssl_provider_transport_server", sgks.getTransportServerProviderName());
|
||||
builder.field("ssl_provider_transport_client", sgks.getTransportClientProviderName());
|
||||
builder.endObject();
|
||||
|
||||
response = new BytesRestResponse(RestStatus.OK, builder);
|
||||
} catch (final Exception e1) {
|
||||
logger.error("Error handle request "+e1, e1);
|
||||
builder = channel.newBuilder();
|
||||
builder.startObject();
|
||||
builder.field("error", e1.toString());
|
||||
builder.endObject();
|
||||
response = new BytesRestResponse(RestStatus.INTERNAL_SERVER_ERROR, builder);
|
||||
} finally {
|
||||
if(builder != null) {
|
||||
builder.close();
|
||||
}
|
||||
}
|
||||
|
||||
channel.sendResponse(response);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return "Open Distro Security SSL Info";
|
||||
}
|
||||
}
|
@ -0,0 +1,92 @@
|
||||
/*
|
||||
* Copyright 2015-2018 _floragunn_ GmbH
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Portions Copyright 2019 Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License").
|
||||
* You may not use this file except in compliance with the License.
|
||||
* A copy of the License is located at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* or in the "license" file accompanying this file. This file is distributed
|
||||
* on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
|
||||
* express or implied. See the License for the specific language governing
|
||||
* permissions and limitations under the License.
|
||||
*/
|
||||
|
||||
package com.amazon.opendistroforelasticsearch.security.ssl.transport;
|
||||
|
||||
import java.security.AccessController;
|
||||
import java.security.PrivilegedAction;
|
||||
import java.security.cert.X509Certificate;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import javax.naming.InvalidNameException;
|
||||
import javax.naming.ldap.LdapName;
|
||||
import javax.naming.ldap.Rdn;
|
||||
import javax.security.auth.x500.X500Principal;
|
||||
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
import org.elasticsearch.SpecialPermission;
|
||||
|
||||
public class DefaultPrincipalExtractor implements PrincipalExtractor {
|
||||
|
||||
protected final Logger log = LogManager.getLogger(this.getClass());
|
||||
|
||||
@Override
|
||||
public String extractPrincipal(final X509Certificate x509Certificate, final Type type) {
|
||||
if (x509Certificate == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
final SecurityManager sm = System.getSecurityManager();
|
||||
|
||||
if (sm != null) {
|
||||
sm.checkPermission(new SpecialPermission());
|
||||
}
|
||||
|
||||
String dnString = AccessController.doPrivileged(new PrivilegedAction<String>() {
|
||||
@Override
|
||||
public String run() {
|
||||
final X500Principal principal = x509Certificate.getSubjectX500Principal();
|
||||
return principal.toString();
|
||||
}
|
||||
});
|
||||
|
||||
//remove whitespaces
|
||||
try {
|
||||
final LdapName ln = new LdapName(dnString);
|
||||
final List<Rdn> rdns = new ArrayList<>(ln.getRdns());
|
||||
Collections.reverse(rdns);
|
||||
dnString = String.join(",", rdns.stream().map(r->r.toString()).collect(Collectors.toList()));
|
||||
} catch (InvalidNameException e) {
|
||||
log.error("Unable to parse: {}",dnString, e);
|
||||
}
|
||||
|
||||
|
||||
if(log.isTraceEnabled()) {
|
||||
log.trace("principal: {}", dnString);
|
||||
}
|
||||
|
||||
return dnString;
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,283 @@
|
||||
/*
|
||||
* Copyright 2015-2018 _floragunn_ GmbH
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Portions Copyright 2019 Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License").
|
||||
* You may not use this file except in compliance with the License.
|
||||
* A copy of the License is located at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* or in the "license" file accompanying this file. This file is distributed
|
||||
* on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
|
||||
* express or implied. See the License for the specific language governing
|
||||
* permissions and limitations under the License.
|
||||
*/
|
||||
|
||||
package com.amazon.opendistroforelasticsearch.security.ssl.transport;
|
||||
|
||||
import io.netty.channel.Channel;
|
||||
import io.netty.channel.ChannelHandler;
|
||||
import io.netty.channel.ChannelHandlerContext;
|
||||
import io.netty.channel.ChannelOutboundHandlerAdapter;
|
||||
import io.netty.channel.ChannelPromise;
|
||||
import io.netty.handler.codec.DecoderException;
|
||||
import io.netty.handler.ssl.NotSslRecordException;
|
||||
import io.netty.handler.ssl.SslHandler;
|
||||
|
||||
import java.net.InetSocketAddress;
|
||||
import java.net.SocketAddress;
|
||||
|
||||
import javax.net.ssl.SSLEngine;
|
||||
import javax.net.ssl.SSLException;
|
||||
import javax.net.ssl.SSLHandshakeException;
|
||||
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
import org.elasticsearch.ExceptionsHelper;
|
||||
import org.elasticsearch.cluster.node.DiscoveryNode;
|
||||
import org.elasticsearch.common.io.stream.NamedWriteableRegistry;
|
||||
import org.elasticsearch.common.network.NetworkService;
|
||||
import org.elasticsearch.common.settings.Settings;
|
||||
import org.elasticsearch.common.util.BigArrays;
|
||||
import org.elasticsearch.indices.breaker.CircuitBreakerService;
|
||||
import org.elasticsearch.threadpool.ThreadPool;
|
||||
import org.elasticsearch.transport.TcpChannel;
|
||||
import org.elasticsearch.transport.netty4.Netty4Transport;
|
||||
|
||||
import com.amazon.opendistroforelasticsearch.security.ssl.OpenDistroSecurityKeyStore;
|
||||
import com.amazon.opendistroforelasticsearch.security.ssl.SslExceptionHandler;
|
||||
import com.amazon.opendistroforelasticsearch.security.ssl.util.SSLConfigConstants;
|
||||
|
||||
public class OpenDistroSecuritySSLNettyTransport extends Netty4Transport {
|
||||
|
||||
private final OpenDistroSecurityKeyStore sgks;
|
||||
private final SslExceptionHandler errorHandler;
|
||||
|
||||
public OpenDistroSecuritySSLNettyTransport(final Settings settings, final ThreadPool threadPool, final NetworkService networkService,
|
||||
final BigArrays bigArrays, final NamedWriteableRegistry namedWriteableRegistry,
|
||||
final CircuitBreakerService circuitBreakerService, final OpenDistroSecurityKeyStore sgks, final SslExceptionHandler errorHandler) {
|
||||
super(settings, threadPool, networkService, bigArrays, namedWriteableRegistry, circuitBreakerService);
|
||||
this.sgks = sgks;
|
||||
this.errorHandler = errorHandler;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onException(TcpChannel channel, Exception e) {
|
||||
|
||||
|
||||
if (lifecycle.started()) {
|
||||
|
||||
Throwable cause = e;
|
||||
|
||||
if(e instanceof DecoderException && e != null) {
|
||||
cause = e.getCause();
|
||||
}
|
||||
|
||||
errorHandler.logError(cause, false);
|
||||
|
||||
if(cause instanceof NotSslRecordException) {
|
||||
logger.warn("Someone ({}) speaks transport plaintext instead of ssl, will close the channel", channel.getLocalAddress());
|
||||
TcpChannel.closeChannel(channel, false);
|
||||
return;
|
||||
} else if (cause instanceof SSLException) {
|
||||
logger.error("SSL Problem "+cause.getMessage(),cause);
|
||||
TcpChannel.closeChannel(channel, false);
|
||||
return;
|
||||
} else if (cause instanceof SSLHandshakeException) {
|
||||
logger.error("Problem during handshake "+cause.getMessage());
|
||||
TcpChannel.closeChannel(channel, false);
|
||||
return;
|
||||
}
|
||||
}
|
||||
super.onException(channel, e);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected ChannelHandler getServerChannelInitializer(String name) {
|
||||
return new SSLServerChannelInitializer(name);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected ChannelHandler getClientChannelInitializer(DiscoveryNode node) {
|
||||
return new SSLClientChannelInitializer(node);
|
||||
}
|
||||
|
||||
protected class SSLServerChannelInitializer extends Netty4Transport.ServerChannelInitializer {
|
||||
|
||||
public SSLServerChannelInitializer(String name) {
|
||||
super(name);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void initChannel(Channel ch) throws Exception {
|
||||
super.initChannel(ch);
|
||||
final SslHandler sslHandler = new SslHandler(sgks.createServerTransportSSLEngine());
|
||||
ch.pipeline().addFirst("ssl_server", sslHandler);
|
||||
}
|
||||
|
||||
@Override
|
||||
public final void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
|
||||
if(OpenDistroSecuritySSLNettyTransport.this.lifecycle.started()) {
|
||||
|
||||
if(cause instanceof DecoderException && cause != null) {
|
||||
cause = cause.getCause();
|
||||
}
|
||||
|
||||
errorHandler.logError(cause, false);
|
||||
|
||||
if(cause instanceof NotSslRecordException) {
|
||||
logger.warn("Someone ({}) speaks transport plaintext instead of ssl, will close the channel", ctx.channel().remoteAddress());
|
||||
ctx.channel().close();
|
||||
return;
|
||||
} else if (cause instanceof SSLException) {
|
||||
logger.error("SSL Problem "+cause.getMessage(),cause);
|
||||
ctx.channel().close();
|
||||
return;
|
||||
} else if (cause instanceof SSLHandshakeException) {
|
||||
logger.error("Problem during handshake "+cause.getMessage());
|
||||
ctx.channel().close();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
super.exceptionCaught(ctx, cause);
|
||||
}
|
||||
}
|
||||
|
||||
protected static class ClientSSLHandler extends ChannelOutboundHandlerAdapter {
|
||||
private final Logger log = LogManager.getLogger(this.getClass());
|
||||
private final OpenDistroSecurityKeyStore sgks;
|
||||
private final boolean hostnameVerificationEnabled;
|
||||
private final boolean hostnameVerificationResovleHostName;
|
||||
private final SslExceptionHandler errorHandler;
|
||||
|
||||
|
||||
private ClientSSLHandler(final OpenDistroSecurityKeyStore sgks, final boolean hostnameVerificationEnabled,
|
||||
final boolean hostnameVerificationResovleHostName, final SslExceptionHandler errorHandler) {
|
||||
this.sgks = sgks;
|
||||
this.hostnameVerificationEnabled = hostnameVerificationEnabled;
|
||||
this.hostnameVerificationResovleHostName = hostnameVerificationResovleHostName;
|
||||
this.errorHandler = errorHandler;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public final void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
|
||||
if(cause instanceof DecoderException && cause != null) {
|
||||
cause = cause.getCause();
|
||||
}
|
||||
|
||||
errorHandler.logError(cause, false);
|
||||
|
||||
if(cause instanceof NotSslRecordException) {
|
||||
log.warn("Someone ({}) speaks transport plaintext instead of ssl, will close the channel", ctx.channel().remoteAddress());
|
||||
ctx.channel().close();
|
||||
return;
|
||||
} else if (cause instanceof SSLException) {
|
||||
log.error("SSL Problem "+cause.getMessage(),cause);
|
||||
ctx.channel().close();
|
||||
return;
|
||||
} else if (cause instanceof SSLHandshakeException) {
|
||||
log.error("Problem during handshake "+cause.getMessage());
|
||||
ctx.channel().close();
|
||||
return;
|
||||
}
|
||||
|
||||
super.exceptionCaught(ctx, cause);
|
||||
}
|
||||
|
||||
|
||||
|
||||
@Override
|
||||
public void connect(ChannelHandlerContext ctx, SocketAddress remoteAddress, SocketAddress localAddress, ChannelPromise promise) throws Exception {
|
||||
SSLEngine engine = null;
|
||||
try {
|
||||
if (hostnameVerificationEnabled) {
|
||||
final InetSocketAddress inetSocketAddress = (InetSocketAddress) remoteAddress;
|
||||
String hostname = null;
|
||||
if (hostnameVerificationResovleHostName) {
|
||||
hostname = inetSocketAddress.getHostName();
|
||||
} else {
|
||||
hostname = inetSocketAddress.getHostString();
|
||||
}
|
||||
|
||||
if(log.isDebugEnabled()) {
|
||||
log.debug("Hostname of peer is {} ({}/{}) with hostnameVerificationResovleHostName: {}", hostname, inetSocketAddress.getHostName(), inetSocketAddress.getHostString(), hostnameVerificationResovleHostName);
|
||||
}
|
||||
|
||||
engine = sgks.createClientTransportSSLEngine(hostname, inetSocketAddress.getPort());
|
||||
} else {
|
||||
engine = sgks.createClientTransportSSLEngine(null, -1);
|
||||
}
|
||||
} catch (final SSLException e) {
|
||||
throw ExceptionsHelper.convertToElastic(e);
|
||||
}
|
||||
final SslHandler sslHandler = new SslHandler(engine);
|
||||
ctx.pipeline().replace(this, "ssl_client", sslHandler);
|
||||
super.connect(ctx, remoteAddress, localAddress, promise);
|
||||
}
|
||||
}
|
||||
|
||||
protected class SSLClientChannelInitializer extends Netty4Transport.ClientChannelInitializer {
|
||||
private final boolean hostnameVerificationEnabled;
|
||||
private final boolean hostnameVerificationResovleHostName;
|
||||
|
||||
public SSLClientChannelInitializer(DiscoveryNode node) {
|
||||
hostnameVerificationEnabled = settings.getAsBoolean(
|
||||
SSLConfigConstants.OPENDISTRO_SECURITY_SSL_TRANSPORT_ENFORCE_HOSTNAME_VERIFICATION, true);
|
||||
hostnameVerificationResovleHostName = settings.getAsBoolean(
|
||||
SSLConfigConstants.OPENDISTRO_SECURITY_SSL_TRANSPORT_ENFORCE_HOSTNAME_VERIFICATION_RESOLVE_HOST_NAME, true);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void initChannel(Channel ch) throws Exception {
|
||||
super.initChannel(ch);
|
||||
ch.pipeline().addFirst("client_ssl_handler", new ClientSSLHandler(sgks, hostnameVerificationEnabled,
|
||||
hostnameVerificationResovleHostName, errorHandler));
|
||||
}
|
||||
|
||||
@Override
|
||||
public final void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
|
||||
if(OpenDistroSecuritySSLNettyTransport.this.lifecycle.started()) {
|
||||
|
||||
if(cause instanceof DecoderException && cause != null) {
|
||||
cause = cause.getCause();
|
||||
}
|
||||
|
||||
errorHandler.logError(cause, false);
|
||||
|
||||
if(cause instanceof NotSslRecordException) {
|
||||
logger.warn("Someone ({}) speaks transport plaintext instead of ssl, will close the channel", ctx.channel().remoteAddress());
|
||||
ctx.channel().close();
|
||||
return;
|
||||
} else if (cause instanceof SSLException) {
|
||||
logger.error("SSL Problem "+cause.getMessage(),cause);
|
||||
ctx.channel().close();
|
||||
return;
|
||||
} else if (cause instanceof SSLHandshakeException) {
|
||||
logger.error("Problem during handshake "+cause.getMessage());
|
||||
ctx.channel().close();
|
||||
return;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
super.exceptionCaught(ctx, cause);
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,185 @@
|
||||
/*
|
||||
* Copyright 2015-2018 _floragunn_ GmbH
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Portions Copyright 2019 Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License").
|
||||
* You may not use this file except in compliance with the License.
|
||||
* A copy of the License is located at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* or in the "license" file accompanying this file. This file is distributed
|
||||
* on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
|
||||
* express or implied. See the License for the specific language governing
|
||||
* permissions and limitations under the License.
|
||||
*/
|
||||
|
||||
package com.amazon.opendistroforelasticsearch.security.ssl.transport;
|
||||
|
||||
import io.netty.channel.Channel;
|
||||
import io.netty.handler.ssl.SslHandler;
|
||||
|
||||
import java.security.cert.Certificate;
|
||||
import java.security.cert.X509Certificate;
|
||||
import java.util.Arrays;
|
||||
|
||||
import javax.net.ssl.SSLPeerUnverifiedException;
|
||||
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
import org.elasticsearch.ElasticsearchException;
|
||||
import org.elasticsearch.ExceptionsHelper;
|
||||
import org.elasticsearch.common.util.concurrent.ThreadContext;
|
||||
import org.elasticsearch.tasks.Task;
|
||||
import org.elasticsearch.threadpool.ThreadPool;
|
||||
import org.elasticsearch.transport.TaskTransportChannel;
|
||||
import org.elasticsearch.transport.TcpChannel;
|
||||
import org.elasticsearch.transport.TcpTransportChannel;
|
||||
import org.elasticsearch.transport.TransportChannel;
|
||||
import org.elasticsearch.transport.TransportRequest;
|
||||
import org.elasticsearch.transport.TransportRequestHandler;
|
||||
import org.elasticsearch.transport.netty4.NettyTcpChannel;
|
||||
|
||||
import com.amazon.opendistroforelasticsearch.security.ssl.SslExceptionHandler;
|
||||
import com.amazon.opendistroforelasticsearch.security.ssl.util.ExceptionUtils;
|
||||
import com.amazon.opendistroforelasticsearch.security.ssl.util.SSLRequestHelper;
|
||||
|
||||
public class OpenDistroSecuritySSLRequestHandler<T extends TransportRequest>
|
||||
implements TransportRequestHandler<T> {
|
||||
|
||||
private final String action;
|
||||
private final TransportRequestHandler<T> actualHandler;
|
||||
private final ThreadPool threadPool;
|
||||
protected final Logger log = LogManager.getLogger(this.getClass());
|
||||
private final PrincipalExtractor principalExtractor;
|
||||
private final SslExceptionHandler errorHandler;
|
||||
|
||||
public OpenDistroSecuritySSLRequestHandler(String action, TransportRequestHandler<T> actualHandler,
|
||||
ThreadPool threadPool, final PrincipalExtractor principalExtractor, final SslExceptionHandler errorHandler) {
|
||||
super();
|
||||
this.action = action;
|
||||
this.actualHandler = actualHandler;
|
||||
this.threadPool = threadPool;
|
||||
this.principalExtractor = principalExtractor;
|
||||
this.errorHandler = errorHandler;
|
||||
}
|
||||
|
||||
protected ThreadContext getThreadContext() {
|
||||
if(threadPool == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return threadPool.getThreadContext();
|
||||
}
|
||||
|
||||
@Override
|
||||
public final void messageReceived(T request, TransportChannel channel) throws Exception {
|
||||
messageReceived(request, channel, null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public final void messageReceived(T request, TransportChannel channel, Task task) throws Exception {
|
||||
ThreadContext threadContext = getThreadContext() ;
|
||||
|
||||
if(SSLRequestHelper.containsBadHeader(threadContext, "_opendistro_security_ssl_")) {
|
||||
final Exception exception = ExceptionUtils.createBadHeaderException();
|
||||
channel.sendResponse(exception);
|
||||
throw exception;
|
||||
}
|
||||
|
||||
if (!"netty".equals(channel.getChannelType())) { //netty4
|
||||
messageReceivedDecorate(request, actualHandler, channel, task);
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
|
||||
NettyTcpChannel nettyChannel = null;
|
||||
|
||||
if (channel instanceof TaskTransportChannel) {
|
||||
final TransportChannel inner = ((TaskTransportChannel) channel).getChannel();
|
||||
nettyChannel = (NettyTcpChannel) ((TcpTransportChannel) inner).getChannel();
|
||||
} else
|
||||
if (channel instanceof TcpTransportChannel) {
|
||||
final TcpChannel inner = ((TcpTransportChannel) channel).getChannel();
|
||||
nettyChannel = (NettyTcpChannel) inner;
|
||||
} else {
|
||||
throw new Exception("Invalid channel of type "+channel.getClass()+ " ("+channel.getChannelType()+")");
|
||||
}
|
||||
|
||||
final SslHandler sslhandler = (SslHandler) nettyChannel.getLowLevelChannel().pipeline().get("ssl_server");
|
||||
|
||||
if (sslhandler == null) {
|
||||
final String msg = "No ssl handler found (Security 11)";
|
||||
//log.error(msg);
|
||||
final Exception exception = new ElasticsearchException(msg);
|
||||
channel.sendResponse(exception);
|
||||
throw exception;
|
||||
}
|
||||
|
||||
|
||||
final Certificate[] peerCerts = sslhandler.engine().getSession().getPeerCertificates();
|
||||
final Certificate[] localCerts = sslhandler.engine().getSession().getLocalCertificates();
|
||||
|
||||
if (peerCerts != null
|
||||
&& peerCerts.length > 0
|
||||
&& peerCerts[0] instanceof X509Certificate
|
||||
&& localCerts != null && localCerts.length > 0
|
||||
&& localCerts[0] instanceof X509Certificate) {
|
||||
final X509Certificate[] x509PeerCerts = Arrays.copyOf(peerCerts, peerCerts.length, X509Certificate[].class);
|
||||
final X509Certificate[] x509LocalCerts = Arrays.copyOf(localCerts, localCerts.length, X509Certificate[].class);
|
||||
final String principal = principalExtractor==null?null:principalExtractor.extractPrincipal(x509PeerCerts[0], PrincipalExtractor.Type.TRANSPORT);
|
||||
addAdditionalContextValues(action, request, x509LocalCerts, x509PeerCerts, principal);
|
||||
if(threadContext != null) {
|
||||
//in the case of ssl plugin only: threadContext and principalExtractor are null
|
||||
threadContext.putTransient("_opendistro_security_ssl_transport_principal", principal);
|
||||
threadContext.putTransient("_opendistro_security_ssl_transport_peer_certificates", x509PeerCerts);
|
||||
threadContext.putTransient("_opendistro_security_ssl_transport_local_certificates", x509LocalCerts);
|
||||
threadContext.putTransient("_opendistro_security_ssl_transport_protocol", sslhandler.engine().getSession().getProtocol());
|
||||
threadContext.putTransient("_opendistro_security_ssl_transport_cipher", sslhandler.engine().getSession().getCipherSuite());
|
||||
}
|
||||
messageReceivedDecorate(request, actualHandler, channel, task);
|
||||
} else {
|
||||
final String msg = "No X509 transport client certificates found (Security 12)";
|
||||
//log.error(msg);
|
||||
final Exception exception = new ElasticsearchException(msg);
|
||||
errorHandler.logError(exception, request, action, task, 0);
|
||||
channel.sendResponse(exception);
|
||||
throw exception;
|
||||
}
|
||||
|
||||
} catch (final SSLPeerUnverifiedException e) {
|
||||
errorHandler.logError(e, request, action, task, 0);
|
||||
final Exception exception = ExceptionsHelper.convertToElastic(e);
|
||||
channel.sendResponse(exception);
|
||||
throw exception;
|
||||
} catch (final Exception e) {
|
||||
errorHandler.logError(e, request, action, task, 0);
|
||||
throw e;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
protected void addAdditionalContextValues(final String action, final TransportRequest request, final X509Certificate[] localCerts, final X509Certificate[] peerCerts, final String principal)
|
||||
throws Exception {
|
||||
// no-op
|
||||
}
|
||||
|
||||
protected void messageReceivedDecorate(final T request, final TransportRequestHandler<T> actualHandler, final TransportChannel transportChannel, Task task) throws Exception {
|
||||
actualHandler.messageReceived(request, transportChannel, task);
|
||||
}
|
||||
}
|
@ -0,0 +1,64 @@
|
||||
/*
|
||||
* Copyright 2015-2018 _floragunn_ GmbH
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Portions Copyright 2019 Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License").
|
||||
* You may not use this file except in compliance with the License.
|
||||
* A copy of the License is located at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* or in the "license" file accompanying this file. This file is distributed
|
||||
* on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
|
||||
* express or implied. See the License for the specific language governing
|
||||
* permissions and limitations under the License.
|
||||
*/
|
||||
|
||||
package com.amazon.opendistroforelasticsearch.security.ssl.transport;
|
||||
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
import org.elasticsearch.common.settings.Settings;
|
||||
import org.elasticsearch.threadpool.ThreadPool;
|
||||
import org.elasticsearch.transport.TransportInterceptor;
|
||||
import org.elasticsearch.transport.TransportRequest;
|
||||
import org.elasticsearch.transport.TransportRequestHandler;
|
||||
|
||||
import com.amazon.opendistroforelasticsearch.security.ssl.SslExceptionHandler;
|
||||
|
||||
public final class OpenDistroSecuritySSLTransportInterceptor implements TransportInterceptor {
|
||||
|
||||
protected final Logger log = LogManager.getLogger(this.getClass());
|
||||
protected final ThreadPool threadPool;
|
||||
protected final PrincipalExtractor principalExtractor;
|
||||
protected final SslExceptionHandler errorHandler;
|
||||
|
||||
public OpenDistroSecuritySSLTransportInterceptor(final Settings settings, final ThreadPool threadPool,
|
||||
PrincipalExtractor principalExtractor, final SslExceptionHandler errorHandler) {
|
||||
this.threadPool = threadPool;
|
||||
this.principalExtractor = principalExtractor;
|
||||
this.errorHandler = errorHandler;
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T extends TransportRequest> TransportRequestHandler<T> interceptHandler(String action, String executor, boolean forceExecution,
|
||||
TransportRequestHandler<T> actualHandler) {
|
||||
return new OpenDistroSecuritySSLRequestHandler<T>(action, actualHandler, threadPool, principalExtractor, errorHandler);
|
||||
}
|
||||
|
||||
|
||||
}
|
@ -0,0 +1,58 @@
|
||||
/*
|
||||
* Copyright 2015-2018 _floragunn_ GmbH
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Portions Copyright 2019 Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License").
|
||||
* You may not use this file except in compliance with the License.
|
||||
* A copy of the License is located at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* or in the "license" file accompanying this file. This file is distributed
|
||||
* on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
|
||||
* express or implied. See the License for the specific language governing
|
||||
* permissions and limitations under the License.
|
||||
*/
|
||||
|
||||
package com.amazon.opendistroforelasticsearch.security.ssl.transport;
|
||||
|
||||
import java.security.cert.X509Certificate;
|
||||
|
||||
public interface PrincipalExtractor {
|
||||
|
||||
public enum Type {
|
||||
HTTP,
|
||||
TRANSPORT
|
||||
}
|
||||
|
||||
/**
|
||||
* Extract the principal name
|
||||
*
|
||||
* Please note that this method gets called for principal extraction of other nodes
|
||||
* as well as transport clients. It's up to the implementer to distinguish between them
|
||||
* and handle them appropriately.
|
||||
*
|
||||
* Implementations must be public classes with a default public default constructor.
|
||||
*
|
||||
* @param x509Certificate The first X509 certificate in the peer certificate chain
|
||||
* This can be null, in this case the method must also return <code>null</code>.
|
||||
* @return The principal as string. This may be <code>null</code> in case where x509Certificate is null
|
||||
* or the principal cannot be extracted because of any other circumstances.
|
||||
*/
|
||||
String extractPrincipal(X509Certificate x509Certificate, Type type);
|
||||
|
||||
}
|
@ -0,0 +1,337 @@
|
||||
/*
|
||||
* Copyright 2015-2018 _floragunn_ GmbH
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Portions Copyright 2019 Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License").
|
||||
* You may not use this file except in compliance with the License.
|
||||
* A copy of the License is located at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* or in the "license" file accompanying this file. This file is distributed
|
||||
* on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
|
||||
* express or implied. See the License for the specific language governing
|
||||
* permissions and limitations under the License.
|
||||
*/
|
||||
|
||||
package com.amazon.opendistroforelasticsearch.security.ssl.util;
|
||||
|
||||
//
|
||||
// ========================================================================
|
||||
// Copyright (c) 1995-2017 Mort Bay Consulting Pty. Ltd.
|
||||
// ------------------------------------------------------------------------
|
||||
// All rights reserved. This program and the accompanying materials
|
||||
// are made available under the terms of the Eclipse Public License v1.0
|
||||
// and Apache License v2.0 which accompanies this distribution.
|
||||
//
|
||||
// The Eclipse Public License is available at
|
||||
// http://www.eclipse.org/legal/epl-v10.html
|
||||
//
|
||||
// The Apache License v2.0 is available at
|
||||
// http://www.opensource.org/licenses/apache2.0.php
|
||||
//
|
||||
// You may elect to redistribute this code under either of these licenses.
|
||||
// ========================================================================
|
||||
//
|
||||
|
||||
import java.security.GeneralSecurityException;
|
||||
import java.security.InvalidParameterException;
|
||||
import java.security.KeyStore;
|
||||
import java.security.Security;
|
||||
import java.security.cert.CRL;
|
||||
import java.security.cert.CertPathBuilder;
|
||||
import java.security.cert.CertPathBuilderResult;
|
||||
import java.security.cert.CertPathValidator;
|
||||
import java.security.cert.CertStore;
|
||||
import java.security.cert.Certificate;
|
||||
import java.security.cert.CertificateException;
|
||||
import java.security.cert.CollectionCertStoreParameters;
|
||||
import java.security.cert.PKIXBuilderParameters;
|
||||
import java.security.cert.PKIXRevocationChecker;
|
||||
import java.security.cert.TrustAnchor;
|
||||
import java.security.cert.X509CertSelector;
|
||||
import java.security.cert.X509Certificate;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.Date;
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* Convenience class to handle validation of certificates, aliases and keystores
|
||||
*
|
||||
* Allows specifying Certificate Revocation List (CRL), as well as enabling
|
||||
* CRL Distribution Points Protocol (CRLDP) certificate extension support,
|
||||
* and also enabling On-Line Certificate Status Protocol (OCSP) support.
|
||||
*
|
||||
* IMPORTANT: at least one of the above mechanisms *MUST* be configured and
|
||||
* operational, otherwise certificate validation *WILL FAIL* unconditionally.
|
||||
*/
|
||||
public class CertificateValidator
|
||||
{
|
||||
|
||||
boolean isPreferCrl() {
|
||||
return preferCrl;
|
||||
}
|
||||
|
||||
void setPreferCrl(boolean preferCrl) {
|
||||
this.preferCrl = preferCrl;
|
||||
}
|
||||
|
||||
boolean isCheckOnlyEndEntities() {
|
||||
return checkOnlyEndEntities;
|
||||
}
|
||||
|
||||
void setCheckOnlyEndEntities(boolean checkOnlyEndEntities) {
|
||||
this.checkOnlyEndEntities = checkOnlyEndEntities;
|
||||
}
|
||||
|
||||
private KeyStore _trustStore;
|
||||
private X509Certificate[] _trustedCert;
|
||||
private Collection<? extends CRL> _crls;
|
||||
|
||||
/** Maximum certification path length (n - number of intermediate certs, -1 for unlimited) */
|
||||
private int _maxCertPathLength = -1;
|
||||
/** CRL Distribution Points (CRLDP) support */
|
||||
private boolean _enableCRLDP = false;
|
||||
/** On-Line Certificate Status Protocol (OCSP) support */
|
||||
private boolean _enableOCSP = false;
|
||||
/** Location of OCSP Responder */
|
||||
private String _ocspResponderURL;
|
||||
|
||||
private boolean preferCrl = false;
|
||||
private boolean checkOnlyEndEntities = true;
|
||||
private Date date = null; //current date
|
||||
|
||||
/**
|
||||
* creates an instance of the certificate validator
|
||||
*
|
||||
* @param trustStore the truststore to use
|
||||
* @param crls the Certificate Revocation List to use
|
||||
*/
|
||||
public CertificateValidator(KeyStore trustStore, Collection<? extends CRL> crls)
|
||||
{
|
||||
if (trustStore == null)
|
||||
{
|
||||
throw new InvalidParameterException("TrustStore must be specified for CertificateValidator.");
|
||||
}
|
||||
|
||||
_trustStore = trustStore;
|
||||
_crls = crls;
|
||||
}
|
||||
|
||||
public CertificateValidator(X509Certificate[] trustedCert, Collection<? extends CRL> crls)
|
||||
{
|
||||
if (trustedCert == null || trustedCert.length == 0)
|
||||
{
|
||||
throw new InvalidParameterException("trustedCert must be specified for CertificateValidator.");
|
||||
}
|
||||
|
||||
_trustedCert = trustedCert;
|
||||
_crls = crls;
|
||||
}
|
||||
|
||||
public void validate(Certificate[] certChain) throws CertificateException
|
||||
{
|
||||
try
|
||||
{
|
||||
ArrayList<X509Certificate> certList = new ArrayList<X509Certificate>();
|
||||
for (Certificate item : certChain)
|
||||
{
|
||||
if (item == null)
|
||||
continue;
|
||||
|
||||
if (!(item instanceof X509Certificate))
|
||||
{
|
||||
throw new IllegalStateException("Invalid certificate type in chain");
|
||||
}
|
||||
|
||||
certList.add((X509Certificate)item);
|
||||
}
|
||||
|
||||
if (certList.isEmpty())
|
||||
{
|
||||
throw new IllegalStateException("Invalid certificate chain");
|
||||
|
||||
}
|
||||
|
||||
X509CertSelector certSelect = new X509CertSelector();
|
||||
certSelect.setCertificate(certList.get(0));
|
||||
|
||||
CertPathBuilder certPathBuilder = CertPathBuilder.getInstance("PKIX");
|
||||
PKIXRevocationChecker revocationChecker = (PKIXRevocationChecker) certPathBuilder.getRevocationChecker();
|
||||
|
||||
Set<PKIXRevocationChecker.Option> opts = new HashSet<>();
|
||||
|
||||
if(preferCrl) {
|
||||
opts.add(PKIXRevocationChecker.Option.PREFER_CRLS);
|
||||
}
|
||||
|
||||
//opts.add(PKIXRevocationChecker.Option.SOFT_FAIL);
|
||||
|
||||
//opts.add(PKIXRevocationChecker.Option.NO_FALLBACK);
|
||||
|
||||
if(checkOnlyEndEntities) {
|
||||
opts.add(PKIXRevocationChecker.Option.ONLY_END_ENTITY);
|
||||
}
|
||||
|
||||
revocationChecker.setOptions(opts);
|
||||
|
||||
// Configure certification path builder parameters
|
||||
PKIXBuilderParameters pbParams = null;
|
||||
|
||||
if(_trustStore != null) {
|
||||
pbParams = new PKIXBuilderParameters(_trustStore, certSelect);
|
||||
} else {
|
||||
Set<TrustAnchor> trustAnchors = new HashSet<TrustAnchor>();
|
||||
for (int i = 0; i < _trustedCert.length; i++) {
|
||||
X509Certificate certificate = _trustedCert[i];
|
||||
TrustAnchor trustAnchor = new TrustAnchor(certificate, null);
|
||||
trustAnchors.add(trustAnchor);
|
||||
}
|
||||
|
||||
pbParams = new PKIXBuilderParameters(trustAnchors, certSelect);
|
||||
}
|
||||
|
||||
pbParams.addCertPathChecker(revocationChecker);
|
||||
|
||||
pbParams.setDate(date);
|
||||
|
||||
pbParams.addCertStore(CertStore.getInstance("Collection", new CollectionCertStoreParameters(certList)));
|
||||
|
||||
// Set maximum certification path length
|
||||
pbParams.setMaxPathLength(_maxCertPathLength);
|
||||
|
||||
// Enable revocation checking
|
||||
pbParams.setRevocationEnabled(true);
|
||||
|
||||
// Set static Certificate Revocation List
|
||||
if (_crls != null && !_crls.isEmpty())
|
||||
{
|
||||
pbParams.addCertStore(CertStore.getInstance("Collection", new CollectionCertStoreParameters(_crls)));
|
||||
}
|
||||
|
||||
// Enable On-Line Certificate Status Protocol (OCSP) support
|
||||
if (_enableOCSP)
|
||||
{
|
||||
Security.setProperty("ocsp.enable","true");
|
||||
}
|
||||
// Enable Certificate Revocation List Distribution Points (CRLDP) support
|
||||
if (_enableCRLDP)
|
||||
{
|
||||
System.setProperty("com.sun.security.enableCRLDP","true");
|
||||
}
|
||||
|
||||
// Build certification path
|
||||
CertPathBuilderResult buildResult = CertPathBuilder.getInstance("PKIX").build(pbParams);
|
||||
|
||||
// Validate certification path
|
||||
CertPathValidator.getInstance("PKIX").validate(buildResult.getCertPath(),pbParams);
|
||||
}
|
||||
catch (GeneralSecurityException gse)
|
||||
{
|
||||
throw new CertificateException("Unable to validate certificate: " + gse.getMessage(), gse);
|
||||
}
|
||||
}
|
||||
|
||||
public Collection<? extends CRL> getCrls()
|
||||
{
|
||||
return _crls;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Maximum number of intermediate certificates in
|
||||
* the certification path (-1 for unlimited)
|
||||
*/
|
||||
public int getMaxCertPathLength()
|
||||
{
|
||||
return _maxCertPathLength;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/**
|
||||
* @param maxCertPathLength
|
||||
* maximum number of intermediate certificates in
|
||||
* the certification path (-1 for unlimited)
|
||||
*/
|
||||
public void setMaxCertPathLength(int maxCertPathLength)
|
||||
{
|
||||
_maxCertPathLength = maxCertPathLength;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/**
|
||||
* @return true if CRL Distribution Points support is enabled
|
||||
*/
|
||||
public boolean isEnableCRLDP()
|
||||
{
|
||||
return _enableCRLDP;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/** Enables CRL Distribution Points Support
|
||||
* @param enableCRLDP true - turn on, false - turns off
|
||||
*/
|
||||
public void setEnableCRLDP(boolean enableCRLDP)
|
||||
{
|
||||
_enableCRLDP = enableCRLDP;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/**
|
||||
* @return true if On-Line Certificate Status Protocol support is enabled
|
||||
*/
|
||||
public boolean isEnableOCSP()
|
||||
{
|
||||
return _enableOCSP;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/** Enables On-Line Certificate Status Protocol support
|
||||
* @param enableOCSP true - turn on, false - turn off
|
||||
*/
|
||||
public void setEnableOCSP(boolean enableOCSP)
|
||||
{
|
||||
_enableOCSP = enableOCSP;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/**
|
||||
* @return Location of the OCSP Responder
|
||||
*/
|
||||
public String getOcspResponderURL()
|
||||
{
|
||||
return _ocspResponderURL;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/** Set the location of the OCSP Responder.
|
||||
* @param ocspResponderURL location of the OCSP Responder
|
||||
*/
|
||||
public void setOcspResponderURL(String ocspResponderURL)
|
||||
{
|
||||
_ocspResponderURL = ocspResponderURL;
|
||||
}
|
||||
|
||||
public Date getDate() {
|
||||
return date==null?null:(Date) date.clone();
|
||||
}
|
||||
|
||||
public void setDate(Date date) {
|
||||
this.date = date==null?null:(Date) date.clone();
|
||||
}
|
||||
}
|
@ -0,0 +1,73 @@
|
||||
/*
|
||||
* Copyright 2015-2018 _floragunn_ GmbH
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Portions Copyright 2019 Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License").
|
||||
* You may not use this file except in compliance with the License.
|
||||
* A copy of the License is located at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* or in the "license" file accompanying this file. This file is distributed
|
||||
* on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
|
||||
* express or implied. See the License for the specific language governing
|
||||
* permissions and limitations under the License.
|
||||
*/
|
||||
|
||||
package com.amazon.opendistroforelasticsearch.security.ssl.util;
|
||||
|
||||
import org.elasticsearch.ElasticsearchException;
|
||||
|
||||
public class ExceptionUtils {
|
||||
|
||||
public static Throwable getRootCause(final Throwable e) {
|
||||
|
||||
if(e == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
final Throwable cause = e.getCause();
|
||||
if(cause == null) {
|
||||
return e;
|
||||
}
|
||||
return getRootCause(cause);
|
||||
}
|
||||
|
||||
public static Throwable findMsg(final Throwable e, String msg) {
|
||||
|
||||
if(e == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if(e.getMessage() != null && e.getMessage().contains(msg)) {
|
||||
return e;
|
||||
}
|
||||
|
||||
final Throwable cause = e.getCause();
|
||||
if(cause == null) {
|
||||
return null;
|
||||
}
|
||||
return findMsg(cause, msg);
|
||||
}
|
||||
|
||||
public static ElasticsearchException createBadHeaderException() {
|
||||
return new ElasticsearchException("Illegal parameter in http or transport request found."+System.lineSeparator()
|
||||
+ "This means that one node is trying to connect to another with "+System.lineSeparator()
|
||||
+ "a non-node certificate (no OID or opendistro_security.nodes_dn incorrect configured) or that someone "+System.lineSeparator()
|
||||
+ "is spoofing requests. Check your TLS certificate setup as described in documentation");
|
||||
}
|
||||
}
|
@ -0,0 +1,200 @@
|
||||
/*
|
||||
* Copyright 2015-2018 _floragunn_ GmbH
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Portions Copyright 2019 Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License").
|
||||
* You may not use this file except in compliance with the License.
|
||||
* A copy of the License is located at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* or in the "license" file accompanying this file. This file is distributed
|
||||
* on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
|
||||
* express or implied. See the License for the specific language governing
|
||||
* permissions and limitations under the License.
|
||||
*/
|
||||
|
||||
package com.amazon.opendistroforelasticsearch.security.ssl.util;
|
||||
|
||||
import java.security.Key;
|
||||
import java.security.KeyStore;
|
||||
import java.security.KeyStoreException;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
import java.security.PrivateKey;
|
||||
import java.security.UnrecoverableKeyException;
|
||||
import java.security.cert.Certificate;
|
||||
import java.security.cert.X509Certificate;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.Enumeration;
|
||||
import java.util.List;
|
||||
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
import org.elasticsearch.common.Strings;
|
||||
|
||||
public class SSLCertificateHelper {
|
||||
|
||||
private static final Logger log = LogManager.getLogger(SSLCertificateHelper.class);
|
||||
private static boolean stripRootFromChain = true; //TODO check
|
||||
|
||||
public static X509Certificate[] exportRootCertificates(final KeyStore ks, final String alias) throws KeyStoreException {
|
||||
logKeyStore(ks);
|
||||
|
||||
final List<X509Certificate> trustedCerts = new ArrayList<X509Certificate>();
|
||||
|
||||
if (Strings.isNullOrEmpty(alias)) {
|
||||
|
||||
if(log.isDebugEnabled()) {
|
||||
log.debug("No alias given, will trust all of the certificates in the store");
|
||||
}
|
||||
|
||||
final List<String> aliases = toList(ks.aliases());
|
||||
|
||||
for (final String _alias : aliases) {
|
||||
|
||||
if (ks.isCertificateEntry(_alias)) {
|
||||
final X509Certificate cert = (X509Certificate) ks.getCertificate(_alias);
|
||||
if (cert != null) {
|
||||
trustedCerts.add(cert);
|
||||
} else {
|
||||
log.error("Alias {} does not exist", _alias);
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (ks.isCertificateEntry(alias)) {
|
||||
final X509Certificate cert = (X509Certificate) ks.getCertificate(alias);
|
||||
if (cert != null) {
|
||||
trustedCerts.add(cert);
|
||||
} else {
|
||||
log.error("Alias {} does not exist", alias);
|
||||
}
|
||||
} else {
|
||||
log.error("Alias {} does not contain a certificate entry", alias);
|
||||
}
|
||||
}
|
||||
|
||||
return trustedCerts.toArray(new X509Certificate[0]);
|
||||
}
|
||||
|
||||
public static X509Certificate[] exportServerCertChain(final KeyStore ks, String alias) throws KeyStoreException {
|
||||
logKeyStore(ks);
|
||||
final List<String> aliases = toList(ks.aliases());
|
||||
|
||||
if (Strings.isNullOrEmpty(alias)) {
|
||||
if(aliases.isEmpty()) {
|
||||
log.error("Keystore does not contain any aliases");
|
||||
} else {
|
||||
alias = aliases.get(0);
|
||||
log.info("No alias given, use the first one: {}", alias);
|
||||
}
|
||||
}
|
||||
|
||||
final Certificate[] certs = ks.getCertificateChain(alias);
|
||||
if (certs != null && certs.length > 0) {
|
||||
X509Certificate[] x509Certs = Arrays.copyOf(certs, certs.length, X509Certificate[].class);
|
||||
|
||||
final X509Certificate lastCertificate = x509Certs[x509Certs.length - 1];
|
||||
|
||||
if (lastCertificate.getBasicConstraints() > -1
|
||||
&& lastCertificate.getSubjectX500Principal().equals(lastCertificate.getIssuerX500Principal())) {
|
||||
log.warn("Certificate chain for alias {} contains a root certificate", alias);
|
||||
|
||||
if(stripRootFromChain ) {
|
||||
x509Certs = Arrays.copyOf(certs, certs.length-1, X509Certificate[].class);
|
||||
}
|
||||
}
|
||||
|
||||
return x509Certs;
|
||||
} else {
|
||||
log.error("Alias {} does not exist or contain a certificate chain", alias);
|
||||
}
|
||||
|
||||
return new X509Certificate[0];
|
||||
}
|
||||
|
||||
public static PrivateKey exportDecryptedKey(final KeyStore ks, final String alias, final char[] password) throws KeyStoreException, UnrecoverableKeyException, NoSuchAlgorithmException {
|
||||
logKeyStore(ks);
|
||||
final List<String> aliases = toList(ks.aliases());
|
||||
|
||||
String evaluatedAlias = alias;
|
||||
|
||||
if (alias == null && aliases.size() > 0) {
|
||||
evaluatedAlias = aliases.get(0);
|
||||
}
|
||||
|
||||
if (evaluatedAlias == null) {
|
||||
throw new KeyStoreException("null alias, current aliases: " + aliases);
|
||||
}
|
||||
|
||||
final Key key = ks.getKey(evaluatedAlias, (password == null || password.length == 0) ? null:password);
|
||||
|
||||
if (key == null) {
|
||||
throw new KeyStoreException("no key alias named " + evaluatedAlias);
|
||||
}
|
||||
|
||||
if (key instanceof PrivateKey) {
|
||||
return (PrivateKey) key;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
private static void logKeyStore(final KeyStore ks) {
|
||||
try {
|
||||
final List<String> aliases = toList(ks.aliases());
|
||||
if (log.isDebugEnabled()) {
|
||||
log.debug("Keystore has {} entries/aliases", ks.size());
|
||||
for (String _alias : aliases) {
|
||||
log.debug("Alias {}: is a certificate entry?{}/is a key entry?{}", _alias, ks.isCertificateEntry(_alias),
|
||||
ks.isKeyEntry(_alias));
|
||||
Certificate[] certs = ks.getCertificateChain(_alias);
|
||||
|
||||
if (certs != null) {
|
||||
log.debug("Alias {}: chain len {}", _alias, certs.length);
|
||||
for (int i = 0; i < certs.length; i++) {
|
||||
X509Certificate certificate = (X509Certificate) certs[i];
|
||||
log.debug("cert {} of type {} -> {}", certificate.getSubjectX500Principal(), certificate.getBasicConstraints(),
|
||||
certificate.getSubjectX500Principal().equals(certificate.getIssuerX500Principal()));
|
||||
}
|
||||
}
|
||||
|
||||
X509Certificate cert = (X509Certificate) ks.getCertificate(_alias);
|
||||
|
||||
if (cert != null) {
|
||||
log.debug("Alias {}: single cert {} of type {} -> {}", _alias, cert.getSubjectX500Principal(),
|
||||
cert.getBasicConstraints(), cert.getSubjectX500Principal().equals(cert.getIssuerX500Principal()));
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (Exception e) {
|
||||
log.error("Error logging keystore due to "+e, e);
|
||||
}
|
||||
}
|
||||
|
||||
private static List<String> toList(final Enumeration<String> enumeration) {
|
||||
final List<String> aliases = new ArrayList<>();
|
||||
|
||||
while (enumeration.hasMoreElements()) {
|
||||
aliases.add(enumeration.nextElement());
|
||||
}
|
||||
|
||||
return Collections.unmodifiableList(aliases);
|
||||
}
|
||||
}
|
@ -0,0 +1,254 @@
|
||||
/*
|
||||
* Copyright 2015-2018 _floragunn_ GmbH
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Portions Copyright 2019 Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License").
|
||||
* You may not use this file except in compliance with the License.
|
||||
* A copy of the License is located at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* or in the "license" file accompanying this file. This file is distributed
|
||||
* on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
|
||||
* express or implied. See the License for the specific language governing
|
||||
* permissions and limitations under the License.
|
||||
*/
|
||||
|
||||
package com.amazon.opendistroforelasticsearch.security.ssl.util;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
import org.elasticsearch.common.settings.Settings;
|
||||
|
||||
public final class SSLConfigConstants {
|
||||
|
||||
public static final String OPENDISTRO_SECURITY_SSL_HTTP_ENABLE_OPENSSL_IF_AVAILABLE = "opendistro_security.ssl.http.enable_openssl_if_available";
|
||||
public static final String OPENDISTRO_SECURITY_SSL_HTTP_ENABLED = "opendistro_security.ssl.http.enabled";
|
||||
public static final boolean OPENDISTRO_SECURITY_SSL_HTTP_ENABLED_DEFAULT = false;
|
||||
public static final String OPENDISTRO_SECURITY_SSL_HTTP_CLIENTAUTH_MODE = "opendistro_security.ssl.http.clientauth_mode";
|
||||
public static final String OPENDISTRO_SECURITY_SSL_HTTP_KEYSTORE_ALIAS = "opendistro_security.ssl.http.keystore_alias";
|
||||
public static final String OPENDISTRO_SECURITY_SSL_HTTP_KEYSTORE_FILEPATH = "opendistro_security.ssl.http.keystore_filepath";
|
||||
public static final String OPENDISTRO_SECURITY_SSL_HTTP_PEMKEY_FILEPATH = "opendistro_security.ssl.http.pemkey_filepath";
|
||||
public static final String OPENDISTRO_SECURITY_SSL_HTTP_PEMKEY_PASSWORD = "opendistro_security.ssl.http.pemkey_password";
|
||||
public static final String OPENDISTRO_SECURITY_SSL_HTTP_PEMCERT_FILEPATH = "opendistro_security.ssl.http.pemcert_filepath";
|
||||
public static final String OPENDISTRO_SECURITY_SSL_HTTP_PEMTRUSTEDCAS_FILEPATH = "opendistro_security.ssl.http.pemtrustedcas_filepath";
|
||||
public static final String OPENDISTRO_SECURITY_SSL_HTTP_KEYSTORE_PASSWORD = "opendistro_security.ssl.http.keystore_password";
|
||||
public static final String OPENDISTRO_SECURITY_SSL_HTTP_KEYSTORE_TYPE = "opendistro_security.ssl.http.keystore_type";
|
||||
public static final String OPENDISTRO_SECURITY_SSL_HTTP_TRUSTSTORE_ALIAS = "opendistro_security.ssl.http.truststore_alias";
|
||||
public static final String OPENDISTRO_SECURITY_SSL_HTTP_TRUSTSTORE_FILEPATH = "opendistro_security.ssl.http.truststore_filepath";
|
||||
public static final String OPENDISTRO_SECURITY_SSL_HTTP_TRUSTSTORE_PASSWORD = "opendistro_security.ssl.http.truststore_password";
|
||||
public static final String OPENDISTRO_SECURITY_SSL_HTTP_TRUSTSTORE_TYPE = "opendistro_security.ssl.http.truststore_type";
|
||||
public static final String OPENDISTRO_SECURITY_SSL_TRANSPORT_ENABLE_OPENSSL_IF_AVAILABLE = "opendistro_security.ssl.transport.enable_openssl_if_available";
|
||||
public static final String OPENDISTRO_SECURITY_SSL_TRANSPORT_ENABLED = "opendistro_security.ssl.transport.enabled";
|
||||
public static final boolean OPENDISTRO_SECURITY_SSL_TRANSPORT_ENABLED_DEFAULT = true;
|
||||
public static final String OPENDISTRO_SECURITY_SSL_TRANSPORT_ENFORCE_HOSTNAME_VERIFICATION = "opendistro_security.ssl.transport.enforce_hostname_verification";
|
||||
public static final String OPENDISTRO_SECURITY_SSL_TRANSPORT_ENFORCE_HOSTNAME_VERIFICATION_RESOLVE_HOST_NAME = "opendistro_security.ssl.transport.resolve_hostname";
|
||||
public static final String OPENDISTRO_SECURITY_SSL_TRANSPORT_KEYSTORE_ALIAS = "opendistro_security.ssl.transport.keystore_alias";
|
||||
public static final String OPENDISTRO_SECURITY_SSL_TRANSPORT_KEYSTORE_FILEPATH = "opendistro_security.ssl.transport.keystore_filepath";
|
||||
public static final String OPENDISTRO_SECURITY_SSL_TRANSPORT_PEMKEY_FILEPATH = "opendistro_security.ssl.transport.pemkey_filepath";
|
||||
public static final String OPENDISTRO_SECURITY_SSL_TRANSPORT_PEMKEY_PASSWORD = "opendistro_security.ssl.transport.pemkey_password";
|
||||
public static final String OPENDISTRO_SECURITY_SSL_TRANSPORT_PEMCERT_FILEPATH = "opendistro_security.ssl.transport.pemcert_filepath";
|
||||
public static final String OPENDISTRO_SECURITY_SSL_TRANSPORT_PEMTRUSTEDCAS_FILEPATH = "opendistro_security.ssl.transport.pemtrustedcas_filepath";
|
||||
public static final String OPENDISTRO_SECURITY_SSL_TRANSPORT_KEYSTORE_PASSWORD = "opendistro_security.ssl.transport.keystore_password";
|
||||
public static final String OPENDISTRO_SECURITY_SSL_TRANSPORT_KEYSTORE_TYPE = "opendistro_security.ssl.transport.keystore_type";
|
||||
public static final String OPENDISTRO_SECURITY_SSL_TRANSPORT_TRUSTSTORE_ALIAS = "opendistro_security.ssl.transport.truststore_alias";
|
||||
public static final String OPENDISTRO_SECURITY_SSL_TRANSPORT_TRUSTSTORE_FILEPATH = "opendistro_security.ssl.transport.truststore_filepath";
|
||||
public static final String OPENDISTRO_SECURITY_SSL_TRANSPORT_TRUSTSTORE_PASSWORD = "opendistro_security.ssl.transport.truststore_password";
|
||||
public static final String OPENDISTRO_SECURITY_SSL_TRANSPORT_TRUSTSTORE_TYPE = "opendistro_security.ssl.transport.truststore_type";
|
||||
public static final String OPENDISTRO_SECURITY_SSL_TRANSPORT_ENABLED_CIPHERS = "opendistro_security.ssl.transport.enabled_ciphers";
|
||||
public static final String OPENDISTRO_SECURITY_SSL_TRANSPORT_ENABLED_PROTOCOLS = "opendistro_security.ssl.transport.enabled_protocols";
|
||||
public static final String OPENDISTRO_SECURITY_SSL_HTTP_ENABLED_CIPHERS = "opendistro_security.ssl.http.enabled_ciphers";
|
||||
public static final String OPENDISTRO_SECURITY_SSL_HTTP_ENABLED_PROTOCOLS = "opendistro_security.ssl.http.enabled_protocols";
|
||||
public static final String OPENDISTRO_SECURITY_SSL_CLIENT_EXTERNAL_CONTEXT_ID = "opendistro_security.ssl.client.external_context_id";
|
||||
public static final String OPENDISTRO_SECURITY_SSL_TRANSPORT_PRINCIPAL_EXTRACTOR_CLASS = "opendistro_security.ssl.transport.principal_extractor_class";
|
||||
|
||||
public static final String OPENDISTRO_SECURITY_SSL_HTTP_CRL_FILE = "opendistro_security.ssl.http.crl.file_path";
|
||||
public static final String OPENDISTRO_SECURITY_SSL_HTTP_CRL_VALIDATE = "opendistro_security.ssl.http.crl.validate";
|
||||
public static final String OPENDISTRO_SECURITY_SSL_HTTP_CRL_PREFER_CRLFILE_OVER_OCSP = "opendistro_security.ssl.http.crl.prefer_crlfile_over_ocsp";
|
||||
public static final String OPENDISTRO_SECURITY_SSL_HTTP_CRL_CHECK_ONLY_END_ENTITIES = "opendistro_security.ssl.http.crl.check_only_end_entities";
|
||||
public static final String OPENDISTRO_SECURITY_SSL_HTTP_CRL_DISABLE_OCSP = "opendistro_security.ssl.http.crl.disable_ocsp";
|
||||
public static final String OPENDISTRO_SECURITY_SSL_HTTP_CRL_DISABLE_CRLDP = "opendistro_security.ssl.http.crl.disable_crldp";
|
||||
public static final String OPENDISTRO_SECURITY_SSL_HTTP_CRL_VALIDATION_DATE = "opendistro_security.ssl.http.crl.validation_date";
|
||||
|
||||
public static final String OPENDISTRO_SECURITY_SSL_ALLOW_CLIENT_INITIATED_RENEGOTIATION = "opendistro_security.ssl.allow_client_initiated_renegotiation";
|
||||
|
||||
public static final String DEFAULT_STORE_PASSWORD = "changeit"; //#16
|
||||
|
||||
public static final String JDK_TLS_REJECT_CLIENT_INITIATED_RENEGOTIATION = "jdk.tls.rejectClientInitiatedRenegotiation";
|
||||
|
||||
private static final String[] _SECURE_SSL_PROTOCOLS = {"TLSv1.3", "TLSv1.2", "TLSv1.1"};
|
||||
|
||||
public static final String[] getSecureSSLProtocols(Settings settings, boolean http)
|
||||
{
|
||||
List<String> configuredProtocols = null;
|
||||
|
||||
if(settings != null) {
|
||||
if(http) {
|
||||
configuredProtocols = settings.getAsList(OPENDISTRO_SECURITY_SSL_HTTP_ENABLED_PROTOCOLS, Collections.emptyList());
|
||||
} else {
|
||||
configuredProtocols = settings.getAsList(OPENDISTRO_SECURITY_SSL_TRANSPORT_ENABLED_PROTOCOLS, Collections.emptyList());
|
||||
}
|
||||
}
|
||||
|
||||
if(configuredProtocols != null && configuredProtocols.size() > 0) {
|
||||
return configuredProtocols.toArray(new String[0]);
|
||||
}
|
||||
|
||||
return _SECURE_SSL_PROTOCOLS.clone();
|
||||
}
|
||||
|
||||
// @formatter:off
|
||||
private static final String[] _SECURE_SSL_CIPHERS =
|
||||
{
|
||||
//TLS_<key exchange and authentication algorithms>_WITH_<bulk cipher and message authentication algorithms>
|
||||
|
||||
//Example (including unsafe ones)
|
||||
//Protocol: TLS, SSL
|
||||
//Key Exchange RSA, Diffie-Hellman, ECDH, SRP, PSK
|
||||
//Authentication RSA, DSA, ECDSA
|
||||
//Bulk Ciphers RC4, 3DES, AES
|
||||
//Message Authentication HMAC-SHA256, HMAC-SHA1, HMAC-MD5
|
||||
|
||||
|
||||
//thats what chrome 48 supports (https://cc.dcsec.uni-hannover.de/)
|
||||
//(c0,2b)ECDHE-ECDSA-AES128-GCM-SHA256128 BitKey exchange: ECDH, encryption: AES, MAC: SHA256.
|
||||
//(c0,2f)ECDHE-RSA-AES128-GCM-SHA256128 BitKey exchange: ECDH, encryption: AES, MAC: SHA256.
|
||||
//(00,9e)DHE-RSA-AES128-GCM-SHA256128 BitKey exchange: DH, encryption: AES, MAC: SHA256.
|
||||
//(cc,14)ECDHE-ECDSA-CHACHA20-POLY1305-SHA256128 BitKey exchange: ECDH, encryption: ChaCha20 Poly1305, MAC: SHA256.
|
||||
//(cc,13)ECDHE-RSA-CHACHA20-POLY1305-SHA256128 BitKey exchange: ECDH, encryption: ChaCha20 Poly1305, MAC: SHA256.
|
||||
//(c0,0a)ECDHE-ECDSA-AES256-SHA256 BitKey exchange: ECDH, encryption: AES, MAC: SHA1.
|
||||
//(c0,14)ECDHE-RSA-AES256-SHA256 BitKey exchange: ECDH, encryption: AES, MAC: SHA1.
|
||||
//(00,39)DHE-RSA-AES256-SHA256 BitKey exchange: DH, encryption: AES, MAC: SHA1.
|
||||
//(c0,09)ECDHE-ECDSA-AES128-SHA128 BitKey exchange: ECDH, encryption: AES, MAC: SHA1.
|
||||
//(c0,13)ECDHE-RSA-AES128-SHA128 BitKey exchange: ECDH, encryption: AES, MAC: SHA1.
|
||||
//(00,33)DHE-RSA-AES128-SHA128 BitKey exchange: DH, encryption: AES, MAC: SHA1.
|
||||
//(00,9c)RSA-AES128-GCM-SHA256128 BitKey exchange: RSA, encryption: AES, MAC: SHA256.
|
||||
//(00,35)RSA-AES256-SHA256 BitKey exchange: RSA, encryption: AES, MAC: SHA1.
|
||||
//(00,2f)RSA-AES128-SHA128 BitKey exchange: RSA, encryption: AES, MAC: SHA1.
|
||||
//(00,0a)RSA-3DES-EDE-SHA168 BitKey exchange: RSA, encryption: 3DES, MAC: SHA1.
|
||||
|
||||
//thats what firefox 42 supports (https://cc.dcsec.uni-hannover.de/)
|
||||
//(c0,2b) ECDHE-ECDSA-AES128-GCM-SHA256
|
||||
//(c0,2f) ECDHE-RSA-AES128-GCM-SHA256
|
||||
//(c0,0a) ECDHE-ECDSA-AES256-SHA
|
||||
//(c0,09) ECDHE-ECDSA-AES128-SHA
|
||||
//(c0,13) ECDHE-RSA-AES128-SHA
|
||||
//(c0,14) ECDHE-RSA-AES256-SHA
|
||||
//(00,33) DHE-RSA-AES128-SHA
|
||||
//(00,39) DHE-RSA-AES256-SHA
|
||||
//(00,2f) RSA-AES128-SHA
|
||||
//(00,35) RSA-AES256-SHA
|
||||
//(00,0a) RSA-3DES-EDE-SHA
|
||||
|
||||
//Mozilla modern browsers
|
||||
//https://wiki.mozilla.org/Security/Server_Side_TLS
|
||||
"TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256",
|
||||
"TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256",
|
||||
"TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384",
|
||||
"TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384",
|
||||
"TLS_DHE_RSA_WITH_AES_128_GCM_SHA256",
|
||||
"TLS_DHE_DSS_WITH_AES_128_GCM_SHA256",
|
||||
"TLS_DHE_DSS_WITH_AES_256_GCM_SHA384",
|
||||
"TLS_DHE_RSA_WITH_AES_256_GCM_SHA384",
|
||||
"TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256",
|
||||
"TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256",
|
||||
"TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA",
|
||||
"TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA",
|
||||
"TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384",
|
||||
"TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384",
|
||||
"TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA",
|
||||
"TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA",
|
||||
"TLS_DHE_RSA_WITH_AES_128_CBC_SHA256",
|
||||
"TLS_DHE_RSA_WITH_AES_128_CBC_SHA",
|
||||
"TLS_DHE_DSS_WITH_AES_128_CBC_SHA256",
|
||||
"TLS_DHE_RSA_WITH_AES_256_CBC_SHA256",
|
||||
"TLS_DHE_DSS_WITH_AES_256_CBC_SHA",
|
||||
"TLS_DHE_RSA_WITH_AES_256_CBC_SHA",
|
||||
|
||||
//TLS 1.3 Java
|
||||
"TLS_AES_128_GCM_SHA256",
|
||||
"TLS_AES_256_GCM_SHA384",
|
||||
|
||||
//TLS 1.3 OpenSSL
|
||||
"TLS_CHACHA20_POLY1305_SHA256",
|
||||
|
||||
//IBM
|
||||
"SSL_ECDHE_RSA_WITH_AES_128_GCM_SHA256",
|
||||
"SSL_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256",
|
||||
"SSL_ECDHE_RSA_WITH_AES_256_GCM_SHA384",
|
||||
"SSL_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384",
|
||||
"SSL_DHE_RSA_WITH_AES_128_GCM_SHA256",
|
||||
"SSL_DHE_DSS_WITH_AES_128_GCM_SHA256",
|
||||
"SSL_DHE_DSS_WITH_AES_256_GCM_SHA384",
|
||||
"SSL_DHE_RSA_WITH_AES_256_GCM_SHA384",
|
||||
"SSL_ECDHE_RSA_WITH_AES_128_CBC_SHA256",
|
||||
"SSL_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256",
|
||||
"SSL_ECDHE_RSA_WITH_AES_128_CBC_SHA",
|
||||
"SSL_ECDHE_ECDSA_WITH_AES_128_CBC_SHA",
|
||||
"SSL_ECDHE_RSA_WITH_AES_256_CBC_SHA384",
|
||||
"SSL_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384",
|
||||
"SSL_ECDHE_RSA_WITH_AES_256_CBC_SHA",
|
||||
"SSL_ECDHE_ECDSA_WITH_AES_256_CBC_SHA",
|
||||
"SSL_DHE_RSA_WITH_AES_128_CBC_SHA256",
|
||||
"SSL_DHE_RSA_WITH_AES_128_CBC_SHA",
|
||||
"SSL_DHE_DSS_WITH_AES_128_CBC_SHA256",
|
||||
"SSL_DHE_RSA_WITH_AES_256_CBC_SHA256",
|
||||
"SSL_DHE_DSS_WITH_AES_256_CBC_SHA",
|
||||
"SSL_DHE_RSA_WITH_AES_256_CBC_SHA"
|
||||
|
||||
//some others
|
||||
//"TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384",
|
||||
//"TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384",
|
||||
//"TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384",
|
||||
//"TLS_DHE_RSA_WITH_AES_256_CBC_SHA",
|
||||
//"TLS_DHE_RSA_WITH_AES_256_GCM_SHA384",
|
||||
//"TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256",
|
||||
//"TLS_DHE_RSA_WITH_AES_128_GCM_SHA256",
|
||||
//"TLS_DHE_RSA_WITH_AES_128_CBC_SHA",
|
||||
//"TLS_RSA_WITH_AES_128_CBC_SHA256",
|
||||
//"TLS_RSA_WITH_AES_128_GCM_SHA256",
|
||||
//"TLS_RSA_WITH_AES_128_CBC_SHA",
|
||||
//"TLS_RSA_WITH_AES_256_CBC_SHA",
|
||||
};
|
||||
// @formatter:on
|
||||
|
||||
public static final List<String> getSecureSSLCiphers(Settings settings, boolean http) {
|
||||
|
||||
List<String> configuredCiphers = null;
|
||||
|
||||
if(settings != null) {
|
||||
if(http) {
|
||||
configuredCiphers = settings.getAsList(OPENDISTRO_SECURITY_SSL_HTTP_ENABLED_CIPHERS, Collections.emptyList());
|
||||
} else {
|
||||
configuredCiphers = settings.getAsList(OPENDISTRO_SECURITY_SSL_TRANSPORT_ENABLED_CIPHERS, Collections.emptyList());
|
||||
}
|
||||
}
|
||||
|
||||
if(configuredCiphers != null && configuredCiphers.size() > 0) {
|
||||
return configuredCiphers;
|
||||
}
|
||||
|
||||
return Collections.unmodifiableList(Arrays.asList(_SECURE_SSL_CIPHERS));
|
||||
}
|
||||
|
||||
private SSLConfigConstants() {
|
||||
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,273 @@
|
||||
/*
|
||||
* Copyright 2015-2018 _floragunn_ GmbH
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Portions Copyright 2019 Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License").
|
||||
* You may not use this file except in compliance with the License.
|
||||
* A copy of the License is located at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* or in the "license" file accompanying this file. This file is distributed
|
||||
* on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
|
||||
* express or implied. See the License for the specific language governing
|
||||
* permissions and limitations under the License.
|
||||
*/
|
||||
|
||||
package com.amazon.opendistroforelasticsearch.security.ssl.util;
|
||||
|
||||
import io.netty.handler.ssl.SslHandler;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.nio.file.Path;
|
||||
import java.security.AccessController;
|
||||
import java.security.KeyStore;
|
||||
import java.security.PrivilegedAction;
|
||||
import java.security.cert.CRL;
|
||||
import java.security.cert.Certificate;
|
||||
import java.security.cert.CertificateFactory;
|
||||
import java.security.cert.X509Certificate;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.Date;
|
||||
import java.util.Map.Entry;
|
||||
|
||||
import javax.net.ssl.SSLEngine;
|
||||
import javax.net.ssl.SSLPeerUnverifiedException;
|
||||
import javax.net.ssl.SSLSession;
|
||||
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
import org.elasticsearch.ElasticsearchException;
|
||||
import org.elasticsearch.ExceptionsHelper;
|
||||
import org.elasticsearch.SpecialPermission;
|
||||
import org.elasticsearch.common.settings.Settings;
|
||||
import org.elasticsearch.common.util.concurrent.ThreadContext;
|
||||
import org.elasticsearch.env.Environment;
|
||||
import org.elasticsearch.http.netty4.Netty4HttpRequest;
|
||||
import org.elasticsearch.rest.RestRequest;
|
||||
|
||||
import com.amazon.opendistroforelasticsearch.security.ssl.transport.PrincipalExtractor;
|
||||
import com.amazon.opendistroforelasticsearch.security.ssl.transport.PrincipalExtractor.Type;
|
||||
|
||||
public class SSLRequestHelper {
|
||||
|
||||
private static final Logger log = LogManager.getLogger(SSLRequestHelper.class);
|
||||
|
||||
public static class SSLInfo {
|
||||
private final X509Certificate[] x509Certs;
|
||||
private final X509Certificate[] localCertificates;
|
||||
private final String principal;
|
||||
private final String protocol;
|
||||
private final String cipher;
|
||||
|
||||
public SSLInfo(final X509Certificate[] x509Certs, final String principal, final String protocol, final String cipher) {
|
||||
this(x509Certs, principal, protocol, cipher, null);
|
||||
}
|
||||
|
||||
public SSLInfo(final X509Certificate[] x509Certs, final String principal, final String protocol, final String cipher, X509Certificate[] localCertificates) {
|
||||
super();
|
||||
this.x509Certs = x509Certs;
|
||||
this.principal = principal;
|
||||
this.protocol = protocol;
|
||||
this.cipher = cipher;
|
||||
this.localCertificates = localCertificates;
|
||||
}
|
||||
|
||||
public X509Certificate[] getX509Certs() {
|
||||
return x509Certs == null ? null : x509Certs.clone();
|
||||
}
|
||||
|
||||
public X509Certificate[] getLocalCertificates() {
|
||||
return localCertificates == null ? null : localCertificates.clone();
|
||||
}
|
||||
|
||||
public String getPrincipal() {
|
||||
return principal;
|
||||
}
|
||||
|
||||
public String getProtocol() {
|
||||
return protocol;
|
||||
}
|
||||
|
||||
public String getCipher() {
|
||||
return cipher;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "SSLInfo [x509Certs=" + Arrays.toString(x509Certs) + ", principal=" + principal + ", protocol=" + protocol + ", cipher="
|
||||
+ cipher + "]";
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public static SSLInfo getSSLInfo(final Settings settings, final Path configPath, final RestRequest request, PrincipalExtractor principalExtractor) throws SSLPeerUnverifiedException {
|
||||
|
||||
if(request == null || !(request instanceof Netty4HttpRequest)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
final Netty4HttpRequest nettyHttpRequest = (Netty4HttpRequest) request;
|
||||
final SslHandler sslhandler = (SslHandler) nettyHttpRequest.getChannel().pipeline().get("ssl_http");
|
||||
|
||||
if(sslhandler == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
final SSLEngine engine = sslhandler.engine();
|
||||
final SSLSession session = engine.getSession();
|
||||
|
||||
X509Certificate[] x509Certs = null;
|
||||
final String protocol = session.getProtocol();
|
||||
final String cipher = session.getCipherSuite();
|
||||
String principal = null;
|
||||
boolean validationFailure = false;
|
||||
|
||||
if (engine.getNeedClientAuth() || engine.getWantClientAuth()) {
|
||||
|
||||
try {
|
||||
final Certificate[] certs = session.getPeerCertificates();
|
||||
|
||||
if (certs != null && certs.length > 0 && certs[0] instanceof X509Certificate) {
|
||||
x509Certs = Arrays.copyOf(certs, certs.length, X509Certificate[].class);
|
||||
final X509Certificate[] x509CertsF = x509Certs;
|
||||
|
||||
final SecurityManager sm = System.getSecurityManager();
|
||||
|
||||
if (sm != null) {
|
||||
sm.checkPermission(new SpecialPermission());
|
||||
}
|
||||
|
||||
validationFailure = AccessController.doPrivileged(new PrivilegedAction<Boolean>() {
|
||||
@Override
|
||||
public Boolean run() {
|
||||
return !validate(x509CertsF, settings, configPath);
|
||||
}
|
||||
});
|
||||
|
||||
if(validationFailure) {
|
||||
throw new SSLPeerUnverifiedException("Unable to validate certificate (CRL)");
|
||||
}
|
||||
principal = principalExtractor == null?null: principalExtractor.extractPrincipal(x509Certs[0], Type.HTTP);
|
||||
} else if (engine.getNeedClientAuth()) {
|
||||
final ElasticsearchException ex = new ElasticsearchException("No client certificates found but such are needed (Security 9).");
|
||||
throw ex;
|
||||
}
|
||||
|
||||
} catch (final SSLPeerUnverifiedException e) {
|
||||
if (engine.getNeedClientAuth() || validationFailure) {
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Certificate[] localCerts = session.getLocalCertificates();
|
||||
return new SSLInfo(x509Certs, principal, protocol, cipher, localCerts==null?null:Arrays.copyOf(localCerts, localCerts.length, X509Certificate[].class));
|
||||
}
|
||||
|
||||
public static boolean containsBadHeader(final ThreadContext context, String prefix) {
|
||||
if (context != null) {
|
||||
for (final Entry<String, String> header : context.getHeaders().entrySet()) {
|
||||
if (header != null && header.getKey() != null && header.getKey().trim().toLowerCase().startsWith(prefix)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private static boolean validate(X509Certificate[] x509Certs, final Settings settings, final Path configPath) {
|
||||
|
||||
final boolean validateCrl = settings.getAsBoolean(SSLConfigConstants.OPENDISTRO_SECURITY_SSL_HTTP_CRL_VALIDATE, false);
|
||||
|
||||
if(log.isTraceEnabled()) {
|
||||
log.trace("validateCrl: "+validateCrl);
|
||||
}
|
||||
|
||||
if(!validateCrl) {
|
||||
return true;
|
||||
}
|
||||
|
||||
final Environment env = new Environment(settings, configPath);
|
||||
|
||||
try {
|
||||
|
||||
Collection<? extends CRL> crls = null;
|
||||
final String crlFile = settings.get(SSLConfigConstants.OPENDISTRO_SECURITY_SSL_HTTP_CRL_FILE);
|
||||
|
||||
if(crlFile != null) {
|
||||
final File crl = env.configFile().resolve(crlFile).toAbsolutePath().toFile();
|
||||
try(FileInputStream crlin = new FileInputStream(crl)) {
|
||||
crls = CertificateFactory.getInstance("X.509").generateCRLs(crlin);
|
||||
}
|
||||
|
||||
if(log.isTraceEnabled()) {
|
||||
log.trace("crls from file: "+crls.size());
|
||||
}
|
||||
} else {
|
||||
if(log.isTraceEnabled()) {
|
||||
log.trace("no crl file configured");
|
||||
}
|
||||
}
|
||||
|
||||
final String truststore = settings.get(SSLConfigConstants.OPENDISTRO_SECURITY_SSL_HTTP_TRUSTSTORE_FILEPATH);
|
||||
CertificateValidator validator = null;
|
||||
|
||||
if(truststore != null) {
|
||||
final String truststoreType = settings.get(SSLConfigConstants.OPENDISTRO_SECURITY_SSL_HTTP_TRUSTSTORE_TYPE, "JKS");
|
||||
final String truststorePassword = settings.get(SSLConfigConstants.OPENDISTRO_SECURITY_SSL_HTTP_TRUSTSTORE_PASSWORD, "changeit");
|
||||
//final String truststoreAlias = settings.get(SSLConfigConstants.OPENDISTRO_SECURITY_SSL_HTTP_TRUSTSTORE_ALIAS, null);
|
||||
|
||||
final KeyStore ts = KeyStore.getInstance(truststoreType);
|
||||
try(FileInputStream fin = new FileInputStream(new File(env.configFile().resolve(truststore).toAbsolutePath().toString()))) {
|
||||
ts.load(fin, (truststorePassword == null || truststorePassword.length() == 0) ?null:truststorePassword.toCharArray());
|
||||
}
|
||||
validator = new CertificateValidator(ts, crls);
|
||||
} else {
|
||||
final File trustedCas = env.configFile().resolve(settings.get(SSLConfigConstants.OPENDISTRO_SECURITY_SSL_HTTP_PEMTRUSTEDCAS_FILEPATH, "")).toAbsolutePath().toFile();
|
||||
try(FileInputStream trin = new FileInputStream(trustedCas)) {
|
||||
Collection<? extends Certificate> cert = (Collection<? extends Certificate>) CertificateFactory.getInstance("X.509").generateCertificates(trin);
|
||||
validator = new CertificateValidator(cert.toArray(new X509Certificate[0]), crls);
|
||||
}
|
||||
}
|
||||
|
||||
validator.setEnableCRLDP(!settings.getAsBoolean(SSLConfigConstants.OPENDISTRO_SECURITY_SSL_HTTP_CRL_DISABLE_CRLDP, false));
|
||||
validator.setEnableOCSP(!settings.getAsBoolean(SSLConfigConstants.OPENDISTRO_SECURITY_SSL_HTTP_CRL_DISABLE_OCSP, false));
|
||||
validator.setCheckOnlyEndEntities(settings.getAsBoolean(SSLConfigConstants.OPENDISTRO_SECURITY_SSL_HTTP_CRL_CHECK_ONLY_END_ENTITIES, true));
|
||||
validator.setPreferCrl(settings.getAsBoolean(SSLConfigConstants.OPENDISTRO_SECURITY_SSL_HTTP_CRL_PREFER_CRLFILE_OVER_OCSP, false));
|
||||
Long dateTimestamp = settings.getAsLong(SSLConfigConstants.OPENDISTRO_SECURITY_SSL_HTTP_CRL_VALIDATION_DATE, null);
|
||||
if(dateTimestamp != null && dateTimestamp.longValue() < 0) {
|
||||
dateTimestamp = null;
|
||||
}
|
||||
validator.setDate(dateTimestamp==null?null:new Date(dateTimestamp.longValue()));
|
||||
validator.validate(x509Certs);
|
||||
|
||||
return true;
|
||||
|
||||
} catch (Exception e) {
|
||||
if(log.isDebugEnabled()) {
|
||||
log.debug("Unable to validate CRL: "+ExceptionsHelper.stackTrace(e));
|
||||
}
|
||||
log.warn("Unable to validate CRL: "+ExceptionUtils.getRootCause(e));
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
@ -0,0 +1,53 @@
|
||||
/*
|
||||
* Copyright 2015-2018 _floragunn_ GmbH
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Portions Copyright 2019 Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License").
|
||||
* You may not use this file except in compliance with the License.
|
||||
* A copy of the License is located at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* or in the "license" file accompanying this file. This file is distributed
|
||||
* on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
|
||||
* express or implied. See the License for the specific language governing
|
||||
* permissions and limitations under the License.
|
||||
*/
|
||||
|
||||
package com.amazon.opendistroforelasticsearch.security.ssl.util;
|
||||
|
||||
|
||||
public class Utils {
|
||||
public static <T> T coalesce(T first, T... more) {
|
||||
if (first != null) {
|
||||
return first;
|
||||
}
|
||||
|
||||
if(more == null || more.length == 0) {
|
||||
return null;
|
||||
}
|
||||
|
||||
for (int i = 0; i < more.length; i++) {
|
||||
T t = more[i];
|
||||
if(t != null) {
|
||||
return t;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
@ -0,0 +1,365 @@
|
||||
/*
|
||||
* Copyright 2015-2018 _floragunn_ GmbH
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Portions Copyright 2019 Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License").
|
||||
* You may not use this file except in compliance with the License.
|
||||
* A copy of the License is located at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* or in the "license" file accompanying this file. This file is distributed
|
||||
* on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
|
||||
* express or implied. See the License for the specific language governing
|
||||
* permissions and limitations under the License.
|
||||
*/
|
||||
|
||||
package com.amazon.opendistroforelasticsearch.security.ssl;
|
||||
|
||||
import io.netty.handler.ssl.OpenSsl;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.UnsupportedEncodingException;
|
||||
import java.net.URL;
|
||||
import java.net.URLDecoder;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.Paths;
|
||||
import java.security.KeyStore;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
|
||||
import javax.net.ssl.SSLContext;
|
||||
|
||||
import org.apache.commons.io.FileUtils;
|
||||
import org.apache.commons.io.IOUtils;
|
||||
import org.apache.http.client.methods.CloseableHttpResponse;
|
||||
import org.apache.http.client.methods.HttpGet;
|
||||
import org.apache.http.config.SocketConfig;
|
||||
import org.apache.http.conn.ssl.NoopHostnameVerifier;
|
||||
import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
|
||||
import org.apache.http.ssl.SSLContextBuilder;
|
||||
import org.apache.http.ssl.SSLContexts;
|
||||
import org.apache.http.impl.client.CloseableHttpClient;
|
||||
import org.apache.http.impl.client.HttpClientBuilder;
|
||||
import org.apache.http.impl.client.HttpClients;
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
import org.elasticsearch.ElasticsearchTimeoutException;
|
||||
import org.elasticsearch.action.admin.cluster.health.ClusterHealthResponse;
|
||||
import org.elasticsearch.action.admin.cluster.node.info.NodeInfo;
|
||||
import org.elasticsearch.action.admin.cluster.node.info.NodesInfoRequest;
|
||||
import org.elasticsearch.action.admin.cluster.node.info.NodesInfoResponse;
|
||||
import org.elasticsearch.client.Client;
|
||||
import org.elasticsearch.client.transport.TransportClient;
|
||||
import org.elasticsearch.cluster.health.ClusterHealthStatus;
|
||||
import org.elasticsearch.common.settings.Settings;
|
||||
import org.elasticsearch.common.transport.TransportAddress;
|
||||
import org.elasticsearch.common.unit.TimeValue;
|
||||
import org.elasticsearch.node.Node;
|
||||
import org.elasticsearch.node.PluginAwareNode;
|
||||
import org.elasticsearch.plugins.Plugin;
|
||||
import org.elasticsearch.transport.Netty4Plugin;
|
||||
import org.junit.After;
|
||||
import org.junit.Before;
|
||||
import org.junit.Rule;
|
||||
import org.junit.rules.TestName;
|
||||
import org.junit.rules.TestWatcher;
|
||||
import org.junit.runner.Description;
|
||||
|
||||
import com.amazon.opendistroforelasticsearch.security.ssl.OpenDistroSecuritySSLPlugin;
|
||||
|
||||
@SuppressWarnings({"unchecked"})
|
||||
public abstract class AbstractUnitTest {
|
||||
|
||||
static {
|
||||
|
||||
System.out.println("OS: " + System.getProperty("os.name") + " " + System.getProperty("os.arch") + " "
|
||||
+ System.getProperty("os.version"));
|
||||
System.out.println("Java Version: " + System.getProperty("java.version") + " " + System.getProperty("java.vendor"));
|
||||
System.out.println("JVM Impl.: " + System.getProperty("java.vm.version") + " " + System.getProperty("java.vm.vendor") + " "
|
||||
+ System.getProperty("java.vm.name"));
|
||||
System.out.println("Open SSL available: "+OpenSsl.isAvailable());
|
||||
System.out.println("Open SSL version: "+OpenSsl.versionString());
|
||||
}
|
||||
|
||||
@Rule
|
||||
public TestName name = new TestName();
|
||||
protected final String clustername = "opendistro_security_ssl_testcluster";
|
||||
|
||||
private Node esNode1;
|
||||
private Node esNode2;
|
||||
private Node esNode3;
|
||||
private String httpHost = null;
|
||||
private int httpPort = -1;
|
||||
protected String nodeHost;
|
||||
protected int nodePort;
|
||||
protected boolean enableHTTPClientSSL = false;
|
||||
protected boolean enableHTTPClientSSLv3Only = false;
|
||||
protected boolean sendHTTPClientCertificate = false;
|
||||
protected boolean trustHTTPServerCertificate = false;
|
||||
protected String keystore = "node-0-keystore.jks";
|
||||
|
||||
@Rule
|
||||
public final TestWatcher testWatcher = new TestWatcher() {
|
||||
@Override
|
||||
protected void starting(final Description description) {
|
||||
final String methodName = description.getMethodName();
|
||||
String className = description.getClassName();
|
||||
className = className.substring(className.lastIndexOf('.') + 1);
|
||||
System.out.println("---------------- Starting JUnit-test: " + className + " " + methodName + " ----------------");
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void failed(final Throwable e, final Description description) {
|
||||
final String methodName = description.getMethodName();
|
||||
String className = description.getClassName();
|
||||
className = className.substring(className.lastIndexOf('.') + 1);
|
||||
System.out.println(">>>> " + className + " " + methodName + " FAILED due to " + e);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void finished(final Description description) {
|
||||
// System.out.println("-----------------------------------------------------------------------------------------");
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
protected AbstractUnitTest() {
|
||||
super();
|
||||
}
|
||||
|
||||
// @formatter:off
|
||||
private Settings.Builder getDefaultSettingsBuilder(final int nodenum, final boolean dataNode, final boolean masterNode) {
|
||||
|
||||
return Settings.builder()
|
||||
.put("node.name", "opendistro_security_testnode_" + nodenum)
|
||||
.put("node.data", dataNode)
|
||||
.put("node.master", masterNode)
|
||||
.put("cluster.name", clustername)
|
||||
.put("path.data", "data/data")
|
||||
.put("path.logs", "data/logs")
|
||||
.put("http.enabled", !dataNode)
|
||||
.put("cluster.routing.allocation.disk.watermark.high","1mb")
|
||||
.put("cluster.routing.allocation.disk.watermark.low","1mb")
|
||||
.put("cluster.routing.allocation.disk.watermark.flood_stage", "1mb")
|
||||
.put("http.cors.enabled", true)
|
||||
.put("transport.type.default", "netty4")
|
||||
.put("node.max_local_storage_nodes", 3)
|
||||
.put("path.home",".");
|
||||
|
||||
|
||||
}
|
||||
// @formatter:on
|
||||
|
||||
protected final Logger log = LogManager.getLogger(this.getClass());
|
||||
|
||||
protected final String getHttpServerUri() {
|
||||
final String address = "http" + (enableHTTPClientSSL ? "s" : "") + "://" + httpHost + ":" + httpPort;
|
||||
log.debug("Connect to {}", address);
|
||||
return address;
|
||||
}
|
||||
|
||||
public final void startES(final Settings settings) throws Exception {
|
||||
|
||||
FileUtils.deleteDirectory(new File("data"));
|
||||
|
||||
esNode1 = new PluginAwareNode(getDefaultSettingsBuilder(1, false, true).put(
|
||||
settings == null ? Settings.Builder.EMPTY_SETTINGS : settings).build(), Netty4Plugin.class, OpenDistroSecuritySSLPlugin.class);
|
||||
esNode2 = new PluginAwareNode(getDefaultSettingsBuilder(2, true, true).put(
|
||||
settings == null ? Settings.Builder.EMPTY_SETTINGS : settings).build(), Netty4Plugin.class, OpenDistroSecuritySSLPlugin.class);
|
||||
esNode3 = new PluginAwareNode(getDefaultSettingsBuilder(3, true, false).put(
|
||||
settings == null ? Settings.Builder.EMPTY_SETTINGS : settings).build(), Netty4Plugin.class, OpenDistroSecuritySSLPlugin.class);
|
||||
|
||||
esNode1.start();
|
||||
esNode2.start();
|
||||
esNode3.start();
|
||||
|
||||
waitForGreenClusterState(esNode1.client());
|
||||
}
|
||||
|
||||
@Before
|
||||
public void setUp() throws Exception {
|
||||
enableHTTPClientSSL = false;
|
||||
enableHTTPClientSSLv3Only = false;
|
||||
sendHTTPClientCertificate = false;
|
||||
trustHTTPServerCertificate = false;
|
||||
keystore = "node-0-keystore.jks";
|
||||
}
|
||||
|
||||
@After
|
||||
public void tearDown() throws Exception {
|
||||
|
||||
if (esNode3 != null) {
|
||||
esNode3.close();
|
||||
}
|
||||
|
||||
if (esNode2 != null) {
|
||||
esNode2.close();
|
||||
}
|
||||
|
||||
if (esNode1 != null) {
|
||||
esNode1.close();
|
||||
}
|
||||
}
|
||||
|
||||
protected void waitForGreenClusterState(final Client client) throws IOException {
|
||||
waitForCluster(ClusterHealthStatus.GREEN, TimeValue.timeValueSeconds(30), client);
|
||||
}
|
||||
|
||||
protected void waitForCluster(final ClusterHealthStatus status, final TimeValue timeout, final Client client) throws IOException {
|
||||
try {
|
||||
log.debug("waiting for cluster state {}", status.name());
|
||||
final ClusterHealthResponse healthResponse = client.admin().cluster().prepareHealth().setWaitForStatus(status)
|
||||
.setTimeout(timeout).setWaitForNodes("3").execute().actionGet();
|
||||
if (healthResponse.isTimedOut()) {
|
||||
throw new IOException("cluster state is " + healthResponse.getStatus().name() + " with "
|
||||
+ healthResponse.getNumberOfNodes() + " nodes");
|
||||
} else {
|
||||
log.debug("... cluster state ok " + healthResponse.getStatus().name() + " with " + healthResponse.getNumberOfNodes()
|
||||
+ " nodes");
|
||||
}
|
||||
|
||||
final NodesInfoResponse res = esNode1.client().admin().cluster().nodesInfo(new NodesInfoRequest()).actionGet();
|
||||
|
||||
final List<NodeInfo> nodes = res.getNodes();
|
||||
|
||||
for (NodeInfo nodeInfo: nodes) {
|
||||
if (nodeInfo.getHttp() != null && nodeInfo.getHttp().address() != null) {
|
||||
final TransportAddress is = nodeInfo.getHttp().address().publishAddress();
|
||||
httpPort = is.getPort();
|
||||
httpHost = is.getAddress();
|
||||
}
|
||||
|
||||
final TransportAddress is = nodeInfo.getTransport().getAddress().publishAddress();
|
||||
nodePort = is.getPort();
|
||||
nodeHost = is.getAddress();
|
||||
}
|
||||
} catch (final ElasticsearchTimeoutException e) {
|
||||
throw new IOException("timeout, cluster does not respond to health request, cowardly refusing to continue with operations");
|
||||
}
|
||||
}
|
||||
|
||||
public Path getAbsoluteFilePathFromClassPath(final String fileNameFromClasspath) {
|
||||
File file = null;
|
||||
final URL fileUrl = AbstractUnitTest.class.getClassLoader().getResource(fileNameFromClasspath);
|
||||
if (fileUrl != null) {
|
||||
try {
|
||||
file = new File(URLDecoder.decode(fileUrl.getFile(), "UTF-8"));
|
||||
} catch (final UnsupportedEncodingException e) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (file.exists() && file.canRead()) {
|
||||
return Paths.get(file.getAbsolutePath());
|
||||
} else {
|
||||
log.error("Cannot read from {}, maybe the file does not exists? ", file.getAbsolutePath());
|
||||
}
|
||||
|
||||
} else {
|
||||
log.error("Failed to load " + fileNameFromClasspath);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
protected String executeSimpleRequest(final String request) throws Exception {
|
||||
|
||||
CloseableHttpClient httpClient = null;
|
||||
CloseableHttpResponse response = null;
|
||||
try {
|
||||
httpClient = getHTTPClient();
|
||||
response = httpClient.execute(new HttpGet(getHttpServerUri() + "/" + request));
|
||||
|
||||
if (response.getStatusLine().getStatusCode() >= 300) {
|
||||
throw new Exception("Statuscode " + response.getStatusLine().getStatusCode()+" - "+response.getStatusLine().getReasonPhrase()+ "-" +IOUtils.toString(response.getEntity().getContent(), StandardCharsets.UTF_8));
|
||||
}
|
||||
|
||||
return IOUtils.toString(response.getEntity().getContent(), StandardCharsets.UTF_8);
|
||||
} finally {
|
||||
|
||||
if (response != null) {
|
||||
response.close();
|
||||
}
|
||||
|
||||
if (httpClient != null) {
|
||||
httpClient.close();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected final CloseableHttpClient getHTTPClient() throws Exception {
|
||||
|
||||
final HttpClientBuilder hcb = HttpClients.custom();
|
||||
|
||||
if (enableHTTPClientSSL) {
|
||||
|
||||
log.debug("Configure HTTP client with SSL");
|
||||
|
||||
final KeyStore myTrustStore = KeyStore.getInstance("JKS");
|
||||
myTrustStore.load(new FileInputStream(getAbsoluteFilePathFromClassPath("truststore.jks").toFile()), "changeit".toCharArray());
|
||||
|
||||
final KeyStore keyStore = KeyStore.getInstance(keystore.toLowerCase().endsWith("p12")?"PKCS12":"JKS");
|
||||
keyStore.load(new FileInputStream(getAbsoluteFilePathFromClassPath(keystore).toFile()), "changeit".toCharArray());
|
||||
|
||||
final SSLContextBuilder sslContextbBuilder = SSLContexts.custom().useProtocol("TLS");
|
||||
|
||||
if (trustHTTPServerCertificate) {
|
||||
sslContextbBuilder.loadTrustMaterial(myTrustStore, null);
|
||||
}
|
||||
|
||||
if (sendHTTPClientCertificate) {
|
||||
sslContextbBuilder.loadKeyMaterial(keyStore, "changeit".toCharArray());
|
||||
}
|
||||
|
||||
final SSLContext sslContext = sslContextbBuilder.build();
|
||||
|
||||
String[] protocols = null;
|
||||
|
||||
if (enableHTTPClientSSLv3Only) {
|
||||
protocols = new String[] { "SSLv3" };
|
||||
} else {
|
||||
protocols = new String[] { "TLSv1", "TLSv1.1", "TLSv1.2" };
|
||||
}
|
||||
|
||||
final SSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactory(sslContext, protocols, null, NoopHostnameVerifier.INSTANCE);
|
||||
|
||||
hcb.setSSLSocketFactory(sslsf);
|
||||
}
|
||||
|
||||
hcb.setDefaultSocketConfig(SocketConfig.custom().setSoTimeout(60 * 1000).build());
|
||||
|
||||
return hcb.build();
|
||||
}
|
||||
|
||||
protected Collection<Class<? extends Plugin>> asCollection(Class<? extends Plugin>... plugins) {
|
||||
return Arrays.asList(plugins);
|
||||
}
|
||||
|
||||
protected class TransportClientImpl extends TransportClient {
|
||||
|
||||
public TransportClientImpl(Settings settings, Collection<Class<? extends Plugin>> plugins) {
|
||||
super(settings, plugins);
|
||||
}
|
||||
|
||||
public TransportClientImpl(Settings settings, Settings defaultSettings, Collection<Class<? extends Plugin>> plugins) {
|
||||
super(settings, defaultSettings, plugins, null);
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,227 @@
|
||||
/*
|
||||
* Copyright 2015-2018 _floragunn_ GmbH
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Portions Copyright 2019 Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License").
|
||||
* You may not use this file except in compliance with the License.
|
||||
* A copy of the License is located at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* or in the "license" file accompanying this file. This file is distributed
|
||||
* on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
|
||||
* express or implied. See the License for the specific language governing
|
||||
* permissions and limitations under the License.
|
||||
*/
|
||||
|
||||
package com.amazon.opendistroforelasticsearch.security.ssl;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.UnsupportedEncodingException;
|
||||
import java.net.URL;
|
||||
import java.net.URLDecoder;
|
||||
import java.security.cert.CRL;
|
||||
import java.security.cert.CertPathBuilderException;
|
||||
import java.security.cert.Certificate;
|
||||
import java.security.cert.CertificateException;
|
||||
import java.security.cert.CertificateFactory;
|
||||
import java.security.cert.CertificateRevokedException;
|
||||
import java.security.cert.X509Certificate;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.Date;
|
||||
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
import org.elasticsearch.ExceptionsHelper;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
|
||||
import com.amazon.opendistroforelasticsearch.security.ssl.util.CertificateValidator;
|
||||
import com.amazon.opendistroforelasticsearch.security.ssl.util.ExceptionUtils;
|
||||
|
||||
public class CertificateValidatorTest {
|
||||
|
||||
public static final Date CRL_DATE = new Date(1525546426000L);
|
||||
protected final Logger log = LogManager.getLogger(this.getClass());
|
||||
|
||||
@Test
|
||||
public void testStaticCRL() throws Exception {
|
||||
|
||||
File staticCrl = getAbsoluteFilePathFromClassPath("crl/revoked.crl");
|
||||
Collection<? extends CRL> crls = null;
|
||||
try(FileInputStream crlin = new FileInputStream(staticCrl)) {
|
||||
crls = CertificateFactory.getInstance("X.509").generateCRLs(crlin);
|
||||
}
|
||||
|
||||
Assert.assertEquals(crls.size(), 1);
|
||||
|
||||
//trust chain incl intermediate certificates (root + intermediates)
|
||||
Collection<? extends Certificate> rootCas;
|
||||
final File trustedCas = getAbsoluteFilePathFromClassPath("chain-ca.pem");
|
||||
try(FileInputStream trin = new FileInputStream(trustedCas)) {
|
||||
rootCas = (Collection<? extends Certificate>) CertificateFactory.getInstance("X.509").generateCertificates(trin);
|
||||
}
|
||||
|
||||
Assert.assertEquals(rootCas.size(), 2);
|
||||
|
||||
//certificate chain to validate (client cert + intermediates but without root)
|
||||
Collection<? extends Certificate> certsToValidate;
|
||||
final File certs = getAbsoluteFilePathFromClassPath("crl/revoked.crt.pem");
|
||||
try(FileInputStream trin = new FileInputStream(certs)) {
|
||||
certsToValidate = (Collection<? extends Certificate>) CertificateFactory.getInstance("X.509").generateCertificates(trin);
|
||||
}
|
||||
|
||||
Assert.assertEquals(certsToValidate.size(), 2);
|
||||
|
||||
CertificateValidator validator = new CertificateValidator(rootCas.toArray(new X509Certificate[0]), crls);
|
||||
validator.setDate(CRL_DATE);
|
||||
try {
|
||||
validator.validate(certsToValidate.toArray(new X509Certificate[0]));
|
||||
Assert.fail();
|
||||
} catch (CertificateException e) {
|
||||
Assert.assertTrue(ExceptionUtils.getRootCause(e) instanceof CertificateRevokedException);
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testStaticCRLOk() throws Exception {
|
||||
|
||||
File staticCrl = getAbsoluteFilePathFromClassPath("crl/revoked.crl");
|
||||
Collection<? extends CRL> crls = null;
|
||||
try(FileInputStream crlin = new FileInputStream(staticCrl)) {
|
||||
crls = CertificateFactory.getInstance("X.509").generateCRLs(crlin);
|
||||
}
|
||||
|
||||
Assert.assertEquals(crls.size(), 1);
|
||||
|
||||
//trust chain incl intermediate certificates (root + intermediates)
|
||||
Collection<? extends Certificate> rootCas;
|
||||
final File trustedCas = getAbsoluteFilePathFromClassPath("chain-ca.pem");
|
||||
try(FileInputStream trin = new FileInputStream(trustedCas)) {
|
||||
rootCas = (Collection<? extends Certificate>) CertificateFactory.getInstance("X.509").generateCertificates(trin);
|
||||
}
|
||||
|
||||
Assert.assertEquals(rootCas.size(), 2);
|
||||
|
||||
//certificate chain to validate (client cert + intermediates but without root)
|
||||
Collection<? extends Certificate> certsToValidate;
|
||||
final File certs = getAbsoluteFilePathFromClassPath("node-0.crt.pem");
|
||||
try(FileInputStream trin = new FileInputStream(certs)) {
|
||||
certsToValidate = (Collection<? extends Certificate>) CertificateFactory.getInstance("X.509").generateCertificates(trin);
|
||||
}
|
||||
|
||||
Assert.assertEquals(certsToValidate.size(), 3);
|
||||
|
||||
CertificateValidator validator = new CertificateValidator(rootCas.toArray(new X509Certificate[0]), crls);
|
||||
validator.setDate(CRL_DATE);
|
||||
try {
|
||||
validator.validate(certsToValidate.toArray(new X509Certificate[0]));
|
||||
} catch (CertificateException e) {
|
||||
Assert.fail(ExceptionsHelper.stackTrace(ExceptionUtils.getRootCause(e)));
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testNoValidationPossible() throws Exception {
|
||||
|
||||
//trust chain incl intermediate certificates (root + intermediates)
|
||||
Collection<? extends Certificate> rootCas;
|
||||
final File trustedCas = getAbsoluteFilePathFromClassPath("chain-ca.pem");
|
||||
try(FileInputStream trin = new FileInputStream(trustedCas)) {
|
||||
rootCas = (Collection<? extends Certificate>) CertificateFactory.getInstance("X.509").generateCertificates(trin);
|
||||
}
|
||||
|
||||
Assert.assertEquals(rootCas.size(), 2);
|
||||
|
||||
//certificate chain to validate (client cert + intermediates but without root)
|
||||
Collection<? extends Certificate> certsToValidate;
|
||||
final File certs = getAbsoluteFilePathFromClassPath("crl/revoked.crt.pem");
|
||||
try(FileInputStream trin = new FileInputStream(certs)) {
|
||||
certsToValidate = (Collection<? extends Certificate>) CertificateFactory.getInstance("X.509").generateCertificates(trin);
|
||||
}
|
||||
|
||||
Assert.assertEquals(certsToValidate.size(), 2);
|
||||
|
||||
CertificateValidator validator = new CertificateValidator(rootCas.toArray(new X509Certificate[0]), Collections.emptyList());
|
||||
validator.setDate(CRL_DATE);
|
||||
try {
|
||||
validator.validate(certsToValidate.toArray(new X509Certificate[0]));
|
||||
Assert.fail();
|
||||
} catch (CertificateException e) {
|
||||
Assert.assertTrue(e.getCause() instanceof CertPathBuilderException);
|
||||
Assert.assertTrue(e.getCause().getMessage().contains("unable to find valid certification path to requested target"));
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCRLDP() throws Exception {
|
||||
|
||||
//trust chain incl intermediate certificates (root + intermediates)
|
||||
Collection<? extends Certificate> rootCas;
|
||||
final File trustedCas = getAbsoluteFilePathFromClassPath("root-ca.pem");
|
||||
try(FileInputStream trin = new FileInputStream(trustedCas)) {
|
||||
rootCas = (Collection<? extends Certificate>) CertificateFactory.getInstance("X.509").generateCertificates(trin);
|
||||
}
|
||||
|
||||
Assert.assertEquals(rootCas.size(), 1);
|
||||
|
||||
//certificate chain to validate (client cert + intermediates but without root)
|
||||
Collection<? extends Certificate> certsToValidate;
|
||||
final File certs = getAbsoluteFilePathFromClassPath("crl/revoked.crt.pem");
|
||||
//final File certs = getAbsoluteFilePathFromClassPath("node-0.crt.pem");
|
||||
try(FileInputStream trin = new FileInputStream(certs)) {
|
||||
certsToValidate = (Collection<? extends Certificate>) CertificateFactory.getInstance("X.509").generateCertificates(trin);
|
||||
}
|
||||
|
||||
Assert.assertEquals(certsToValidate.size(), 2);
|
||||
|
||||
CertificateValidator validator = new CertificateValidator(rootCas.toArray(new X509Certificate[0]), Collections.emptyList());
|
||||
validator.setEnableCRLDP(true);
|
||||
validator.setEnableOCSP(true);
|
||||
validator.setDate(CRL_DATE);
|
||||
try {
|
||||
validator.validate(certsToValidate.toArray(new X509Certificate[0]));
|
||||
Assert.fail();
|
||||
} catch (CertificateException e) {
|
||||
Assert.assertTrue(ExceptionUtils.getRootCause(e) instanceof CertificateRevokedException);
|
||||
}
|
||||
}
|
||||
|
||||
public File getAbsoluteFilePathFromClassPath(final String fileNameFromClasspath) {
|
||||
File file = null;
|
||||
final URL fileUrl = AbstractUnitTest.class.getClassLoader().getResource(fileNameFromClasspath);
|
||||
if (fileUrl != null) {
|
||||
try {
|
||||
file = new File(URLDecoder.decode(fileUrl.getFile(), "UTF-8"));
|
||||
} catch (final UnsupportedEncodingException e) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (file.exists() && file.canRead()) {
|
||||
return file;
|
||||
} else {
|
||||
log.error("Cannot read from {}, maybe the file does not exists? ", file.getAbsolutePath());
|
||||
}
|
||||
|
||||
} else {
|
||||
log.error("Failed to load " + fileNameFromClasspath);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
@ -0,0 +1,180 @@
|
||||
/*
|
||||
* Copyright 2015-2018 _floragunn_ GmbH
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Portions Copyright 2019 Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License").
|
||||
* You may not use this file except in compliance with the License.
|
||||
* A copy of the License is located at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* or in the "license" file accompanying this file. This file is distributed
|
||||
* on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
|
||||
* express or implied. See the License for the specific language governing
|
||||
* permissions and limitations under the License.
|
||||
*/
|
||||
|
||||
package com.amazon.opendistroforelasticsearch.security.ssl;
|
||||
|
||||
import io.netty.handler.ssl.OpenSsl;
|
||||
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
|
||||
import org.elasticsearch.common.settings.Settings;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Assume;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
|
||||
import com.amazon.opendistroforelasticsearch.security.ssl.util.SSLConfigConstants;
|
||||
|
||||
public class OpenSSLTest extends SSLTest {
|
||||
|
||||
@Before
|
||||
public void setup() {
|
||||
allowOpenSSL = true;
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testEnsureOpenSSLAvailability() {
|
||||
//Assert.assertTrue("OpenSSL not available: "+String.valueOf(OpenSsl.unavailabilityCause()), OpenSsl.isAvailable());
|
||||
|
||||
final String openSSLOptional = System.getenv("OPENDISTRO_SECURITY_TEST_OPENSSL_OPT");
|
||||
System.out.println("OPENDISTRO_SECURITY_TEST_OPENSSL_OPT "+openSSLOptional);
|
||||
if(!Boolean.parseBoolean(openSSLOptional)) {
|
||||
System.out.println("OpenSSL must be available");
|
||||
Assert.assertTrue("OpenSSL not available: "+String.valueOf(OpenSsl.unavailabilityCause()), OpenSsl.isAvailable());
|
||||
} else {
|
||||
System.out.println("OpenSSL can be available");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@Test
|
||||
public void testHttps() throws Exception {
|
||||
Assume.assumeTrue(OpenSsl.isAvailable());
|
||||
super.testHttps();
|
||||
}
|
||||
|
||||
@Override
|
||||
@Test
|
||||
public void testHttpsAndNodeSSL() throws Exception {
|
||||
Assume.assumeTrue(OpenSsl.isAvailable());
|
||||
super.testHttpsAndNodeSSL();
|
||||
}
|
||||
|
||||
@Override
|
||||
@Test
|
||||
public void testHttpPlainFail() throws Exception {
|
||||
Assume.assumeTrue(OpenSsl.isAvailable());
|
||||
super.testHttpPlainFail();
|
||||
}
|
||||
|
||||
@Override
|
||||
@Test
|
||||
public void testHttpsNoEnforce() throws Exception {
|
||||
Assume.assumeTrue(OpenSsl.isAvailable());
|
||||
super.testHttpsNoEnforce();
|
||||
}
|
||||
|
||||
@Override
|
||||
@Test
|
||||
public void testHttpsV3Fail() throws Exception {
|
||||
Assume.assumeTrue(OpenSsl.isAvailable());
|
||||
super.testHttpsV3Fail();
|
||||
}
|
||||
|
||||
@Override
|
||||
@Test(timeout=40000)
|
||||
public void testTransportClientSSL() throws Exception {
|
||||
Assume.assumeTrue(OpenSsl.isAvailable());
|
||||
super.testTransportClientSSL();
|
||||
}
|
||||
|
||||
@Override
|
||||
@Test(timeout=40000)
|
||||
public void testNodeClientSSL() throws Exception {
|
||||
Assume.assumeTrue(OpenSsl.isAvailable());
|
||||
super.testNodeClientSSL();
|
||||
}
|
||||
|
||||
@Override
|
||||
@Test(timeout=40000)
|
||||
public void testTransportClientSSLFail() throws Exception {
|
||||
Assume.assumeTrue(OpenSsl.isAvailable());
|
||||
super.testTransportClientSSLFail();
|
||||
}
|
||||
|
||||
@Override
|
||||
@Test
|
||||
public void testHttpsOptionalAuth() throws Exception {
|
||||
Assume.assumeTrue(OpenSsl.isAvailable());
|
||||
super.testHttpsOptionalAuth();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testAvailCiphersOpenSSL() throws Exception {
|
||||
Assume.assumeTrue(OpenSsl.isAvailable());
|
||||
|
||||
// Set<String> openSSLAvailCiphers = new
|
||||
// HashSet<>(OpenSsl.availableCipherSuites());
|
||||
// System.out.println("OpenSSL available ciphers: "+openSSLAvailCiphers);
|
||||
// ECDHE-RSA-AES256-SHA, ECDH-ECDSA-AES256-SHA, DH-DSS-DES-CBC-SHA,
|
||||
// ADH-AES256-SHA256, ADH-CAMELLIA128-SHA
|
||||
|
||||
final Set<String> openSSLSecureCiphers = new HashSet<>();
|
||||
for (final String secure : SSLConfigConstants.getSecureSSLCiphers(Settings.EMPTY, false)) {
|
||||
if (OpenSsl.isCipherSuiteAvailable(secure)) {
|
||||
openSSLSecureCiphers.add(secure);
|
||||
}
|
||||
}
|
||||
|
||||
System.out.println("OpenSSL secure ciphers: " + openSSLSecureCiphers);
|
||||
Assert.assertTrue(openSSLSecureCiphers.size() > 0);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testHttpsEnforceFail() throws Exception {
|
||||
Assume.assumeTrue(OpenSsl.isAvailable());
|
||||
super.testHttpsEnforceFail();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void testCipherAndProtocols() throws Exception {
|
||||
Assume.assumeTrue(OpenSsl.isAvailable());
|
||||
super.testCipherAndProtocols();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void testHttpsAndNodeSSLFailedCipher() throws Exception {
|
||||
Assume.assumeTrue(OpenSsl.isAvailable());
|
||||
super.testHttpsAndNodeSSLFailedCipher();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testHttpsAndNodeSSLPem() throws Exception {
|
||||
Assume.assumeTrue(OpenSsl.isAvailable());
|
||||
super.testHttpsAndNodeSSLPem();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testHttpsAndNodeSSLPemEnc() throws Exception {
|
||||
Assume.assumeTrue(OpenSsl.isAvailable());
|
||||
super.testHttpsAndNodeSSLPemEnc();
|
||||
}
|
||||
}
|
@ -0,0 +1,814 @@
|
||||
/*
|
||||
* Copyright 2015-2018 _floragunn_ GmbH
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Portions Copyright 2019 Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License").
|
||||
* You may not use this file except in compliance with the License.
|
||||
* A copy of the License is located at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* or in the "license" file accompanying this file. This file is distributed
|
||||
* on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
|
||||
* express or implied. See the License for the specific language governing
|
||||
* permissions and limitations under the License.
|
||||
*/
|
||||
|
||||
package com.amazon.opendistroforelasticsearch.security.ssl;
|
||||
|
||||
import io.netty.util.internal.PlatformDependent;
|
||||
|
||||
import java.net.InetSocketAddress;
|
||||
import java.net.SocketException;
|
||||
import java.nio.file.Paths;
|
||||
import java.security.KeyStore;
|
||||
import java.security.Security;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.Random;
|
||||
|
||||
import javax.net.ssl.KeyManagerFactory;
|
||||
import javax.net.ssl.SSLContext;
|
||||
import javax.net.ssl.SSLEngine;
|
||||
import javax.net.ssl.SSLException;
|
||||
import javax.net.ssl.SSLHandshakeException;
|
||||
import javax.net.ssl.TrustManagerFactory;
|
||||
|
||||
import org.apache.http.NoHttpResponseException;
|
||||
import org.apache.lucene.util.Constants;
|
||||
import org.elasticsearch.ElasticsearchSecurityException;
|
||||
import org.elasticsearch.action.admin.cluster.health.ClusterHealthRequest;
|
||||
import org.elasticsearch.action.admin.cluster.health.ClusterHealthResponse;
|
||||
import org.elasticsearch.action.admin.cluster.node.info.NodesInfoRequest;
|
||||
import org.elasticsearch.action.index.IndexRequest;
|
||||
import org.elasticsearch.action.search.SearchRequest;
|
||||
import org.elasticsearch.action.support.WriteRequest.RefreshPolicy;
|
||||
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.common.unit.TimeValue;
|
||||
import org.elasticsearch.common.xcontent.XContentType;
|
||||
import org.elasticsearch.node.Node;
|
||||
import org.elasticsearch.node.PluginAwareNode;
|
||||
import org.elasticsearch.transport.Netty4Plugin;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Assume;
|
||||
import org.junit.Rule;
|
||||
import org.junit.Test;
|
||||
import org.junit.rules.ExpectedException;
|
||||
|
||||
import com.amazon.opendistroforelasticsearch.security.ssl.DefaultOpenDistroSecurityKeyStore;
|
||||
import com.amazon.opendistroforelasticsearch.security.ssl.ExternalOpenDistroSecurityKeyStore;
|
||||
import com.amazon.opendistroforelasticsearch.security.ssl.OpenDistroSecuritySSLPlugin;
|
||||
import com.amazon.opendistroforelasticsearch.security.ssl.util.ExceptionUtils;
|
||||
import com.amazon.opendistroforelasticsearch.security.ssl.util.SSLConfigConstants;
|
||||
|
||||
@SuppressWarnings({"resource", "unchecked"})
|
||||
public class SSLTest extends AbstractUnitTest {
|
||||
|
||||
@Rule
|
||||
public final ExpectedException thrown = ExpectedException.none();
|
||||
|
||||
protected boolean allowOpenSSL = false;
|
||||
|
||||
@Test
|
||||
public void testHttps() throws Exception {
|
||||
|
||||
enableHTTPClientSSL = true;
|
||||
trustHTTPServerCertificate = true;
|
||||
sendHTTPClientCertificate = true;
|
||||
keystore = "node-untspec5-keystore.p12";
|
||||
|
||||
final Settings settings = Settings.builder().put("opendistro_security.ssl.transport.enabled", false)
|
||||
.put("opendistro_security.ssl.http.enabled", true)
|
||||
.put(SSLConfigConstants.OPENDISTRO_SECURITY_SSL_HTTP_ENABLE_OPENSSL_IF_AVAILABLE, allowOpenSSL)
|
||||
.put(SSLConfigConstants.OPENDISTRO_SECURITY_SSL_TRANSPORT_ENABLE_OPENSSL_IF_AVAILABLE, allowOpenSSL)
|
||||
.put("opendistro_security.ssl.http.clientauth_mode", "REQUIRE")
|
||||
.putList(SSLConfigConstants.OPENDISTRO_SECURITY_SSL_HTTP_ENABLED_PROTOCOLS, "TLSv1.1","TLSv1.2")
|
||||
.putList(SSLConfigConstants.OPENDISTRO_SECURITY_SSL_HTTP_ENABLED_CIPHERS, "TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256")
|
||||
.putList(SSLConfigConstants.OPENDISTRO_SECURITY_SSL_TRANSPORT_ENABLED_PROTOCOLS, "TLSv1.1","TLSv1.2")
|
||||
.putList(SSLConfigConstants.OPENDISTRO_SECURITY_SSL_TRANSPORT_ENABLED_CIPHERS, "TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256")
|
||||
.put("opendistro_security.ssl.http.keystore_filepath", getAbsoluteFilePathFromClassPath("node-0-keystore.jks"))
|
||||
.put("opendistro_security.ssl.http.truststore_filepath", getAbsoluteFilePathFromClassPath("truststore.jks"))
|
||||
.build();
|
||||
|
||||
startES(settings);
|
||||
|
||||
System.out.println(executeSimpleRequest("_opendistro/_security/sslinfo?pretty&show_dn=true"));
|
||||
Assert.assertTrue(executeSimpleRequest("_opendistro/_security/sslinfo?pretty&show_dn=true").contains("EMAILADDRESS=unt@tst.com"));
|
||||
Assert.assertTrue(executeSimpleRequest("_opendistro/_security/sslinfo?pretty&show_dn=true").contains("local_certificates_list"));
|
||||
Assert.assertFalse(executeSimpleRequest("_opendistro/_security/sslinfo?pretty&show_dn=false").contains("local_certificates_list"));
|
||||
Assert.assertFalse(executeSimpleRequest("_opendistro/_security/sslinfo?pretty").contains("local_certificates_list"));
|
||||
Assert.assertTrue(executeSimpleRequest("_nodes/settings?pretty").contains(clustername));
|
||||
Assert.assertFalse(executeSimpleRequest("_nodes/settings?pretty").contains("\"opendistro_security\""));
|
||||
Assert.assertFalse(executeSimpleRequest("_nodes/settings?pretty").contains("keystore_filepath"));
|
||||
//Assert.assertTrue(executeSimpleRequest("_opendistro/_security/sslinfo?pretty").contains("CN=node-0.example.com,OU=SSL,O=Test,L=Test,C=DE"));
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCipherAndProtocols() throws Exception {
|
||||
|
||||
Security.setProperty("jdk.tls.disabledAlgorithms","");
|
||||
System.out.println("Disabled algos: "+Security.getProperty("jdk.tls.disabledAlgorithms"));
|
||||
System.out.println("allowOpenSSL: "+allowOpenSSL);
|
||||
|
||||
Settings settings = Settings.builder().put("opendistro_security.ssl.transport.enabled", false)
|
||||
.put(SSLConfigConstants.OPENDISTRO_SECURITY_SSL_HTTP_KEYSTORE_ALIAS, "node-0").put("opendistro_security.ssl.http.enabled", true)
|
||||
.put(SSLConfigConstants.OPENDISTRO_SECURITY_SSL_HTTP_ENABLE_OPENSSL_IF_AVAILABLE, allowOpenSSL)
|
||||
.put(SSLConfigConstants.OPENDISTRO_SECURITY_SSL_TRANSPORT_ENABLE_OPENSSL_IF_AVAILABLE, allowOpenSSL)
|
||||
.put("opendistro_security.ssl.http.clientauth_mode", "REQUIRE")
|
||||
.put("opendistro_security.ssl.http.keystore_filepath", getAbsoluteFilePathFromClassPath("node-0-keystore.jks"))
|
||||
.put("opendistro_security.ssl.http.truststore_filepath", getAbsoluteFilePathFromClassPath("truststore.jks"))
|
||||
//WEAK and insecure cipher, do NOT use this, its here for unittesting only!!!
|
||||
.put("opendistro_security.ssl.http.enabled_ciphers","SSL_RSA_EXPORT_WITH_RC4_40_MD5")
|
||||
//WEAK and insecure protocol, do NOT use this, its here for unittesting only!!!
|
||||
.put("opendistro_security.ssl.http.enabled_protocols","SSLv3")
|
||||
.put("client.type","node")
|
||||
.put("path.home",".")
|
||||
.build();
|
||||
|
||||
try {
|
||||
String[] enabledCiphers = new DefaultOpenDistroSecurityKeyStore(settings, Paths.get(".")).createHTTPSSLEngine().getEnabledCipherSuites();
|
||||
String[] enabledProtocols = new DefaultOpenDistroSecurityKeyStore(settings, Paths.get(".")).createHTTPSSLEngine().getEnabledProtocols();
|
||||
|
||||
if(allowOpenSSL) {
|
||||
Assert.assertEquals(2, enabledProtocols.length); //SSLv2Hello is always enabled when using openssl
|
||||
Assert.assertTrue("Check SSLv3", "SSLv3".equals(enabledProtocols[0]) || "SSLv3".equals(enabledProtocols[1]));
|
||||
Assert.assertEquals(1, enabledCiphers.length);
|
||||
Assert.assertEquals("TLS_RSA_EXPORT_WITH_RC4_40_MD5",enabledCiphers[0]);
|
||||
} else {
|
||||
Assert.assertEquals(1, enabledProtocols.length);
|
||||
Assert.assertEquals("SSLv3", enabledProtocols[0]);
|
||||
Assert.assertEquals(1, enabledCiphers.length);
|
||||
Assert.assertEquals("SSL_RSA_EXPORT_WITH_RC4_40_MD5",enabledCiphers[0]);
|
||||
}
|
||||
|
||||
settings = Settings.builder().put("opendistro_security.ssl.transport.enabled", true)
|
||||
.put(SSLConfigConstants.OPENDISTRO_SECURITY_SSL_HTTP_ENABLE_OPENSSL_IF_AVAILABLE, allowOpenSSL)
|
||||
.put(SSLConfigConstants.OPENDISTRO_SECURITY_SSL_TRANSPORT_ENABLE_OPENSSL_IF_AVAILABLE, allowOpenSSL)
|
||||
.put("opendistro_security.ssl.transport.keystore_filepath", getAbsoluteFilePathFromClassPath("node-0-keystore.jks"))
|
||||
.put("opendistro_security.ssl.transport.truststore_filepath", getAbsoluteFilePathFromClassPath("truststore.jks"))
|
||||
//WEAK and insecure cipher, do NOT use this, its here for unittesting only!!!
|
||||
.put("opendistro_security.ssl.transport.enabled_ciphers","SSL_RSA_EXPORT_WITH_RC4_40_MD5")
|
||||
//WEAK and insecure protocol, do NOT use this, its here for unittesting only!!!
|
||||
.put("opendistro_security.ssl.transport.enabled_protocols","SSLv3")
|
||||
.put("client.type","node")
|
||||
.put("path.home",".")
|
||||
.build();
|
||||
|
||||
enabledCiphers = new DefaultOpenDistroSecurityKeyStore(settings, Paths.get(".")).createServerTransportSSLEngine().getEnabledCipherSuites();
|
||||
enabledProtocols = new DefaultOpenDistroSecurityKeyStore(settings, Paths.get(".")).createServerTransportSSLEngine().getEnabledProtocols();
|
||||
|
||||
if(allowOpenSSL) {
|
||||
Assert.assertEquals(2, enabledProtocols.length); //SSLv2Hello is always enabled when using openssl
|
||||
Assert.assertTrue("Check SSLv3", "SSLv3".equals(enabledProtocols[0]) || "SSLv3".equals(enabledProtocols[1]));
|
||||
Assert.assertEquals(1, enabledCiphers.length);
|
||||
Assert.assertEquals("TLS_RSA_EXPORT_WITH_RC4_40_MD5",enabledCiphers[0]);
|
||||
} else {
|
||||
Assert.assertEquals(1, enabledProtocols.length);
|
||||
Assert.assertEquals("SSLv3", enabledProtocols[0]);
|
||||
Assert.assertEquals(1, enabledCiphers.length);
|
||||
Assert.assertEquals("SSL_RSA_EXPORT_WITH_RC4_40_MD5",enabledCiphers[0]);
|
||||
}
|
||||
enabledCiphers = new DefaultOpenDistroSecurityKeyStore(settings, Paths.get(".")).createClientTransportSSLEngine(null, -1).getEnabledCipherSuites();
|
||||
enabledProtocols = new DefaultOpenDistroSecurityKeyStore(settings, Paths.get(".")).createClientTransportSSLEngine(null, -1).getEnabledProtocols();
|
||||
|
||||
if(allowOpenSSL) {
|
||||
Assert.assertEquals(2, enabledProtocols.length); //SSLv2Hello is always enabled when using openssl
|
||||
Assert.assertTrue("Check SSLv3","SSLv3".equals(enabledProtocols[0]) || "SSLv3".equals(enabledProtocols[1]));
|
||||
Assert.assertEquals(1, enabledCiphers.length);
|
||||
Assert.assertEquals("TLS_RSA_EXPORT_WITH_RC4_40_MD5",enabledCiphers[0]);
|
||||
} else {
|
||||
Assert.assertEquals(1, enabledProtocols.length);
|
||||
Assert.assertEquals("SSLv3", enabledProtocols[0]);
|
||||
Assert.assertEquals(1, enabledCiphers.length);
|
||||
Assert.assertEquals("SSL_RSA_EXPORT_WITH_RC4_40_MD5",enabledCiphers[0]);
|
||||
}
|
||||
} catch (ElasticsearchSecurityException e) {
|
||||
System.out.println("EXPECTED "+e.getClass().getSimpleName()+" for "+System.getProperty("java.specification.version")+": "+e.toString());
|
||||
e.printStackTrace();
|
||||
Assert.assertTrue("Check if error contains 'no valid cipher suites' -> "+e.toString(),e.toString().contains("no valid cipher suites")
|
||||
|| e.toString().contains("failed to set cipher suite")
|
||||
|| e.toString().contains("Unable to configure permitted SSL ciphers")
|
||||
|| e.toString().contains("OPENSSL_internal:NO_CIPHER_MATCH")
|
||||
);
|
||||
Assert.assertTrue("Check if >= Java 8 and no openssl",allowOpenSSL?true:Constants.JRE_IS_MINIMUM_JAVA8 );
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testHttpsOptionalAuth() throws Exception {
|
||||
|
||||
enableHTTPClientSSL = true;
|
||||
trustHTTPServerCertificate = true;
|
||||
sendHTTPClientCertificate = true;
|
||||
|
||||
final Settings settings = Settings.builder().put("opendistro_security.ssl.transport.enabled", false)
|
||||
.put(SSLConfigConstants.OPENDISTRO_SECURITY_SSL_HTTP_KEYSTORE_ALIAS, "node-0").put("opendistro_security.ssl.http.enabled", true)
|
||||
.put(SSLConfigConstants.OPENDISTRO_SECURITY_SSL_HTTP_ENABLE_OPENSSL_IF_AVAILABLE, allowOpenSSL)
|
||||
.put(SSLConfigConstants.OPENDISTRO_SECURITY_SSL_TRANSPORT_ENABLE_OPENSSL_IF_AVAILABLE, allowOpenSSL)
|
||||
.put("opendistro_security.ssl.http.keystore_filepath", getAbsoluteFilePathFromClassPath("node-0-keystore.jks"))
|
||||
.put("opendistro_security.ssl.http.truststore_filepath", getAbsoluteFilePathFromClassPath("truststore.jks")).build();
|
||||
|
||||
startES(settings);
|
||||
|
||||
System.out.println(executeSimpleRequest("_opendistro/_security/sslinfo?pretty"));
|
||||
Assert.assertTrue(executeSimpleRequest("_opendistro/_security/sslinfo?pretty").contains("TLS"));
|
||||
Assert.assertTrue(executeSimpleRequest("_nodes/settings?pretty").contains(clustername));
|
||||
Assert.assertFalse(executeSimpleRequest("_nodes/settings?pretty").contains("\"opendistro_security\""));
|
||||
Assert.assertTrue(executeSimpleRequest("_opendistro/_security/sslinfo?pretty").contains("CN=node-0.example.com,OU=SSL,O=Test,L=Test,C=DE"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testHttpsAndNodeSSL() throws Exception {
|
||||
|
||||
enableHTTPClientSSL = true;
|
||||
trustHTTPServerCertificate = true;
|
||||
sendHTTPClientCertificate = true;
|
||||
|
||||
final Settings settings = Settings.builder().put("opendistro_security.ssl.transport.enabled", true)
|
||||
.put(SSLConfigConstants.OPENDISTRO_SECURITY_SSL_HTTP_ENABLE_OPENSSL_IF_AVAILABLE, allowOpenSSL)
|
||||
.put(SSLConfigConstants.OPENDISTRO_SECURITY_SSL_TRANSPORT_ENABLE_OPENSSL_IF_AVAILABLE, allowOpenSSL)
|
||||
.put(SSLConfigConstants.OPENDISTRO_SECURITY_SSL_TRANSPORT_KEYSTORE_ALIAS, "node-0")
|
||||
.put(SSLConfigConstants.OPENDISTRO_SECURITY_SSL_HTTP_KEYSTORE_ALIAS, "node-0")
|
||||
.put("opendistro_security.ssl.transport.keystore_filepath", getAbsoluteFilePathFromClassPath("node-0-keystore.jks"))
|
||||
.put("opendistro_security.ssl.transport.truststore_filepath", getAbsoluteFilePathFromClassPath("truststore.jks"))
|
||||
.put("opendistro_security.ssl.transport.enforce_hostname_verification", false)
|
||||
.put("opendistro_security.ssl.transport.resolve_hostname", false)
|
||||
|
||||
.put("opendistro_security.ssl.http.enabled", true).put("opendistro_security.ssl.http.clientauth_mode", "REQUIRE")
|
||||
.put("opendistro_security.ssl.http.keystore_filepath", getAbsoluteFilePathFromClassPath("node-0-keystore.jks"))
|
||||
.put("opendistro_security.ssl.http.truststore_filepath", getAbsoluteFilePathFromClassPath("truststore.jks"))
|
||||
|
||||
.build();
|
||||
|
||||
startES(settings);
|
||||
System.out.println(executeSimpleRequest("_opendistro/_security/sslinfo?pretty"));
|
||||
Assert.assertTrue(executeSimpleRequest("_opendistro/_security/sslinfo?pretty").contains("TLS"));
|
||||
Assert.assertTrue(executeSimpleRequest("_opendistro/_security/sslinfo?pretty").length() > 0);
|
||||
Assert.assertTrue(executeSimpleRequest("_nodes/settings?pretty").contains(clustername));
|
||||
Assert.assertTrue(executeSimpleRequest("_opendistro/_security/sslinfo?pretty").contains("CN=node-0.example.com,OU=SSL,O=Test,L=Test,C=DE"));
|
||||
Assert.assertFalse(executeSimpleRequest("_nodes/stats?pretty").contains("\"tx_size_in_bytes\" : 0"));
|
||||
Assert.assertFalse(executeSimpleRequest("_nodes/stats?pretty").contains("\"rx_count\" : 0"));
|
||||
Assert.assertFalse(executeSimpleRequest("_nodes/stats?pretty").contains("\"rx_size_in_bytes\" : 0"));
|
||||
Assert.assertFalse(executeSimpleRequest("_nodes/stats?pretty").contains("\"tx_count\" : 0"));
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testHttpsAndNodeSSLPem() throws Exception {
|
||||
|
||||
enableHTTPClientSSL = true;
|
||||
trustHTTPServerCertificate = true;
|
||||
sendHTTPClientCertificate = true;
|
||||
|
||||
final Settings settings = Settings.builder().put("opendistro_security.ssl.transport.enabled", true)
|
||||
.put(SSLConfigConstants.OPENDISTRO_SECURITY_SSL_HTTP_ENABLE_OPENSSL_IF_AVAILABLE, allowOpenSSL)
|
||||
.put(SSLConfigConstants.OPENDISTRO_SECURITY_SSL_TRANSPORT_ENABLE_OPENSSL_IF_AVAILABLE, allowOpenSSL)
|
||||
.put(SSLConfigConstants.OPENDISTRO_SECURITY_SSL_TRANSPORT_PEMCERT_FILEPATH, getAbsoluteFilePathFromClassPath("node-0.crt.pem"))
|
||||
.put(SSLConfigConstants.OPENDISTRO_SECURITY_SSL_TRANSPORT_PEMKEY_FILEPATH, getAbsoluteFilePathFromClassPath("node-0.key.pem"))
|
||||
//.put(SSLConfigConstants.OPENDISTRO_SECURITY_SSL_TRANSPORT_PEMKEY_PASSWORD, "changeit")
|
||||
.put(SSLConfigConstants.OPENDISTRO_SECURITY_SSL_TRANSPORT_PEMTRUSTEDCAS_FILEPATH, getAbsoluteFilePathFromClassPath("root-ca.pem"))
|
||||
.put("opendistro_security.ssl.transport.enforce_hostname_verification", false)
|
||||
.put("opendistro_security.ssl.transport.resolve_hostname", false)
|
||||
|
||||
.put("opendistro_security.ssl.http.enabled", true)
|
||||
.put("opendistro_security.ssl.http.clientauth_mode", "REQUIRE")
|
||||
.put(SSLConfigConstants.OPENDISTRO_SECURITY_SSL_HTTP_PEMCERT_FILEPATH, getAbsoluteFilePathFromClassPath("node-0.crt.pem"))
|
||||
.put(SSLConfigConstants.OPENDISTRO_SECURITY_SSL_HTTP_PEMKEY_FILEPATH, getAbsoluteFilePathFromClassPath("node-0.key.pem"))
|
||||
//.put(SSLConfigConstants.OPENDISTRO_SECURITY_SSL_HTTP_PEMKEY_PASSWORD, "changeit")
|
||||
.put(SSLConfigConstants.OPENDISTRO_SECURITY_SSL_HTTP_PEMTRUSTEDCAS_FILEPATH, getAbsoluteFilePathFromClassPath("root-ca.pem"))
|
||||
.build();
|
||||
|
||||
startES(settings);
|
||||
System.out.println(executeSimpleRequest("_opendistro/_security/sslinfo?pretty"));
|
||||
Assert.assertTrue(executeSimpleRequest("_opendistro/_security/sslinfo?pretty").contains("TLS"));
|
||||
Assert.assertTrue(executeSimpleRequest("_opendistro/_security/sslinfo?pretty").length() > 0);
|
||||
Assert.assertTrue(executeSimpleRequest("_nodes/settings?pretty").contains(clustername));
|
||||
//Assert.assertTrue(!executeSimpleRequest("_opendistro/_security/sslinfo?pretty").contains("null"));
|
||||
Assert.assertTrue(executeSimpleRequest("_opendistro/_security/sslinfo?pretty").contains("CN=node-0.example.com,OU=SSL,O=Test,L=Test,C=DE"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testHttpsAndNodeSSLPemEnc() throws Exception {
|
||||
|
||||
enableHTTPClientSSL = true;
|
||||
trustHTTPServerCertificate = true;
|
||||
sendHTTPClientCertificate = true;
|
||||
|
||||
final Settings settings = Settings.builder().put("opendistro_security.ssl.transport.enabled", true)
|
||||
.put(SSLConfigConstants.OPENDISTRO_SECURITY_SSL_HTTP_ENABLE_OPENSSL_IF_AVAILABLE, allowOpenSSL)
|
||||
.put(SSLConfigConstants.OPENDISTRO_SECURITY_SSL_TRANSPORT_ENABLE_OPENSSL_IF_AVAILABLE, allowOpenSSL)
|
||||
.put(SSLConfigConstants.OPENDISTRO_SECURITY_SSL_TRANSPORT_PEMCERT_FILEPATH, getAbsoluteFilePathFromClassPath("pem/node-4.crt.pem"))
|
||||
.put(SSLConfigConstants.OPENDISTRO_SECURITY_SSL_TRANSPORT_PEMKEY_FILEPATH, getAbsoluteFilePathFromClassPath("pem/node-4.key"))
|
||||
.put(SSLConfigConstants.OPENDISTRO_SECURITY_SSL_TRANSPORT_PEMKEY_PASSWORD, "changeit")
|
||||
.put(SSLConfigConstants.OPENDISTRO_SECURITY_SSL_TRANSPORT_PEMTRUSTEDCAS_FILEPATH, getAbsoluteFilePathFromClassPath("root-ca.pem"))
|
||||
.put("opendistro_security.ssl.transport.enforce_hostname_verification", false)
|
||||
.put("opendistro_security.ssl.transport.resolve_hostname", false)
|
||||
|
||||
.put("opendistro_security.ssl.http.enabled", true)
|
||||
.put("opendistro_security.ssl.http.clientauth_mode", "REQUIRE")
|
||||
.put(SSLConfigConstants.OPENDISTRO_SECURITY_SSL_HTTP_PEMCERT_FILEPATH, getAbsoluteFilePathFromClassPath("pem/node-4.crt.pem"))
|
||||
.put(SSLConfigConstants.OPENDISTRO_SECURITY_SSL_HTTP_PEMKEY_FILEPATH, getAbsoluteFilePathFromClassPath("pem/node-4.key"))
|
||||
.put(SSLConfigConstants.OPENDISTRO_SECURITY_SSL_HTTP_PEMKEY_PASSWORD, "changeit")
|
||||
.put(SSLConfigConstants.OPENDISTRO_SECURITY_SSL_HTTP_PEMTRUSTEDCAS_FILEPATH, getAbsoluteFilePathFromClassPath("root-ca.pem"))
|
||||
.build();
|
||||
|
||||
startES(settings);
|
||||
System.out.println(executeSimpleRequest("_opendistro/_security/sslinfo?pretty"));
|
||||
Assert.assertTrue(executeSimpleRequest("_opendistro/_security/sslinfo?pretty").contains("TLS"));
|
||||
Assert.assertTrue(executeSimpleRequest("_opendistro/_security/sslinfo?pretty").length() > 0);
|
||||
Assert.assertTrue(executeSimpleRequest("_nodes/settings?pretty").contains(clustername));
|
||||
//Assert.assertTrue(!executeSimpleRequest("_opendistro/_security/sslinfo?pretty").contains("null"));
|
||||
Assert.assertTrue(executeSimpleRequest("_opendistro/_security/sslinfo?pretty").contains("CN=node-0.example.com,OU=SSL,O=Test,L=Test,C=DE"));
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testHttpsAndNodeSSLFailedCipher() throws Exception {
|
||||
|
||||
enableHTTPClientSSL = true;
|
||||
trustHTTPServerCertificate = true;
|
||||
sendHTTPClientCertificate = true;
|
||||
|
||||
final Settings settings = Settings.builder().put("opendistro_security.ssl.transport.enabled", true)
|
||||
.put(SSLConfigConstants.OPENDISTRO_SECURITY_SSL_HTTP_ENABLE_OPENSSL_IF_AVAILABLE, allowOpenSSL)
|
||||
.put(SSLConfigConstants.OPENDISTRO_SECURITY_SSL_TRANSPORT_ENABLE_OPENSSL_IF_AVAILABLE, allowOpenSSL)
|
||||
.put(SSLConfigConstants.OPENDISTRO_SECURITY_SSL_TRANSPORT_KEYSTORE_ALIAS, "node-0")
|
||||
.put(SSLConfigConstants.OPENDISTRO_SECURITY_SSL_HTTP_KEYSTORE_ALIAS, "node-0")
|
||||
.put("opendistro_security.ssl.transport.keystore_filepath", getAbsoluteFilePathFromClassPath("node-0-keystore.jks"))
|
||||
.put("opendistro_security.ssl.transport.truststore_filepath", getAbsoluteFilePathFromClassPath("truststore.jks"))
|
||||
.put("opendistro_security.ssl.transport.enforce_hostname_verification", false)
|
||||
.put("opendistro_security.ssl.transport.resolve_hostname", false)
|
||||
|
||||
.put("opendistro_security.ssl.http.enabled", true).put("opendistro_security.ssl.http.clientauth_mode", "REQUIRE")
|
||||
.put("opendistro_security.ssl.http.keystore_filepath", getAbsoluteFilePathFromClassPath("node-0-keystore.jks"))
|
||||
.put("opendistro_security.ssl.http.truststore_filepath", getAbsoluteFilePathFromClassPath("truststore.jks"))
|
||||
|
||||
.put("opendistro_security.ssl.transport.enabled_ciphers","INVALID_CIPHER")
|
||||
|
||||
.build();
|
||||
|
||||
try {
|
||||
startES(settings);
|
||||
Assert.fail();
|
||||
} catch (Exception e1) {
|
||||
Throwable e = ExceptionUtils.getRootCause(e1);
|
||||
if(allowOpenSSL) {
|
||||
Assert.assertTrue(e.toString(), e.toString().contains("no cipher match"));
|
||||
} else {
|
||||
Assert.assertTrue(e.toString(), e.toString().contains("no valid cipher"));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testHttpPlainFail() throws Exception {
|
||||
thrown.expect(NoHttpResponseException.class);
|
||||
|
||||
enableHTTPClientSSL = false;
|
||||
trustHTTPServerCertificate = true;
|
||||
sendHTTPClientCertificate = false;
|
||||
|
||||
final Settings settings = Settings.builder().put("opendistro_security.ssl.transport.enabled", false)
|
||||
.put(SSLConfigConstants.OPENDISTRO_SECURITY_SSL_HTTP_ENABLE_OPENSSL_IF_AVAILABLE, allowOpenSSL)
|
||||
.put(SSLConfigConstants.OPENDISTRO_SECURITY_SSL_TRANSPORT_ENABLE_OPENSSL_IF_AVAILABLE, allowOpenSSL)
|
||||
.put(SSLConfigConstants.OPENDISTRO_SECURITY_SSL_HTTP_KEYSTORE_ALIAS, "node-0").put("opendistro_security.ssl.http.enabled", true)
|
||||
.put("opendistro_security.ssl.http.clientauth_mode", "OPTIONAL")
|
||||
.put("opendistro_security.ssl.http.keystore_filepath", getAbsoluteFilePathFromClassPath("node-0-keystore.jks"))
|
||||
.put("opendistro_security.ssl.http.truststore_filepath", getAbsoluteFilePathFromClassPath("truststore.jks")).build();
|
||||
|
||||
startES(settings);
|
||||
Assert.assertTrue(executeSimpleRequest("_opendistro/_security/sslinfo?pretty").length() > 0);
|
||||
Assert.assertTrue(executeSimpleRequest("_nodes/settings?pretty").contains(clustername));
|
||||
Assert.assertTrue(executeSimpleRequest("_opendistro/_security/sslinfo?pretty").contains("CN=node-0.example.com,OU=SSL,O=Test,L=Test,C=DE"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testHttpsNoEnforce() throws Exception {
|
||||
|
||||
enableHTTPClientSSL = true;
|
||||
trustHTTPServerCertificate = true;
|
||||
sendHTTPClientCertificate = false;
|
||||
|
||||
final Settings settings = Settings.builder().put("opendistro_security.ssl.transport.enabled", false)
|
||||
.put(SSLConfigConstants.OPENDISTRO_SECURITY_SSL_HTTP_ENABLE_OPENSSL_IF_AVAILABLE, allowOpenSSL)
|
||||
.put(SSLConfigConstants.OPENDISTRO_SECURITY_SSL_TRANSPORT_ENABLE_OPENSSL_IF_AVAILABLE, allowOpenSSL)
|
||||
.put(SSLConfigConstants.OPENDISTRO_SECURITY_SSL_HTTP_KEYSTORE_ALIAS, "node-0").put("opendistro_security.ssl.http.enabled", true)
|
||||
.put("opendistro_security.ssl.http.clientauth_mode", "NONE")
|
||||
.put("opendistro_security.ssl.http.keystore_filepath", getAbsoluteFilePathFromClassPath("node-0-keystore.jks"))
|
||||
.put("opendistro_security.ssl.http.truststore_filepath", getAbsoluteFilePathFromClassPath("truststore.jks")).build();
|
||||
|
||||
startES(settings);
|
||||
Assert.assertTrue(executeSimpleRequest("_opendistro/_security/sslinfo?pretty").length() > 0);
|
||||
Assert.assertTrue(executeSimpleRequest("_nodes/settings?pretty").contains(clustername));
|
||||
Assert.assertFalse(executeSimpleRequest("_opendistro/_security/sslinfo?pretty").contains("CN=node-0.example.com,OU=SSL,O=Test,L=Test,C=DE"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testHttpsEnforceFail() throws Exception {
|
||||
|
||||
enableHTTPClientSSL = true;
|
||||
trustHTTPServerCertificate = true;
|
||||
sendHTTPClientCertificate = false;
|
||||
|
||||
final Settings settings = Settings.builder().put("opendistro_security.ssl.transport.enabled", false)
|
||||
.put(SSLConfigConstants.OPENDISTRO_SECURITY_SSL_HTTP_ENABLE_OPENSSL_IF_AVAILABLE, allowOpenSSL)
|
||||
.put(SSLConfigConstants.OPENDISTRO_SECURITY_SSL_TRANSPORT_ENABLE_OPENSSL_IF_AVAILABLE, allowOpenSSL)
|
||||
.put(SSLConfigConstants.OPENDISTRO_SECURITY_SSL_HTTP_KEYSTORE_ALIAS, "node-0").put("opendistro_security.ssl.http.enabled", true)
|
||||
.put("opendistro_security.ssl.http.clientauth_mode", "REQUIRE")
|
||||
.put("opendistro_security.ssl.http.keystore_filepath", getAbsoluteFilePathFromClassPath("node-0-keystore.jks"))
|
||||
.put("opendistro_security.ssl.http.truststore_filepath", getAbsoluteFilePathFromClassPath("truststore.jks")).build();
|
||||
|
||||
startES(settings);
|
||||
try {
|
||||
executeSimpleRequest("");
|
||||
Assert.fail();
|
||||
} catch (SocketException | SSLException e) {
|
||||
//expected
|
||||
System.out.println("Expected SSLHandshakeException "+e.toString());
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
Assert.fail("Unexpected exception "+e.toString());
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testHttpsV3Fail() throws Exception {
|
||||
thrown.expect(SSLHandshakeException.class);
|
||||
|
||||
enableHTTPClientSSL = true;
|
||||
trustHTTPServerCertificate = true;
|
||||
sendHTTPClientCertificate = false;
|
||||
enableHTTPClientSSLv3Only = true;
|
||||
|
||||
final Settings settings = Settings.builder().put("opendistro_security.ssl.transport.enabled", false)
|
||||
.put(SSLConfigConstants.OPENDISTRO_SECURITY_SSL_HTTP_ENABLE_OPENSSL_IF_AVAILABLE, allowOpenSSL)
|
||||
.put(SSLConfigConstants.OPENDISTRO_SECURITY_SSL_TRANSPORT_ENABLE_OPENSSL_IF_AVAILABLE, allowOpenSSL)
|
||||
.put(SSLConfigConstants.OPENDISTRO_SECURITY_SSL_HTTP_KEYSTORE_ALIAS, "node-0").put("opendistro_security.ssl.http.enabled", true)
|
||||
.put("opendistro_security.ssl.http.clientauth_mode", "NONE")
|
||||
.put("opendistro_security.ssl.http.keystore_filepath", getAbsoluteFilePathFromClassPath("node-0-keystore.jks"))
|
||||
.put("opendistro_security.ssl.http.truststore_filepath", getAbsoluteFilePathFromClassPath("truststore.jks")).build();
|
||||
|
||||
startES(settings);
|
||||
Assert.assertTrue(executeSimpleRequest("_opendistro/_security/sslinfo?pretty").length() > 0);
|
||||
Assert.assertTrue(executeSimpleRequest("_nodes/settings?pretty").contains(clustername));
|
||||
}
|
||||
|
||||
// transport
|
||||
@Test
|
||||
public void testTransportClientSSL() throws Exception {
|
||||
|
||||
final Settings settings = Settings.builder().put("opendistro_security.ssl.transport.enabled", true)
|
||||
.put(SSLConfigConstants.OPENDISTRO_SECURITY_SSL_HTTP_ENABLE_OPENSSL_IF_AVAILABLE, allowOpenSSL)
|
||||
.put(SSLConfigConstants.OPENDISTRO_SECURITY_SSL_TRANSPORT_ENABLE_OPENSSL_IF_AVAILABLE, allowOpenSSL)
|
||||
.put(SSLConfigConstants.OPENDISTRO_SECURITY_SSL_TRANSPORT_KEYSTORE_ALIAS, "node-0")
|
||||
.put("opendistro_security.ssl.transport.keystore_filepath", getAbsoluteFilePathFromClassPath("node-0-keystore.jks"))
|
||||
.put("opendistro_security.ssl.transport.truststore_filepath", getAbsoluteFilePathFromClassPath("truststore.jks"))
|
||||
.put("opendistro_security.ssl.transport.enforce_hostname_verification", false)
|
||||
.put("opendistro_security.ssl.transport.resolve_hostname", false).build();
|
||||
|
||||
startES(settings);
|
||||
|
||||
log.debug("Elasticsearch started");
|
||||
|
||||
final Settings tcSettings = Settings.builder().put("cluster.name", clustername).put(settings).build();
|
||||
|
||||
try (TransportClient tc = new TransportClientImpl(tcSettings, asCollection(OpenDistroSecuritySSLPlugin.class))) {
|
||||
|
||||
log.debug("TransportClient built, connect now to {}:{}", nodeHost, nodePort);
|
||||
|
||||
tc.addTransportAddress(new TransportAddress(new InetSocketAddress(nodeHost, nodePort)));
|
||||
Assert.assertEquals(3, tc.admin().cluster().nodesInfo(new NodesInfoRequest()).actionGet().getNodes().size());
|
||||
log.debug("TransportClient connected");
|
||||
Assert.assertEquals("test", tc.index(new IndexRequest("test","test").setRefreshPolicy(RefreshPolicy.IMMEDIATE).source("{\"a\":5}", XContentType.JSON)).actionGet().getIndex());
|
||||
log.debug("Index created");
|
||||
Assert.assertEquals(1L, tc.search(new SearchRequest("test")).actionGet().getHits().getTotalHits());
|
||||
log.debug("Search done");
|
||||
Assert.assertEquals(3, tc.admin().cluster().health(new ClusterHealthRequest("test")).actionGet().getNumberOfNodes());
|
||||
log.debug("ClusterHealth done");
|
||||
Assert.assertEquals(3, tc.admin().cluster().nodesInfo(new NodesInfoRequest()).actionGet().getNodes().size());
|
||||
log.debug("NodesInfoRequest asserted");
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testTransportClientSSLExternalContext() throws Exception {
|
||||
|
||||
final Settings settings = Settings.builder().put("opendistro_security.ssl.transport.enabled", true)
|
||||
.put(SSLConfigConstants.OPENDISTRO_SECURITY_SSL_HTTP_ENABLE_OPENSSL_IF_AVAILABLE, allowOpenSSL)
|
||||
.put(SSLConfigConstants.OPENDISTRO_SECURITY_SSL_TRANSPORT_ENABLE_OPENSSL_IF_AVAILABLE, allowOpenSSL)
|
||||
.put(SSLConfigConstants.OPENDISTRO_SECURITY_SSL_TRANSPORT_KEYSTORE_ALIAS, "node-0")
|
||||
.put("opendistro_security.ssl.transport.keystore_filepath", getAbsoluteFilePathFromClassPath("node-0-keystore.jks"))
|
||||
.put("opendistro_security.ssl.transport.truststore_filepath", getAbsoluteFilePathFromClassPath("truststore.jks"))
|
||||
.put("opendistro_security.ssl.transport.enforce_hostname_verification", false)
|
||||
.put("opendistro_security.ssl.transport.resolve_hostname", false).build();
|
||||
|
||||
startES(settings);
|
||||
|
||||
log.debug("Elasticsearch started");
|
||||
|
||||
final Settings tcSettings = Settings.builder()
|
||||
.put("cluster.name", clustername)
|
||||
.put("path.home", ".")
|
||||
.put("opendistro_security.ssl.client.external_context_id", "abcx")
|
||||
.build();
|
||||
|
||||
final TrustManagerFactory tmf = TrustManagerFactory.getInstance(TrustManagerFactory
|
||||
.getDefaultAlgorithm());
|
||||
final KeyStore trustStore = KeyStore.getInstance("JKS");
|
||||
trustStore.load(this.getClass().getResourceAsStream("/truststore.jks"), "changeit".toCharArray());
|
||||
tmf.init(trustStore);
|
||||
|
||||
final KeyManagerFactory kmf = KeyManagerFactory.getInstance(KeyManagerFactory
|
||||
.getDefaultAlgorithm());
|
||||
final KeyStore keyStore = KeyStore.getInstance("JKS");
|
||||
keyStore.load(this.getClass().getResourceAsStream("/node-0-keystore.jks"), "changeit".toCharArray());
|
||||
kmf.init(keyStore, "changeit".toCharArray());
|
||||
|
||||
|
||||
SSLContext sslContext = SSLContext.getInstance("TLSv1.2");
|
||||
sslContext.init(kmf.getKeyManagers(), tmf.getTrustManagers(), null);
|
||||
ExternalOpenDistroSecurityKeyStore.registerExternalSslContext("abcx", sslContext);
|
||||
|
||||
try (TransportClient tc = new TransportClientImpl(tcSettings, asCollection(OpenDistroSecuritySSLPlugin.class))) {
|
||||
|
||||
log.debug("TransportClient built, connect now to {}:{}", nodeHost, nodePort);
|
||||
|
||||
tc.addTransportAddress(new TransportAddress(new InetSocketAddress(nodeHost, nodePort)));
|
||||
|
||||
log.debug("TransportClient connected");
|
||||
|
||||
Assert.assertEquals("test", tc.index(new IndexRequest("test","test").setRefreshPolicy(RefreshPolicy.IMMEDIATE).source("{\"a\":5}", XContentType.JSON)).actionGet().getIndex());
|
||||
|
||||
log.debug("Index created");
|
||||
|
||||
Assert.assertEquals(1L, tc.search(new SearchRequest("test")).actionGet().getHits().getTotalHits());
|
||||
|
||||
log.debug("Search done");
|
||||
|
||||
Assert.assertEquals(3, tc.admin().cluster().health(new ClusterHealthRequest("test")).actionGet().getNumberOfNodes());
|
||||
|
||||
log.debug("ClusterHealth done");
|
||||
|
||||
//Assert.assertEquals(3, tc.admin().cluster().nodesInfo(new NodesInfoRequest()).actionGet().getNodes().length);
|
||||
|
||||
//log.debug("NodesInfoRequest asserted");
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testNodeClientSSL() throws Exception {
|
||||
|
||||
final Settings settings = Settings.builder().put("opendistro_security.ssl.transport.enabled", true)
|
||||
.put(SSLConfigConstants.OPENDISTRO_SECURITY_SSL_HTTP_ENABLE_OPENSSL_IF_AVAILABLE, allowOpenSSL)
|
||||
.put(SSLConfigConstants.OPENDISTRO_SECURITY_SSL_TRANSPORT_ENABLE_OPENSSL_IF_AVAILABLE, allowOpenSSL)
|
||||
.put(SSLConfigConstants.OPENDISTRO_SECURITY_SSL_TRANSPORT_KEYSTORE_ALIAS, "node-0")
|
||||
.put("opendistro_security.ssl.transport.keystore_filepath", getAbsoluteFilePathFromClassPath("node-0-keystore.jks"))
|
||||
.put("opendistro_security.ssl.transport.truststore_filepath", getAbsoluteFilePathFromClassPath("truststore.jks"))
|
||||
.put("opendistro_security.ssl.transport.enforce_hostname_verification", false)
|
||||
.put("opendistro_security.ssl.transport.resolve_hostname", false)
|
||||
.build();
|
||||
|
||||
startES(settings);
|
||||
|
||||
final Settings tcSettings = Settings.builder().put("cluster.name", clustername).put("path.home", ".")
|
||||
.put("node.name", "client_node_" + new Random().nextInt())
|
||||
.put(settings)// -----
|
||||
.build();
|
||||
|
||||
try (Node node = new PluginAwareNode(tcSettings, Netty4Plugin.class, OpenDistroSecuritySSLPlugin.class).start()) {
|
||||
ClusterHealthResponse res = node.client().admin().cluster().health(new ClusterHealthRequest().waitForNodes("4").timeout(TimeValue.timeValueSeconds(5))).actionGet();
|
||||
Assert.assertFalse(res.isTimedOut());
|
||||
Assert.assertEquals(4, res.getNumberOfNodes());
|
||||
Assert.assertEquals(4, node.client().admin().cluster().nodesInfo(new NodesInfoRequest()).actionGet().getNodes().size());
|
||||
}
|
||||
|
||||
Assert.assertFalse(executeSimpleRequest("_nodes/stats?pretty").contains("\"tx_size_in_bytes\" : 0"));
|
||||
Assert.assertFalse(executeSimpleRequest("_nodes/stats?pretty").contains("\"rx_count\" : 0"));
|
||||
Assert.assertFalse(executeSimpleRequest("_nodes/stats?pretty").contains("\"rx_size_in_bytes\" : 0"));
|
||||
Assert.assertFalse(executeSimpleRequest("_nodes/stats?pretty").contains("\"tx_count\" : 0"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testTransportClientSSLFail() throws Exception {
|
||||
thrown.expect(NoNodeAvailableException.class);
|
||||
|
||||
final Settings settings = Settings.builder().put("opendistro_security.ssl.transport.enabled", true)
|
||||
.put(SSLConfigConstants.OPENDISTRO_SECURITY_SSL_HTTP_ENABLE_OPENSSL_IF_AVAILABLE, allowOpenSSL)
|
||||
.put(SSLConfigConstants.OPENDISTRO_SECURITY_SSL_TRANSPORT_ENABLE_OPENSSL_IF_AVAILABLE, allowOpenSSL)
|
||||
.put(SSLConfigConstants.OPENDISTRO_SECURITY_SSL_TRANSPORT_KEYSTORE_ALIAS, "node-0")
|
||||
.put("opendistro_security.ssl.transport.keystore_filepath", getAbsoluteFilePathFromClassPath("node-0-keystore.jks"))
|
||||
.put("opendistro_security.ssl.transport.truststore_filepath", getAbsoluteFilePathFromClassPath("truststore.jks"))
|
||||
.put("opendistro_security.ssl.transport.enforce_hostname_verification", false)
|
||||
.put("opendistro_security.ssl.transport.resolve_hostname", false).build();
|
||||
|
||||
startES(settings);
|
||||
|
||||
final Settings tcSettings = Settings.builder().put("cluster.name", clustername)
|
||||
.put("path.home", getAbsoluteFilePathFromClassPath("node-0-keystore.jks").getParent())
|
||||
.put("opendistro_security.ssl.transport.keystore_filepath", getAbsoluteFilePathFromClassPath("node-0-keystore.jks"))
|
||||
.put("opendistro_security.ssl.transport.truststore_filepath", getAbsoluteFilePathFromClassPath("truststore_fail.jks"))
|
||||
.put("opendistro_security.ssl.transport.enforce_hostname_verification", false)
|
||||
.put("opendistro_security.ssl.transport.resolve_hostname", false).build();
|
||||
|
||||
try (TransportClient tc = new TransportClientImpl(tcSettings, asCollection(OpenDistroSecuritySSLPlugin.class))) {
|
||||
tc.addTransportAddress(new TransportAddress(new InetSocketAddress(nodeHost, nodePort)));
|
||||
Assert.assertEquals(3, tc.admin().cluster().nodesInfo(new NodesInfoRequest()).actionGet().getNodes().size());
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testAvailCiphers() throws Exception {
|
||||
final SSLContext serverContext = SSLContext.getInstance("TLS");
|
||||
serverContext.init(null, null, null);
|
||||
final SSLEngine engine = serverContext.createSSLEngine();
|
||||
final List<String> jdkSupportedCiphers = new ArrayList<>(Arrays.asList(engine.getSupportedCipherSuites()));
|
||||
jdkSupportedCiphers.retainAll(SSLConfigConstants.getSecureSSLCiphers(Settings.EMPTY, false));
|
||||
engine.setEnabledCipherSuites(jdkSupportedCiphers.toArray(new String[0]));
|
||||
|
||||
final List<String> jdkEnabledCiphers = Arrays.asList(engine.getEnabledCipherSuites());
|
||||
// example
|
||||
// TLS_RSA_WITH_AES_128_CBC_SHA256, TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA,
|
||||
// TLS_RSA_WITH_AES_128_CBC_SHA, TLS_DHE_RSA_WITH_AES_128_CBC_SHA
|
||||
System.out.println("JDK enabled ciphers: " + jdkEnabledCiphers);
|
||||
Assert.assertTrue(jdkEnabledCiphers.size() > 0);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testUnmodifieableCipherProtocolConfig() throws Exception {
|
||||
SSLConfigConstants.getSecureSSLProtocols(Settings.EMPTY, false)[0] = "bogus";
|
||||
Assert.assertEquals("TLSv1.3", SSLConfigConstants.getSecureSSLProtocols(Settings.EMPTY, false)[0]);
|
||||
|
||||
try {
|
||||
SSLConfigConstants.getSecureSSLCiphers(Settings.EMPTY, false).set(0, "bogus");
|
||||
Assert.fail();
|
||||
} catch (UnsupportedOperationException e) {
|
||||
//expected
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCustomPrincipalExtractor() throws Exception {
|
||||
|
||||
enableHTTPClientSSL = true;
|
||||
trustHTTPServerCertificate = true;
|
||||
sendHTTPClientCertificate = true;
|
||||
|
||||
final Settings settings = Settings.builder().put("opendistro_security.ssl.transport.enabled", true)
|
||||
.put(SSLConfigConstants.OPENDISTRO_SECURITY_SSL_HTTP_ENABLE_OPENSSL_IF_AVAILABLE, allowOpenSSL)
|
||||
.put(SSLConfigConstants.OPENDISTRO_SECURITY_SSL_TRANSPORT_ENABLE_OPENSSL_IF_AVAILABLE, allowOpenSSL)
|
||||
.put(SSLConfigConstants.OPENDISTRO_SECURITY_SSL_TRANSPORT_KEYSTORE_ALIAS, "node-0")
|
||||
.put("opendistro_security.ssl.transport.keystore_filepath", getAbsoluteFilePathFromClassPath("node-0-keystore.jks"))
|
||||
.put("opendistro_security.ssl.transport.truststore_filepath", getAbsoluteFilePathFromClassPath("truststore.jks"))
|
||||
.put("opendistro_security.ssl.transport.enforce_hostname_verification", false)
|
||||
.put("opendistro_security.ssl.transport.resolve_hostname", false)
|
||||
.put("opendistro_security.ssl.transport.principal_extractor_class", "com.amazon.opendistroforelasticsearch.security.ssl.TestPrincipalExtractor")
|
||||
.put(SSLConfigConstants.OPENDISTRO_SECURITY_SSL_HTTP_KEYSTORE_ALIAS, "node-0")
|
||||
.put("opendistro_security.ssl.http.enabled", true)
|
||||
.put("opendistro_security.ssl.http.keystore_filepath", getAbsoluteFilePathFromClassPath("node-0-keystore.jks"))
|
||||
.put("opendistro_security.ssl.http.truststore_filepath", getAbsoluteFilePathFromClassPath("truststore.jks")).build();
|
||||
|
||||
startES(settings);
|
||||
|
||||
log.debug("Elasticsearch started");
|
||||
|
||||
final Settings tcSettings = Settings.builder().put("cluster.name", clustername).put("path.home", ".").put(settings).build();
|
||||
|
||||
try (TransportClient tc = new TransportClientImpl(tcSettings, asCollection(OpenDistroSecuritySSLPlugin.class))) {
|
||||
|
||||
log.debug("TransportClient built, connect now to {}:{}", nodeHost, nodePort);
|
||||
|
||||
tc.addTransportAddress(new TransportAddress(new InetSocketAddress(nodeHost, nodePort)));
|
||||
Assert.assertEquals(3, tc.admin().cluster().nodesInfo(new NodesInfoRequest()).actionGet().getNodes().size());
|
||||
log.debug("TransportClient connected");
|
||||
TestPrincipalExtractor.reset();
|
||||
Assert.assertEquals("test", tc.index(new IndexRequest("test","test").setRefreshPolicy(RefreshPolicy.IMMEDIATE).source("{\"a\":5}", XContentType.JSON)).actionGet().getIndex());
|
||||
log.debug("Index created");
|
||||
Assert.assertEquals(1L, tc.search(new SearchRequest("test")).actionGet().getHits().getTotalHits());
|
||||
log.debug("Search done");
|
||||
Assert.assertEquals(3, tc.admin().cluster().health(new ClusterHealthRequest("test")).actionGet().getNumberOfNodes());
|
||||
log.debug("ClusterHealth done");
|
||||
Assert.assertEquals(3, tc.admin().cluster().nodesInfo(new NodesInfoRequest()).actionGet().getNodes().size());
|
||||
log.debug("NodesInfoRequest asserted");
|
||||
}
|
||||
|
||||
executeSimpleRequest("_opendistro/_security/sslinfo?pretty");
|
||||
|
||||
//we need to test this in Security itself because in the SSL only plugin the info is not longer propagated
|
||||
//Assert.assertTrue(TestPrincipalExtractor.getTransportCount() > 0);
|
||||
Assert.assertTrue(TestPrincipalExtractor.getHttpCount() > 0);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCRLPem() throws Exception {
|
||||
|
||||
enableHTTPClientSSL = true;
|
||||
trustHTTPServerCertificate = true;
|
||||
sendHTTPClientCertificate = true;
|
||||
|
||||
final Settings settings = Settings.builder().put("opendistro_security.ssl.transport.enabled", true)
|
||||
.put(SSLConfigConstants.OPENDISTRO_SECURITY_SSL_HTTP_ENABLE_OPENSSL_IF_AVAILABLE, allowOpenSSL)
|
||||
.put(SSLConfigConstants.OPENDISTRO_SECURITY_SSL_TRANSPORT_ENABLE_OPENSSL_IF_AVAILABLE, allowOpenSSL)
|
||||
.put(SSLConfigConstants.OPENDISTRO_SECURITY_SSL_TRANSPORT_PEMCERT_FILEPATH, getAbsoluteFilePathFromClassPath("node-0.crt.pem"))
|
||||
.put(SSLConfigConstants.OPENDISTRO_SECURITY_SSL_TRANSPORT_PEMKEY_FILEPATH, getAbsoluteFilePathFromClassPath("node-0.key.pem"))
|
||||
//.put(SSLConfigConstants.OPENDISTRO_SECURITY_SSL_TRANSPORT_PEMKEY_PASSWORD, "changeit")
|
||||
.put(SSLConfigConstants.OPENDISTRO_SECURITY_SSL_TRANSPORT_PEMTRUSTEDCAS_FILEPATH, getAbsoluteFilePathFromClassPath("root-ca.pem"))
|
||||
.put("opendistro_security.ssl.transport.enforce_hostname_verification", false)
|
||||
.put("opendistro_security.ssl.transport.resolve_hostname", false)
|
||||
|
||||
.put("opendistro_security.ssl.http.enabled", true)
|
||||
.put("opendistro_security.ssl.http.clientauth_mode", "REQUIRE")
|
||||
.put(SSLConfigConstants.OPENDISTRO_SECURITY_SSL_HTTP_PEMCERT_FILEPATH, getAbsoluteFilePathFromClassPath("node-0.crt.pem"))
|
||||
.put(SSLConfigConstants.OPENDISTRO_SECURITY_SSL_HTTP_PEMKEY_FILEPATH, getAbsoluteFilePathFromClassPath("node-0.key.pem"))
|
||||
//.put(SSLConfigConstants.OPENDISTRO_SECURITY_SSL_HTTP_PEMKEY_PASSWORD, "changeit")
|
||||
.put(SSLConfigConstants.OPENDISTRO_SECURITY_SSL_HTTP_PEMTRUSTEDCAS_FILEPATH, getAbsoluteFilePathFromClassPath("chain-ca.pem"))
|
||||
.put(SSLConfigConstants.OPENDISTRO_SECURITY_SSL_HTTP_CRL_VALIDATE, true)
|
||||
.put(SSLConfigConstants.OPENDISTRO_SECURITY_SSL_HTTP_CRL_VALIDATION_DATE, CertificateValidatorTest.CRL_DATE.getTime())
|
||||
.build();
|
||||
|
||||
startES(settings);
|
||||
Assert.assertTrue(executeSimpleRequest("_opendistro/_security/sslinfo?pretty").contains("TLS"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCRL() throws Exception {
|
||||
|
||||
enableHTTPClientSSL = true;
|
||||
trustHTTPServerCertificate = true;
|
||||
sendHTTPClientCertificate = true;
|
||||
|
||||
final Settings settings = Settings.builder().put("opendistro_security.ssl.transport.enabled", false)
|
||||
.put(SSLConfigConstants.OPENDISTRO_SECURITY_SSL_HTTP_KEYSTORE_ALIAS, "node-0").put("opendistro_security.ssl.http.enabled", true)
|
||||
.put(SSLConfigConstants.OPENDISTRO_SECURITY_SSL_HTTP_ENABLE_OPENSSL_IF_AVAILABLE, allowOpenSSL)
|
||||
.put(SSLConfigConstants.OPENDISTRO_SECURITY_SSL_TRANSPORT_ENABLE_OPENSSL_IF_AVAILABLE, allowOpenSSL)
|
||||
.put("opendistro_security.ssl.http.clientauth_mode", "REQUIRE")
|
||||
.put("opendistro_security.ssl.http.keystore_filepath", getAbsoluteFilePathFromClassPath("node-0-keystore.jks"))
|
||||
.put("opendistro_security.ssl.http.truststore_filepath", getAbsoluteFilePathFromClassPath("truststore.jks"))
|
||||
.put(SSLConfigConstants.OPENDISTRO_SECURITY_SSL_HTTP_CRL_VALIDATE, true)
|
||||
.put(SSLConfigConstants.OPENDISTRO_SECURITY_SSL_HTTP_CRL_FILE, getAbsoluteFilePathFromClassPath("crl/revoked.crl"))
|
||||
.put(SSLConfigConstants.OPENDISTRO_SECURITY_SSL_HTTP_CRL_VALIDATION_DATE, CertificateValidatorTest.CRL_DATE.getTime())
|
||||
.build();
|
||||
|
||||
startES(settings);
|
||||
|
||||
Assert.assertTrue(executeSimpleRequest("_nodes/settings?pretty").contains(clustername));
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testNodeClientSSLwithJavaTLSv13() throws Exception {
|
||||
|
||||
//Java TLS 1.3 is available since Java 11
|
||||
Assume.assumeTrue(!allowOpenSSL && PlatformDependent.javaVersion() >= 11);
|
||||
|
||||
final Settings settings = Settings.builder().put("opendistro_security.ssl.transport.enabled", true)
|
||||
.put(SSLConfigConstants.OPENDISTRO_SECURITY_SSL_HTTP_ENABLE_OPENSSL_IF_AVAILABLE, allowOpenSSL)
|
||||
.put(SSLConfigConstants.OPENDISTRO_SECURITY_SSL_TRANSPORT_ENABLE_OPENSSL_IF_AVAILABLE, allowOpenSSL)
|
||||
.put(SSLConfigConstants.OPENDISTRO_SECURITY_SSL_TRANSPORT_KEYSTORE_ALIAS, "node-0")
|
||||
.put("opendistro_security.ssl.transport.keystore_filepath", getAbsoluteFilePathFromClassPath("node-0-keystore.jks"))
|
||||
.put("opendistro_security.ssl.transport.truststore_filepath", getAbsoluteFilePathFromClassPath("truststore.jks"))
|
||||
.put("opendistro_security.ssl.transport.enforce_hostname_verification", false)
|
||||
.put("opendistro_security.ssl.transport.resolve_hostname", false)
|
||||
.putList(SSLConfigConstants.OPENDISTRO_SECURITY_SSL_TRANSPORT_ENABLED_PROTOCOLS, "TLSv1.3")
|
||||
.putList(SSLConfigConstants.OPENDISTRO_SECURITY_SSL_TRANSPORT_ENABLED_CIPHERS, "TLS_AES_128_GCM_SHA256")
|
||||
.build();
|
||||
|
||||
startES(settings);
|
||||
|
||||
final Settings tcSettings = Settings.builder().put("cluster.name", clustername).put("path.home", ".")
|
||||
.put("node.name", "client_node_" + new Random().nextInt())
|
||||
.put(settings)// -----
|
||||
.build();
|
||||
|
||||
try (Node node = new PluginAwareNode(tcSettings, Netty4Plugin.class, OpenDistroSecuritySSLPlugin.class).start()) {
|
||||
ClusterHealthResponse res = node.client().admin().cluster().health(new ClusterHealthRequest().waitForNodes("4").timeout(TimeValue.timeValueSeconds(5))).actionGet();
|
||||
Assert.assertFalse(res.isTimedOut());
|
||||
Assert.assertEquals(4, res.getNumberOfNodes());
|
||||
Assert.assertEquals(4, node.client().admin().cluster().nodesInfo(new NodesInfoRequest()).actionGet().getNodes().size());
|
||||
}
|
||||
|
||||
Assert.assertFalse(executeSimpleRequest("_nodes/stats?pretty").contains("\"tx_size_in_bytes\" : 0"));
|
||||
Assert.assertFalse(executeSimpleRequest("_nodes/stats?pretty").contains("\"rx_count\" : 0"));
|
||||
Assert.assertFalse(executeSimpleRequest("_nodes/stats?pretty").contains("\"rx_size_in_bytes\" : 0"));
|
||||
Assert.assertFalse(executeSimpleRequest("_nodes/stats?pretty").contains("\"tx_count\" : 0"));
|
||||
}
|
||||
}
|
@ -0,0 +1,71 @@
|
||||
/*
|
||||
* Copyright 2015-2018 _floragunn_ GmbH
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Portions Copyright 2019 Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License").
|
||||
* You may not use this file except in compliance with the License.
|
||||
* A copy of the License is located at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* or in the "license" file accompanying this file. This file is distributed
|
||||
* on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
|
||||
* express or implied. See the License for the specific language governing
|
||||
* permissions and limitations under the License.
|
||||
*/
|
||||
|
||||
package com.amazon.opendistroforelasticsearch.security.ssl;
|
||||
|
||||
import java.security.cert.X509Certificate;
|
||||
|
||||
import com.amazon.opendistroforelasticsearch.security.ssl.transport.PrincipalExtractor;
|
||||
|
||||
public class TestPrincipalExtractor implements PrincipalExtractor {
|
||||
|
||||
private static int transportCount = 0;
|
||||
private static int httpCount = 0;
|
||||
|
||||
public TestPrincipalExtractor() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public String extractPrincipal(X509Certificate x509Certificate, Type type) {
|
||||
if(type == Type.HTTP) {
|
||||
httpCount++;
|
||||
}
|
||||
|
||||
if(type == Type.TRANSPORT) {
|
||||
transportCount++;
|
||||
}
|
||||
|
||||
return "testdn";
|
||||
}
|
||||
|
||||
public static int getTransportCount() {
|
||||
return transportCount;
|
||||
}
|
||||
|
||||
public static int getHttpCount() {
|
||||
return httpCount;
|
||||
}
|
||||
|
||||
public static void reset() {
|
||||
httpCount = 0;
|
||||
transportCount = 0;
|
||||
}
|
||||
|
||||
}
|
51
src/test/java/org/elasticsearch/node/PluginAwareNode.java
Normal file
51
src/test/java/org/elasticsearch/node/PluginAwareNode.java
Normal file
@ -0,0 +1,51 @@
|
||||
/*
|
||||
* Copyright 2015-2018 _floragunn_ GmbH
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Portions Copyright 2019 Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License").
|
||||
* You may not use this file except in compliance with the License.
|
||||
* A copy of the License is located at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* or in the "license" file accompanying this file. This file is distributed
|
||||
* on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
|
||||
* express or implied. See the License for the specific language governing
|
||||
* permissions and limitations under the License.
|
||||
*/
|
||||
|
||||
package org.elasticsearch.node;
|
||||
|
||||
import java.util.Arrays;
|
||||
|
||||
import org.elasticsearch.common.logging.LogConfigurator;
|
||||
import org.elasticsearch.common.settings.Settings;
|
||||
import org.elasticsearch.plugins.Plugin;
|
||||
|
||||
public class PluginAwareNode extends Node {
|
||||
|
||||
@SafeVarargs
|
||||
public PluginAwareNode(final Settings preparedSettings, final Class<? extends Plugin>... plugins) {
|
||||
super(InternalSettingsPreparer.prepareEnvironment(preparedSettings, null), Arrays.asList(plugins), true);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void registerDerivedNodeNameWithLogger(String nodeName) {
|
||||
System.out.println("nn "+nodeName);
|
||||
LogConfigurator.setNodeName(nodeName);
|
||||
}
|
||||
}
|
48
src/test/resources/chain-ca.pem
Normal file
48
src/test/resources/chain-ca.pem
Normal file
@ -0,0 +1,48 @@
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIIEBzCCAu+gAwIBAgIBAjANBgkqhkiG9w0BAQsFADCBjzETMBEGCgmSJomT8ixk
|
||||
ARkWA2NvbTEXMBUGCgmSJomT8ixkARkWB2V4YW1wbGUxGTAXBgNVBAoMEEV4YW1w
|
||||
bGUgQ29tIEluYy4xITAfBgNVBAsMGEV4YW1wbGUgQ29tIEluYy4gUm9vdCBDQTEh
|
||||
MB8GA1UEAwwYRXhhbXBsZSBDb20gSW5jLiBSb290IENBMB4XDTE4MDUwNTE0Mzcw
|
||||
OFoXDTI4MDUwNDE0MzcwOFowgZUxEzARBgoJkiaJk/IsZAEZFgNjb20xFzAVBgoJ
|
||||
kiaJk/IsZAEZFgdleGFtcGxlMRkwFwYDVQQKDBBFeGFtcGxlIENvbSBJbmMuMSQw
|
||||
IgYDVQQLDBtFeGFtcGxlIENvbSBJbmMuIFNpZ25pbmcgQ0ExJDAiBgNVBAMMG0V4
|
||||
YW1wbGUgQ29tIEluYy4gU2lnbmluZyBDQTCCASIwDQYJKoZIhvcNAQEBBQADggEP
|
||||
ADCCAQoCggEBANWsMh2EWiqH2eZmaiHreWG4NlhLZGcUbwzRIZT0HmeeBolQygGq
|
||||
cJE1MpzCMYdezjTRaws/FVA2dkrtcox2xGT6YG7sKqr+4VlIt3Pd0Sah/5dEdRJv
|
||||
RsN2mj8V8xNUZdduD6NnrIGW/wAoF4isDNJ3QlGFhPM0f0Of5TVFIyholgrevNLT
|
||||
7D5rdUupIW192zQbOOuOxOmeXkunl8u35wq/VI/ZyJ4/mutCLR5sqd6/kOSDKQTU
|
||||
gQ+xIrs7LiuF1xZbCtRT3/PWnnD/GJulUsuJ0xOeEHkQaJuwRwYzqFkyVrEea2Wf
|
||||
U6XmSRZK9L0q5jy8TpCgzULlxb92POZd9ssCAwEAAaNmMGQwDgYDVR0PAQH/BAQD
|
||||
AgEGMBIGA1UdEwEB/wQIMAYBAf8CAQAwHQYDVR0OBBYEFJR34pMxCz+258vljmpE
|
||||
pMTjBMHgMB8GA1UdIwQYMBaAFFvHubBG7v/2QuZe5M8S+FdMajAVMA0GCSqGSIb3
|
||||
DQEBCwUAA4IBAQAY22ahhmYBdYUpPwQEyEUexyTWal29sbV+R44qVKM6FDEEd/8Q
|
||||
cFe5cnguDqmLBwHDLey4eSsAHI5tBUtslPJMqobWbwzswxdZ9WCOaLBWlvZdK4XU
|
||||
hkrq919wENMT6DVagNdpNRmDA47G4eRha4oD1ZO2YCFM0H8rEWDRSlaAHsGHLR59
|
||||
cJ5AgPqAVrEMfP6WzxXW2ThY6HD1LsE69T20/CfR8/k826BkcYVHKR/MQ/YZOWXb
|
||||
ccfb7D5o/oMop0E4+huCdF7ZDOt7/f5+BAfJZ08GCMLy5GSxU9gf8WiT/yNBYETS
|
||||
DAj+BAKhzlzvsaC3E2lAeyUepIMN0B8YHjqV
|
||||
-----END CERTIFICATE-----
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIID/jCCAuagAwIBAgIBATANBgkqhkiG9w0BAQsFADCBjzETMBEGCgmSJomT8ixk
|
||||
ARkWA2NvbTEXMBUGCgmSJomT8ixkARkWB2V4YW1wbGUxGTAXBgNVBAoMEEV4YW1w
|
||||
bGUgQ29tIEluYy4xITAfBgNVBAsMGEV4YW1wbGUgQ29tIEluYy4gUm9vdCBDQTEh
|
||||
MB8GA1UEAwwYRXhhbXBsZSBDb20gSW5jLiBSb290IENBMB4XDTE4MDUwNTE0Mzcw
|
||||
OFoXDTI4MDUwNDE0MzcwOFowgY8xEzARBgoJkiaJk/IsZAEZFgNjb20xFzAVBgoJ
|
||||
kiaJk/IsZAEZFgdleGFtcGxlMRkwFwYDVQQKDBBFeGFtcGxlIENvbSBJbmMuMSEw
|
||||
HwYDVQQLDBhFeGFtcGxlIENvbSBJbmMuIFJvb3QgQ0ExITAfBgNVBAMMGEV4YW1w
|
||||
bGUgQ29tIEluYy4gUm9vdCBDQTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoC
|
||||
ggEBAKYR4V2qdDbh2EMyNxQrXj4ucmA7b058s1zqiNwYQYRmQuZSp2hCmNcZuOa2
|
||||
4yt0fXHSDLYNDdVKgC0K9nm25Tyw/ZxScKdiGyYAmzK+0mhaT5gZsovpHMSc8tco
|
||||
10r6floxCkazLHaUgCAFv1uaNvIKK88KKHjXm5i0NPmx/4VW9IkJuYmi/ECdea5R
|
||||
76LAB21ih8kroVI0eRhHB1VzbYE9izneMJ5UBfLHF2iMR/RTilgs5IAkpdlj6guh
|
||||
CvSJsbOj0fmmcESUrPwKAEfhGVGfiE7b15Ho5ECQR6yn1CDiulpOLmthp7zcZ2jx
|
||||
BzevtTNeWzPom021hKG0nryoH5UCAwEAAaNjMGEwDgYDVR0PAQH/BAQDAgEGMA8G
|
||||
A1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFFvHubBG7v/2QuZe5M8S+FdMajAVMB8G
|
||||
A1UdIwQYMBaAFFvHubBG7v/2QuZe5M8S+FdMajAVMA0GCSqGSIb3DQEBCwUAA4IB
|
||||
AQAqW6C1XKJZH6GQydHFcUToLpm4YSypqZvD0Wf39dXNygih8szydtxtKEYjFivx
|
||||
O3oOa4v3J/52y4oNc2ksFyhXRAJhKEE58NHDGtb6eqUWWt9k2YrnsvD8k0hibjzt
|
||||
TmAWTYxYIMdF+4E0hfNUxkFmXXtThOoMhdcEqUYVXrVdrUOF9tVm49BCsQrrCkQw
|
||||
Q0vWvgTaik0sgsz4yaKI+iORt9qF74/Wf7KjLPpZR3OkkE1srfWhCszNzUB0CMD4
|
||||
34v9bIRWtjzvVQTCNNm9PaB2tMkQmeK+jOR7ywItO0+mij0vDSK3bWGqTrfgAXUn
|
||||
pTIIfrQcZ1vrDg0lYzVgQ1iT
|
||||
-----END CERTIFICATE-----
|
14
src/test/resources/crl/revoked.crl
Normal file
14
src/test/resources/crl/revoked.crl
Normal file
@ -0,0 +1,14 @@
|
||||
-----BEGIN X509 CRL-----
|
||||
MIICJzCCAQ8CAQEwDQYJKoZIhvcNAQELBQAwgZUxEzARBgoJkiaJk/IsZAEZFgNj
|
||||
b20xFzAVBgoJkiaJk/IsZAEZFgdleGFtcGxlMRkwFwYDVQQKDBBFeGFtcGxlIENv
|
||||
bSBJbmMuMSQwIgYDVQQLDBtFeGFtcGxlIENvbSBJbmMuIFNpZ25pbmcgQ0ExJDAi
|
||||
BgNVBAMMG0V4YW1wbGUgQ29tIEluYy4gU2lnbmluZyBDQRcNMTgwNTA1MTQzNzEz
|
||||
WhcNMTgwNjA0MTQzNzEzWjAUMBICAQQXDTE4MDUwNTE0MzcxM1qgLzAtMB8GA1Ud
|
||||
IwQYMBaAFJR34pMxCz+258vljmpEpMTjBMHgMAoGA1UdFAQDAgECMA0GCSqGSIb3
|
||||
DQEBCwUAA4IBAQBrfIw3gou9Rcrv5ih/Pm6Ghot8dZosJvpG+gMbU6+ZmBwldfMI
|
||||
qNW5zEKm3pjKw6412MfjqhPV8ioKolxfHVBockH//a0fbo0VUH0H9K2C9lcKbHXV
|
||||
h97x3ubrKkF/TqY9xKUTRbNJ5pUNGgq2SLnjaVHdI1dSQ17V6yIepJV6xk6s3jbl
|
||||
bPf/rJAr7Ft4XLnw6LUuXSWN0vTxolQxHACTST8GBMsE57Vbs6TneCo3eOa6HwO6
|
||||
Yolz3GTaVoF1wireUkNUAi+nf5T72HlgrMBEU24qbIuM2IcI0DuLMGISbFqp+BkK
|
||||
74YjkYcDKqehftGJQPVqFTQTX/VnXOBWp0ww
|
||||
-----END X509 CRL-----
|
50
src/test/resources/crl/revoked.crt.pem
Normal file
50
src/test/resources/crl/revoked.crt.pem
Normal file
@ -0,0 +1,50 @@
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIIEczCCA1ugAwIBAgIBBDANBgkqhkiG9w0BAQsFADCBlTETMBEGCgmSJomT8ixk
|
||||
ARkWA2NvbTEXMBUGCgmSJomT8ixkARkWB2V4YW1wbGUxGTAXBgNVBAoMEEV4YW1w
|
||||
bGUgQ29tIEluYy4xJDAiBgNVBAsMG0V4YW1wbGUgQ29tIEluYy4gU2lnbmluZyBD
|
||||
QTEkMCIGA1UEAwwbRXhhbXBsZSBDb20gSW5jLiBTaWduaW5nIENBMB4XDTE4MDUw
|
||||
NTE0MzcxM1oXDTI4MDUwMjE0MzcxM1owVzELMAkGA1UEBhMCREUxDTALBgNVBAcM
|
||||
BFRlc3QxDTALBgNVBAoMBFRlc3QxDDAKBgNVBAsMA1NTTDEcMBoGA1UEAwwTcmV2
|
||||
b2tlZC5leGFtcGxlLmNvbTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEB
|
||||
AKxwDZ7p6XYyfUSvaoBe8LzWYAm5QLcia/CVihP57OxZZoggIXNZjzmXQfgDR/Kq
|
||||
OJeIBSJuNRmyZBqXZ1Hn5gTX7/JiZV3+vNGf3MhPjE6yhULRiASvi9S7oKyz6msW
|
||||
r1fC8cXfhdnwtp2xcszBww+28MqCK+FVe4351H9/vjkaBgpG6bFg8TAtCGmhgZCZ
|
||||
86o3e4+6GTIdDj8oWhNbz3VMxtNgMNmQX/JZYvq0SX6qbAQ2O9qSP41j2BnqDL8u
|
||||
9iVK9S5lsciezROOa8ULKB1qsD/L8Giw23IZiSLLN+CsX9bKyc3kvXD/Po5mNcAb
|
||||
5l08cm/u4WrPFiK1+CHoivMCAwEAAaOCAQkwggEFMA4GA1UdDwEB/wQEAwIFoDAJ
|
||||
BgNVHRMEAjAAMB0GA1UdJQQWMBQGCCsGAQUFBwMBBggrBgEFBQcDAjAdBgNVHQ4E
|
||||
FgQUy1zyrICC0otqxUy17nO6vHuCvBYwHwYDVR0jBBgwFoAUlHfikzELP7bny+WO
|
||||
akSkxOMEweAwYgYDVR0fBFswWTBXoFWgU4ZRaHR0cHM6Ly9yYXcuZ2l0aHVidXNl
|
||||
cmNvbnRlbnQuY29tL2Zsb3JhZ3VubmNvbS91bml0dGVzdC1hc3NldHMvbWFzdGVy
|
||||
L3Jldm9rZWQuY3JsMCUGA1UdEQQeMByCE3Jldm9rZWQuZXhhbXBsZS5jb22IBSoD
|
||||
BAUFMA0GCSqGSIb3DQEBCwUAA4IBAQDG6Ov5TMUdofGHKQgSjJDzka4XtQtMU7PP
|
||||
rPvomrL6RsCEYv4hpbJwiZQuoMAPTQX14b9I+doQtN7kMb7nXK+UEOXff9LIUPi1
|
||||
qS9OR6ViB3u1M9AV9vWIbUd3stqLr1Oceba+ISXxThW73eXpPnEFZXaA/1s84aqa
|
||||
PrAIS7vsLrWI1TtsoyxZdzSVCjq5PjlAEW1hkrTw8GFe0ayIi1Vc4jWYlYJhCWn2
|
||||
GRmpmARbV7yq1h+1Cp0bDs0LykUsAkTpiWN+E5YcS9Nt882ZRmQ59dkctvxxJzW8
|
||||
+YMJisWjXv1Ssr1WokIMC+uVBcltzaIs+DY2guSmSOhBDHMKv8Jb
|
||||
-----END CERTIFICATE-----
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIIEBzCCAu+gAwIBAgIBAjANBgkqhkiG9w0BAQsFADCBjzETMBEGCgmSJomT8ixk
|
||||
ARkWA2NvbTEXMBUGCgmSJomT8ixkARkWB2V4YW1wbGUxGTAXBgNVBAoMEEV4YW1w
|
||||
bGUgQ29tIEluYy4xITAfBgNVBAsMGEV4YW1wbGUgQ29tIEluYy4gUm9vdCBDQTEh
|
||||
MB8GA1UEAwwYRXhhbXBsZSBDb20gSW5jLiBSb290IENBMB4XDTE4MDUwNTE0Mzcw
|
||||
OFoXDTI4MDUwNDE0MzcwOFowgZUxEzARBgoJkiaJk/IsZAEZFgNjb20xFzAVBgoJ
|
||||
kiaJk/IsZAEZFgdleGFtcGxlMRkwFwYDVQQKDBBFeGFtcGxlIENvbSBJbmMuMSQw
|
||||
IgYDVQQLDBtFeGFtcGxlIENvbSBJbmMuIFNpZ25pbmcgQ0ExJDAiBgNVBAMMG0V4
|
||||
YW1wbGUgQ29tIEluYy4gU2lnbmluZyBDQTCCASIwDQYJKoZIhvcNAQEBBQADggEP
|
||||
ADCCAQoCggEBANWsMh2EWiqH2eZmaiHreWG4NlhLZGcUbwzRIZT0HmeeBolQygGq
|
||||
cJE1MpzCMYdezjTRaws/FVA2dkrtcox2xGT6YG7sKqr+4VlIt3Pd0Sah/5dEdRJv
|
||||
RsN2mj8V8xNUZdduD6NnrIGW/wAoF4isDNJ3QlGFhPM0f0Of5TVFIyholgrevNLT
|
||||
7D5rdUupIW192zQbOOuOxOmeXkunl8u35wq/VI/ZyJ4/mutCLR5sqd6/kOSDKQTU
|
||||
gQ+xIrs7LiuF1xZbCtRT3/PWnnD/GJulUsuJ0xOeEHkQaJuwRwYzqFkyVrEea2Wf
|
||||
U6XmSRZK9L0q5jy8TpCgzULlxb92POZd9ssCAwEAAaNmMGQwDgYDVR0PAQH/BAQD
|
||||
AgEGMBIGA1UdEwEB/wQIMAYBAf8CAQAwHQYDVR0OBBYEFJR34pMxCz+258vljmpE
|
||||
pMTjBMHgMB8GA1UdIwQYMBaAFFvHubBG7v/2QuZe5M8S+FdMajAVMA0GCSqGSIb3
|
||||
DQEBCwUAA4IBAQAY22ahhmYBdYUpPwQEyEUexyTWal29sbV+R44qVKM6FDEEd/8Q
|
||||
cFe5cnguDqmLBwHDLey4eSsAHI5tBUtslPJMqobWbwzswxdZ9WCOaLBWlvZdK4XU
|
||||
hkrq919wENMT6DVagNdpNRmDA47G4eRha4oD1ZO2YCFM0H8rEWDRSlaAHsGHLR59
|
||||
cJ5AgPqAVrEMfP6WzxXW2ThY6HD1LsE69T20/CfR8/k826BkcYVHKR/MQ/YZOWXb
|
||||
ccfb7D5o/oMop0E4+huCdF7ZDOt7/f5+BAfJZ08GCMLy5GSxU9gf8WiT/yNBYETS
|
||||
DAj+BAKhzlzvsaC3E2lAeyUepIMN0B8YHjqV
|
||||
-----END CERTIFICATE-----
|
29
src/test/resources/crl/revoked.key
Normal file
29
src/test/resources/crl/revoked.key
Normal file
@ -0,0 +1,29 @@
|
||||
-----BEGIN ENCRYPTED PRIVATE KEY-----
|
||||
MIIE6TAbBgkqhkiG9w0BBQMwDgQIuBSRCrFlilwCAggABIIEyGvzG/HskxEPdjlB
|
||||
UH23XevwHIWn2sf7mlsZipfBsgjm9v3kizTlbAlVrgHspuU2DK+Sd9pVoKGZ3HBA
|
||||
nqt5RjPyXUtG9+RClGIF6KxErHCokF35iYb+7wGB4eZjGr1Pthl7Qffb62FT0Ecx
|
||||
aP+4daY8ZHYujjNsFRAcrEvad72xRZh9+quZZWnOYYYh8wIpHBjBPvWOJdgnWA0C
|
||||
hkFlqjBgqCFOkWFfSHO8TVwywU+QAH4/CW7RVWIpPUZmB7D5XhB7GHDunnA5sZZS
|
||||
chHzJ+tyEQ2eryz4/raeFsOeRgdHMWxTJeLflLmJFBDglmsVg2ly0noobOaPtOOL
|
||||
SxEzgVEC6pJ9hlWvwiAbTmnHaCdp8Oo8mVMemMrgxME7a7gPw8DfY9VJ9zc3JNk6
|
||||
4eBYZMeG9HnBLLqG1LOsEt32QOIegHrEx729WpyEAXtYd7G+ZY0qT5LG5Vscy1vf
|
||||
LGGPagcg1x6Bk8f8oxMRlMdMXHWPdYYvE9kQz+tiM2n/HAipUotgYGnC4jl/ux/Q
|
||||
wvTK9qj2iHC7PTGdIeV08b01wvljfWWRLh5oMm3lQuxSTcHXx0+vw+OBuicEYwwb
|
||||
KFyo/qPRqautDKLsHyNBUR1xbt43ZGP8ziwxLxJeNrSzmUed7gFsFZllg8czXlLk
|
||||
54Wl3Ism6G9jkjb+K+QXKI2FKdb4RZmXmMXwrQnI8U77W1YT2g1p5W/e1w+/cVvE
|
||||
vNQFcnIBTXvLKh3hM95X+QvFhIW4dXHHU4E+6GvNtp2IR27isfR+xc4BFicXsA4F
|
||||
Ngz5qr8CJN5VT5XONGx9HuSF/oT3nu2S6LRVjkdLLo5ygCULLN9TdovtPrBrI0u9
|
||||
oZALTXQVqGEBS+7YEO315EvWYk9RA1pAYqpho3lDGCUbO8y4RmuXjv1WsfM0qDl3
|
||||
JF/aYgqJshF1lgMv5Dx8GTCUGawv3r53T2IWhI+MEbAzyrD/1Xs2+C4RCEsOE+bb
|
||||
9pFvoDWWmLQzwagERsFdixdTvW4hBb/x/BJcD0FYoIN8FRp9/X8r8jclF3uIW5LY
|
||||
9TikkjjPi25tAYKrlAkg+zcmDBnlL266UTa2BF5wtw34a8EbXb7bTSKWtjmS4f6G
|
||||
gEaU7n3UwAE4yzJvY7h+OMbdoiCzf+Jlq+v8lEpGAmE1leSPd8OaWGcSsg20CjUc
|
||||
0eCxFm4FGDFPn0OD4XiSFviFoyVngWx2H3ztSeP3tkCGKa7mYVf6slc8MNqa/emQ
|
||||
NkzTmSr0Z+aGnCLfb2Y4B6F7kMk93+sYNXW1n2D1FECQbf84XgfjUB4D2FeGfPVT
|
||||
L2MFVgUe42HBy7J3v0a4yAfb77LtAEild2PgWYQR5oKTnUndpiSj0Hxtwqy8gxac
|
||||
K37V+SVbsi5JVCAjpu8r8bK7Dsw3937CjArOCKRj2iYYRf54rP58SG6EiIrZzQZh
|
||||
DR8f9IZU7zEVzNfaH0canP0+ShqRUkoe5h2GyFRJnjDrZYRFoLRUFs4Bkqlhag9F
|
||||
ws2N/eU9al8m6eursmBO6ZZnv2adIUF1A33Efk/vuKjy7Rd19HD/G45uji9U3tsJ
|
||||
ygcKCS82yWsqbAcNAd7e2+MAyLnrh3ERyvW3ywr8am1Pk+nNbfDD/DK6kh+YOvol
|
||||
Ax3JqWKlwZZ+pSls/A==
|
||||
-----END ENCRYPTED PRIVATE KEY-----
|
BIN
src/test/resources/crl/revoked.p12
Normal file
BIN
src/test/resources/crl/revoked.p12
Normal file
Binary file not shown.
BIN
src/test/resources/kirk-keystore.jks
Normal file
BIN
src/test/resources/kirk-keystore.jks
Normal file
Binary file not shown.
BIN
src/test/resources/kirk-keystore.p12
Normal file
BIN
src/test/resources/kirk-keystore.p12
Normal file
Binary file not shown.
30
src/test/resources/kirk.crt.pem
Normal file
30
src/test/resources/kirk.crt.pem
Normal file
@ -0,0 +1,30 @@
|
||||
Bag Attributes
|
||||
friendlyName: kirk
|
||||
localKeyID: 54 69 6D 65 20 31 35 32 35 35 33 31 30 33 36 39 34 34
|
||||
subject=/C=DE/L=Test/O=client/OU=client/CN=kirk
|
||||
issuer=/DC=com/DC=example/O=Example Com Inc./OU=Example Com Inc. Signing CA/CN=Example Com Inc. Signing CA
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIIEQDCCAyigAwIBAgIBCDANBgkqhkiG9w0BAQsFADCBlTETMBEGCgmSJomT8ixk
|
||||
ARkWA2NvbTEXMBUGCgmSJomT8ixkARkWB2V4YW1wbGUxGTAXBgNVBAoMEEV4YW1w
|
||||
bGUgQ29tIEluYy4xJDAiBgNVBAsMG0V4YW1wbGUgQ29tIEluYy4gU2lnbmluZyBD
|
||||
QTEkMCIGA1UEAwwbRXhhbXBsZSBDb20gSW5jLiBTaWduaW5nIENBMB4XDTE4MDUw
|
||||
NTE0MzcxNloXDTI4MDUwMjE0MzcxNlowTTELMAkGA1UEBhMCREUxDTALBgNVBAcT
|
||||
BFRlc3QxDzANBgNVBAoTBmNsaWVudDEPMA0GA1UECxMGY2xpZW50MQ0wCwYDVQQD
|
||||
EwRraXJrMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAt7iBnBLbkmCK
|
||||
MEkc9meRsLmtrYeKKbkPL/CNogjP5fhIH5vSWd2+vSzgENAXtaHkhLrDiqi6vnny
|
||||
+r0KaluCsuYGZkisMMcPku3sODGtHakuWts4YYLqHtZWvsR4F8ioHJ1E+gdG+ACj
|
||||
df4MvWR+MkG5tswceqwfltpZti0xzUOTCowFdtZ6NaCoWPMgmg85T3hjWGe7SSSI
|
||||
gJDAWpJAETCb4RIKrSS26dlESdgU6zj4QowEV+/gKdLKO9pVo5mOKKuDNYLMzN6m
|
||||
1Q7abUQFeTAgIq6MX9YSJ40Qj7fWWq2OB/hJNTHN9LfTra9/ZMKPt5ecyBCTRpr+
|
||||
KmXlMEg+BwIDAQABo4HhMIHeMA4GA1UdDwEB/wQEAwIFoDAJBgNVHRMEAjAAMB0G
|
||||
A1UdJQQWMBQGCCsGAQUFBwMBBggrBgEFBQcDAjAdBgNVHQ4EFgQUOXz2tftJLgWX
|
||||
+hwbtJmItC0nJ8cwHwYDVR0jBBgwFoAUlHfikzELP7bny+WOakSkxOMEweAwYgYD
|
||||
VR0fBFswWTBXoFWgU4ZRaHR0cHM6Ly9yYXcuZ2l0aHVidXNlcmNvbnRlbnQuY29t
|
||||
L2Zsb3JhZ3VubmNvbS91bml0dGVzdC1hc3NldHMvbWFzdGVyL3Jldm9rZWQuY3Js
|
||||
MA0GCSqGSIb3DQEBCwUAA4IBAQAORNkM6q4j1ELFStU3CVI0AJIepZQ4JoBPLOUN
|
||||
K0tvnnzRuTEM57kaydg2PmbG1YUY6XS3S/IFyUZic95rPMxUUL8gGGCs1lJLq3i9
|
||||
Kt7aN0oyrnL00N2h8EDgi1WFjTYF0l/L52zKrxIOc7fAo1M0HLOHiPUq21A6hCrS
|
||||
VsBOeXB8GBgpKIqMLtx0wYDIwK3ItadGZ8B/rwH8rimMZHSSXvjd2RUQtaEHw5yj
|
||||
7zSE+0CogoMWuBjiSWl5WzQ0RWHnYQVunzuCnMZVRTk04yO4L2ctPWqlRVUlXM7A
|
||||
y/YZiBL/k1uu28QVRcP1XzH63XE4MAQMcShvTbAZAoSWAJkV
|
||||
-----END CERTIFICATE-----
|
9
src/test/resources/log4j2.properties
Normal file
9
src/test/resources/log4j2.properties
Normal file
@ -0,0 +1,9 @@
|
||||
status = error
|
||||
|
||||
appender.console.type = Console
|
||||
appender.console.name = console
|
||||
appender.console.layout.type = PatternLayout
|
||||
appender.console.layout.pattern = [%d{ISO8601}][%-5p][%-25c{1.}] %marker%m%n
|
||||
|
||||
rootLogger.level = info
|
||||
rootLogger.appenderRef.console.ref = console
|
BIN
src/test/resources/node-0-keystore.jks
Normal file
BIN
src/test/resources/node-0-keystore.jks
Normal file
Binary file not shown.
BIN
src/test/resources/node-0-keystore.p12
Normal file
BIN
src/test/resources/node-0-keystore.p12
Normal file
Binary file not shown.
88
src/test/resources/node-0.crt.pem
Normal file
88
src/test/resources/node-0.crt.pem
Normal file
@ -0,0 +1,88 @@
|
||||
Bag Attributes
|
||||
friendlyName: node-0
|
||||
localKeyID: 54 69 6D 65 20 31 35 32 35 35 33 31 30 33 30 31 36 38
|
||||
subject=/C=DE/L=Test/O=Test/OU=SSL/CN=node-0.example.com
|
||||
issuer=/DC=com/DC=example/O=Example Com Inc./OU=Example Com Inc. Signing CA/CN=Example Com Inc. Signing CA
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIIEgjCCA2qgAwIBAgIBATANBgkqhkiG9w0BAQsFADCBlTETMBEGCgmSJomT8ixk
|
||||
ARkWA2NvbTEXMBUGCgmSJomT8ixkARkWB2V4YW1wbGUxGTAXBgNVBAoMEEV4YW1w
|
||||
bGUgQ29tIEluYy4xJDAiBgNVBAsMG0V4YW1wbGUgQ29tIEluYy4gU2lnbmluZyBD
|
||||
QTEkMCIGA1UEAwwbRXhhbXBsZSBDb20gSW5jLiBTaWduaW5nIENBMB4XDTE4MDUw
|
||||
NTE0MzcwOVoXDTI4MDUwMjE0MzcwOVowVjELMAkGA1UEBhMCREUxDTALBgNVBAcT
|
||||
BFRlc3QxDTALBgNVBAoTBFRlc3QxDDAKBgNVBAsTA1NTTDEbMBkGA1UEAxMSbm9k
|
||||
ZS0wLmV4YW1wbGUuY29tMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA
|
||||
h5j6Dy0HqaP5MZe+KLkby42pUJn7OaQfZ7AYHJXs8XQ0aB+3eHfl57ubGDlsbxZc
|
||||
9s88LuhPo1Y3Frgj7SbH/KVeD0nc04uSWDvhFlxbL27c+TopPg75YTC8KcXy4mK+
|
||||
Bt1od28yxno6z18XroOoqBEf7086MY7MyDnduuLp/B1nwGijYM32k+KP9HJbRu9J
|
||||
MMt16GQYmbQtGJEqo5E8WAP/doTiH1f/cASSSoaiAR4Lzjhjbf6BEvtEQK51BFvq
|
||||
hG/qN229joyiOOexiLZb/bCdRdGebOOpOb9uBjqI1FlVc4TgIfyCKm/QATinZMLC
|
||||
cSl6NcUTFgcJkUxZn9DaEwIDAQABo4IBGTCCARUwDgYDVR0PAQH/BAQDAgWgMAkG
|
||||
A1UdEwQCMAAwHQYDVR0lBBYwFAYIKwYBBQUHAwEGCCsGAQUFBwMCMB0GA1UdDgQW
|
||||
BBR8XDrqpmWsEGpmnfP3sIdFTOZ7XDAfBgNVHSMEGDAWgBSUd+KTMQs/tufL5Y5q
|
||||
RKTE4wTB4DBiBgNVHR8EWzBZMFegVaBThlFodHRwczovL3Jhdy5naXRodWJ1c2Vy
|
||||
Y29udGVudC5jb20vZmxvcmFndW5uY29tL3VuaXR0ZXN0LWFzc2V0cy9tYXN0ZXIv
|
||||
cmV2b2tlZC5jcmwwNQYDVR0RBC4wLIISbm9kZS0wLmV4YW1wbGUuY29tgglsb2Nh
|
||||
bGhvc3SHBH8AAAGIBSoDBAUFMA0GCSqGSIb3DQEBCwUAA4IBAQBvrw8OxZfhRb6N
|
||||
JtKTUN6L4Tof/PxrE6onKzNeB7H/YrWXx+ZN4eg4STLNY3jwV5sop8YqF9nF2QA/
|
||||
+iC/xH6KA74qLD8t/epwOhkMt+w9q+N/j8KAesRyBOFiMKLgtQy/J2KvvT7hx2wY
|
||||
NujerGbWW08UJgRohvbm0Ekm2FHx/yt/4jt1uNoEBgg1MI7dF99/M4sMm0pLgKab
|
||||
5mn2PNsmQzF4FMPQ5vilmg4/sHe60ntR6YsfFxmkgLrEEiERs/DjUPTgSVMMPRmv
|
||||
Cc+2hudY6sdLyrHV+NfGXqCcc18+ImpTVQ6QvngN/L9ZneXgooasFUAbs2Qgvl1+
|
||||
aMsb6ZpV
|
||||
-----END CERTIFICATE-----
|
||||
Bag Attributes
|
||||
friendlyName: CN=Example Com Inc. Signing CA,OU=Example Com Inc. Signing CA,O=Example Com Inc.,DC=example,DC=com
|
||||
subject=/DC=com/DC=example/O=Example Com Inc./OU=Example Com Inc. Signing CA/CN=Example Com Inc. Signing CA
|
||||
issuer=/DC=com/DC=example/O=Example Com Inc./OU=Example Com Inc. Root CA/CN=Example Com Inc. Root CA
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIIEBzCCAu+gAwIBAgIBAjANBgkqhkiG9w0BAQsFADCBjzETMBEGCgmSJomT8ixk
|
||||
ARkWA2NvbTEXMBUGCgmSJomT8ixkARkWB2V4YW1wbGUxGTAXBgNVBAoMEEV4YW1w
|
||||
bGUgQ29tIEluYy4xITAfBgNVBAsMGEV4YW1wbGUgQ29tIEluYy4gUm9vdCBDQTEh
|
||||
MB8GA1UEAwwYRXhhbXBsZSBDb20gSW5jLiBSb290IENBMB4XDTE4MDUwNTE0Mzcw
|
||||
OFoXDTI4MDUwNDE0MzcwOFowgZUxEzARBgoJkiaJk/IsZAEZFgNjb20xFzAVBgoJ
|
||||
kiaJk/IsZAEZFgdleGFtcGxlMRkwFwYDVQQKDBBFeGFtcGxlIENvbSBJbmMuMSQw
|
||||
IgYDVQQLDBtFeGFtcGxlIENvbSBJbmMuIFNpZ25pbmcgQ0ExJDAiBgNVBAMMG0V4
|
||||
YW1wbGUgQ29tIEluYy4gU2lnbmluZyBDQTCCASIwDQYJKoZIhvcNAQEBBQADggEP
|
||||
ADCCAQoCggEBANWsMh2EWiqH2eZmaiHreWG4NlhLZGcUbwzRIZT0HmeeBolQygGq
|
||||
cJE1MpzCMYdezjTRaws/FVA2dkrtcox2xGT6YG7sKqr+4VlIt3Pd0Sah/5dEdRJv
|
||||
RsN2mj8V8xNUZdduD6NnrIGW/wAoF4isDNJ3QlGFhPM0f0Of5TVFIyholgrevNLT
|
||||
7D5rdUupIW192zQbOOuOxOmeXkunl8u35wq/VI/ZyJ4/mutCLR5sqd6/kOSDKQTU
|
||||
gQ+xIrs7LiuF1xZbCtRT3/PWnnD/GJulUsuJ0xOeEHkQaJuwRwYzqFkyVrEea2Wf
|
||||
U6XmSRZK9L0q5jy8TpCgzULlxb92POZd9ssCAwEAAaNmMGQwDgYDVR0PAQH/BAQD
|
||||
AgEGMBIGA1UdEwEB/wQIMAYBAf8CAQAwHQYDVR0OBBYEFJR34pMxCz+258vljmpE
|
||||
pMTjBMHgMB8GA1UdIwQYMBaAFFvHubBG7v/2QuZe5M8S+FdMajAVMA0GCSqGSIb3
|
||||
DQEBCwUAA4IBAQAY22ahhmYBdYUpPwQEyEUexyTWal29sbV+R44qVKM6FDEEd/8Q
|
||||
cFe5cnguDqmLBwHDLey4eSsAHI5tBUtslPJMqobWbwzswxdZ9WCOaLBWlvZdK4XU
|
||||
hkrq919wENMT6DVagNdpNRmDA47G4eRha4oD1ZO2YCFM0H8rEWDRSlaAHsGHLR59
|
||||
cJ5AgPqAVrEMfP6WzxXW2ThY6HD1LsE69T20/CfR8/k826BkcYVHKR/MQ/YZOWXb
|
||||
ccfb7D5o/oMop0E4+huCdF7ZDOt7/f5+BAfJZ08GCMLy5GSxU9gf8WiT/yNBYETS
|
||||
DAj+BAKhzlzvsaC3E2lAeyUepIMN0B8YHjqV
|
||||
-----END CERTIFICATE-----
|
||||
Bag Attributes
|
||||
friendlyName: CN=Example Com Inc. Root CA,OU=Example Com Inc. Root CA,O=Example Com Inc.,DC=example,DC=com
|
||||
subject=/DC=com/DC=example/O=Example Com Inc./OU=Example Com Inc. Root CA/CN=Example Com Inc. Root CA
|
||||
issuer=/DC=com/DC=example/O=Example Com Inc./OU=Example Com Inc. Root CA/CN=Example Com Inc. Root CA
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIID/jCCAuagAwIBAgIBATANBgkqhkiG9w0BAQsFADCBjzETMBEGCgmSJomT8ixk
|
||||
ARkWA2NvbTEXMBUGCgmSJomT8ixkARkWB2V4YW1wbGUxGTAXBgNVBAoMEEV4YW1w
|
||||
bGUgQ29tIEluYy4xITAfBgNVBAsMGEV4YW1wbGUgQ29tIEluYy4gUm9vdCBDQTEh
|
||||
MB8GA1UEAwwYRXhhbXBsZSBDb20gSW5jLiBSb290IENBMB4XDTE4MDUwNTE0Mzcw
|
||||
OFoXDTI4MDUwNDE0MzcwOFowgY8xEzARBgoJkiaJk/IsZAEZFgNjb20xFzAVBgoJ
|
||||
kiaJk/IsZAEZFgdleGFtcGxlMRkwFwYDVQQKDBBFeGFtcGxlIENvbSBJbmMuMSEw
|
||||
HwYDVQQLDBhFeGFtcGxlIENvbSBJbmMuIFJvb3QgQ0ExITAfBgNVBAMMGEV4YW1w
|
||||
bGUgQ29tIEluYy4gUm9vdCBDQTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoC
|
||||
ggEBAKYR4V2qdDbh2EMyNxQrXj4ucmA7b058s1zqiNwYQYRmQuZSp2hCmNcZuOa2
|
||||
4yt0fXHSDLYNDdVKgC0K9nm25Tyw/ZxScKdiGyYAmzK+0mhaT5gZsovpHMSc8tco
|
||||
10r6floxCkazLHaUgCAFv1uaNvIKK88KKHjXm5i0NPmx/4VW9IkJuYmi/ECdea5R
|
||||
76LAB21ih8kroVI0eRhHB1VzbYE9izneMJ5UBfLHF2iMR/RTilgs5IAkpdlj6guh
|
||||
CvSJsbOj0fmmcESUrPwKAEfhGVGfiE7b15Ho5ECQR6yn1CDiulpOLmthp7zcZ2jx
|
||||
BzevtTNeWzPom021hKG0nryoH5UCAwEAAaNjMGEwDgYDVR0PAQH/BAQDAgEGMA8G
|
||||
A1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFFvHubBG7v/2QuZe5M8S+FdMajAVMB8G
|
||||
A1UdIwQYMBaAFFvHubBG7v/2QuZe5M8S+FdMajAVMA0GCSqGSIb3DQEBCwUAA4IB
|
||||
AQAqW6C1XKJZH6GQydHFcUToLpm4YSypqZvD0Wf39dXNygih8szydtxtKEYjFivx
|
||||
O3oOa4v3J/52y4oNc2ksFyhXRAJhKEE58NHDGtb6eqUWWt9k2YrnsvD8k0hibjzt
|
||||
TmAWTYxYIMdF+4E0hfNUxkFmXXtThOoMhdcEqUYVXrVdrUOF9tVm49BCsQrrCkQw
|
||||
Q0vWvgTaik0sgsz4yaKI+iORt9qF74/Wf7KjLPpZR3OkkE1srfWhCszNzUB0CMD4
|
||||
34v9bIRWtjzvVQTCNNm9PaB2tMkQmeK+jOR7ywItO0+mij0vDSK3bWGqTrfgAXUn
|
||||
pTIIfrQcZ1vrDg0lYzVgQ1iT
|
||||
-----END CERTIFICATE-----
|
32
src/test/resources/node-0.key.pem
Normal file
32
src/test/resources/node-0.key.pem
Normal file
@ -0,0 +1,32 @@
|
||||
Bag Attributes
|
||||
friendlyName: node-0
|
||||
localKeyID: 54 69 6D 65 20 31 35 32 35 35 33 31 30 33 30 31 36 38
|
||||
Key Attributes: <No Attributes>
|
||||
-----BEGIN PRIVATE KEY-----
|
||||
MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQCHmPoPLQepo/kx
|
||||
l74ouRvLjalQmfs5pB9nsBgclezxdDRoH7d4d+Xnu5sYOWxvFlz2zzwu6E+jVjcW
|
||||
uCPtJsf8pV4PSdzTi5JYO+EWXFsvbtz5Oik+DvlhMLwpxfLiYr4G3Wh3bzLGejrP
|
||||
Xxeug6ioER/vTzoxjszIOd264un8HWfAaKNgzfaT4o/0cltG70kwy3XoZBiZtC0Y
|
||||
kSqjkTxYA/92hOIfV/9wBJJKhqIBHgvOOGNt/oES+0RArnUEW+qEb+o3bb2OjKI4
|
||||
57GItlv9sJ1F0Z5s46k5v24GOojUWVVzhOAh/IIqb9ABOKdkwsJxKXo1xRMWBwmR
|
||||
TFmf0NoTAgMBAAECggEARFPRrdQDCHiYGWVdbSfZ2biImRT+gw0wxg72F3F09Daa
|
||||
Md3JlerU7vCaNpq5CUE7lyLWMMzfVG8dU1V2xQnFvImX3BxcKj0qgUurIJlpWX2D
|
||||
3BJytdLV1yO3rVUSDwGyv8LR4V0nONxexiAkzsuJMSdv8Cb8K/zJNBv0nze4sFFd
|
||||
9Mb3rlHTm+gVXk6Qa+2j5hQkfwCQ0HQnyyXnFb99YZIBVMaBkn6oUkdbbwn2BdH+
|
||||
BxypwbDRgB/FoRhwMIah9CBLyuqZt26KiVKUnscemvuI/H3sH1H1veH2shpqWIeD
|
||||
JcNWs2IbS8kbGW7wDc5lrzRpTLSiVs6g7gIk7KRQAQKBgQD1uIT8+3QnWZpr1i+1
|
||||
coYJzgFWlghJVEj9SqVVFsC82aLDYaTd2S84anCYV9yDnO85se5qA7z+DE+jBF6S
|
||||
uy1u5iFsUOyrEXeSXK46Os0sg8V93ez4mcCfDamrXTq95QZxWVeIcWjB9mwzoCj9
|
||||
gLtFkd74tVHBgLhYqYE4x1a5yQKBgQCNRR9WG1rJanBw98e+LriBN7A97ti11j+W
|
||||
geh30PsEMtmFtBHztUoO1BeXSy5L6ZQADjDKDEhPDLzzFt6iN2RqynG3nKf7ZzBV
|
||||
YXTE0C0suzRFLE4B4IwOBLUa0I50teIOav67+o4t/KmCzx93T7M+YRLAATXuRQ1E
|
||||
R8UHLjwi+wKBgDd/b3n8CSYCFOCaRbhDn4aDYsX9qO12/e1HeMQZGXsN5LcgTK5W
|
||||
qVWipL+jyIhpX5a2W1TSd1Mh0LLO/9VANWjAzXe7Z1jT3x/NkwRP15tgP7DH+QfF
|
||||
Ij5KRbIQon3VRnk/ZofIpZJ5Z8LZP6jR9HooEiY2PbroqbpMvoTmcO4RAoGAIW/y
|
||||
8taWroXbB2IejQ1R7oPX21DlSmTjuCQXegSk5WGDyvnMJfsLBGd/DfhlhOJMfZbe
|
||||
RXSSyOMi9ga7u3mQ8xXnxKX3vLG35v2iPdNoXeYRgS3zaM5VWBwVIburfERwtSju
|
||||
EmBDtu7O0H9l2z+qFWG0pm2i7jq54Sd7oy92XHECgYEAs+ke0hR19C0bGPrcGr9U
|
||||
o5JSsMIcqESYtrkJ3YR62k+guzDc6t3KRIFDzLv9I4s4Dpssn46QKnMYW/KUBxv7
|
||||
pHkdZUtJagYPqeMIKPWR+UnwsmDDFJ9R/9U7Pf/9MMaQf7U64ffh3Qxdod/MEyI8
|
||||
uUwbul3fmSa4OAjHhSNPoSk=
|
||||
-----END PRIVATE KEY-----
|
BIN
src/test/resources/node-1-keystore.jks
Normal file
BIN
src/test/resources/node-1-keystore.jks
Normal file
Binary file not shown.
BIN
src/test/resources/node-1-keystore.p12
Normal file
BIN
src/test/resources/node-1-keystore.p12
Normal file
Binary file not shown.
BIN
src/test/resources/node-2-keystore.jks
Normal file
BIN
src/test/resources/node-2-keystore.jks
Normal file
Binary file not shown.
BIN
src/test/resources/node-2-keystore.p12
Normal file
BIN
src/test/resources/node-2-keystore.p12
Normal file
Binary file not shown.
BIN
src/test/resources/node-untspec5-keystore.p12
Normal file
BIN
src/test/resources/node-untspec5-keystore.p12
Normal file
Binary file not shown.
50
src/test/resources/pem/node-4.crt.pem
Normal file
50
src/test/resources/pem/node-4.crt.pem
Normal file
@ -0,0 +1,50 @@
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIIEcTCCA1mgAwIBAgIBBjANBgkqhkiG9w0BAQsFADCBlTETMBEGCgmSJomT8ixk
|
||||
ARkWA2NvbTEXMBUGCgmSJomT8ixkARkWB2V4YW1wbGUxGTAXBgNVBAoMEEV4YW1w
|
||||
bGUgQ29tIEluYy4xJDAiBgNVBAsMG0V4YW1wbGUgQ29tIEluYy4gU2lnbmluZyBD
|
||||
QTEkMCIGA1UEAwwbRXhhbXBsZSBDb20gSW5jLiBTaWduaW5nIENBMB4XDTE4MDUw
|
||||
NTE0MzcxNFoXDTI4MDUwMjE0MzcxNFowVjELMAkGA1UEBhMCREUxDTALBgNVBAcM
|
||||
BFRlc3QxDTALBgNVBAoMBFRlc3QxDDAKBgNVBAsMA1NTTDEbMBkGA1UEAwwSbm9k
|
||||
ZS00LmV4YW1wbGUuY29tMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA
|
||||
1EjVHY9yVLJjWN7J5OU2pkZyrttRO674kUtIn1Z8lCNTD31DIfOnJ6iLlUDZ0HhC
|
||||
9VumGOu4dc9HCSoxr4ck1GiDG0YrVdbZ6Hx4E3P+BY/RCxuQutGQeKi4BwgBm/bF
|
||||
5yg9ro0+ia2808RB9pWuvLClypPjhSJSMfG+UUJ8+23jRYdxYRboWPScacbuV634
|
||||
1AdOdlr7k7Rauw7nagehRi1k/DUEEOrSHbWqxyziiisJvU97Ey9FZhVya8st8srM
|
||||
wgNst+Lr16458V1pLRm097PoBYQMU9/MgMVXIz0Rmm1oqRMCPW5CPg6x5SXiKoCf
|
||||
9i1rwmt5abB58tYwxwJB8wIDAQABo4IBCDCCAQQwDgYDVR0PAQH/BAQDAgWgMAkG
|
||||
A1UdEwQCMAAwHQYDVR0lBBYwFAYIKwYBBQUHAwEGCCsGAQUFBwMCMB0GA1UdDgQW
|
||||
BBSuaYlnZZNkm6DUGh5K4zLBBYvQMTAfBgNVHSMEGDAWgBSUd+KTMQs/tufL5Y5q
|
||||
RKTE4wTB4DBiBgNVHR8EWzBZMFegVaBThlFodHRwczovL3Jhdy5naXRodWJ1c2Vy
|
||||
Y29udGVudC5jb20vZmxvcmFndW5uY29tL3VuaXR0ZXN0LWFzc2V0cy9tYXN0ZXIv
|
||||
cmV2b2tlZC5jcmwwJAYDVR0RBB0wG4ISbm9kZS00LmV4YW1wbGUuY29tiAUqAwQF
|
||||
BTANBgkqhkiG9w0BAQsFAAOCAQEAlCP1gK4DkG5VwPAY68BeifMSmSFai/JOOVSA
|
||||
URk7UiQ+nNkwo7Wuvf60aXqN+K440D3fvW3Bzk7+EnnKQFNXm4jief3ndM4Hvra0
|
||||
WKh979iWfrBY2LUqWhpW9zsIEx6PQGJIBlAfNiaQSW+gU05DQ8sxcfOgPPou94XT
|
||||
xrioFBg42JDMDLhiNhyLcMgMEwmdyfNw+N28HLrsoEJ223H9DWwfse1j/IgOKA8h
|
||||
5/PWNWUE1OFUflWov9wmlMVH4RUDovJGjvzFqZ7e+mH5gALp3CNtIcwl8u5jT3Y7
|
||||
206hdGScJoTWorKv5ujyhrGY/2Vp7AzY3pHHuP74HZL0HHvp4w==
|
||||
-----END CERTIFICATE-----
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIIEBzCCAu+gAwIBAgIBAjANBgkqhkiG9w0BAQsFADCBjzETMBEGCgmSJomT8ixk
|
||||
ARkWA2NvbTEXMBUGCgmSJomT8ixkARkWB2V4YW1wbGUxGTAXBgNVBAoMEEV4YW1w
|
||||
bGUgQ29tIEluYy4xITAfBgNVBAsMGEV4YW1wbGUgQ29tIEluYy4gUm9vdCBDQTEh
|
||||
MB8GA1UEAwwYRXhhbXBsZSBDb20gSW5jLiBSb290IENBMB4XDTE4MDUwNTE0Mzcw
|
||||
OFoXDTI4MDUwNDE0MzcwOFowgZUxEzARBgoJkiaJk/IsZAEZFgNjb20xFzAVBgoJ
|
||||
kiaJk/IsZAEZFgdleGFtcGxlMRkwFwYDVQQKDBBFeGFtcGxlIENvbSBJbmMuMSQw
|
||||
IgYDVQQLDBtFeGFtcGxlIENvbSBJbmMuIFNpZ25pbmcgQ0ExJDAiBgNVBAMMG0V4
|
||||
YW1wbGUgQ29tIEluYy4gU2lnbmluZyBDQTCCASIwDQYJKoZIhvcNAQEBBQADggEP
|
||||
ADCCAQoCggEBANWsMh2EWiqH2eZmaiHreWG4NlhLZGcUbwzRIZT0HmeeBolQygGq
|
||||
cJE1MpzCMYdezjTRaws/FVA2dkrtcox2xGT6YG7sKqr+4VlIt3Pd0Sah/5dEdRJv
|
||||
RsN2mj8V8xNUZdduD6NnrIGW/wAoF4isDNJ3QlGFhPM0f0Of5TVFIyholgrevNLT
|
||||
7D5rdUupIW192zQbOOuOxOmeXkunl8u35wq/VI/ZyJ4/mutCLR5sqd6/kOSDKQTU
|
||||
gQ+xIrs7LiuF1xZbCtRT3/PWnnD/GJulUsuJ0xOeEHkQaJuwRwYzqFkyVrEea2Wf
|
||||
U6XmSRZK9L0q5jy8TpCgzULlxb92POZd9ssCAwEAAaNmMGQwDgYDVR0PAQH/BAQD
|
||||
AgEGMBIGA1UdEwEB/wQIMAYBAf8CAQAwHQYDVR0OBBYEFJR34pMxCz+258vljmpE
|
||||
pMTjBMHgMB8GA1UdIwQYMBaAFFvHubBG7v/2QuZe5M8S+FdMajAVMA0GCSqGSIb3
|
||||
DQEBCwUAA4IBAQAY22ahhmYBdYUpPwQEyEUexyTWal29sbV+R44qVKM6FDEEd/8Q
|
||||
cFe5cnguDqmLBwHDLey4eSsAHI5tBUtslPJMqobWbwzswxdZ9WCOaLBWlvZdK4XU
|
||||
hkrq919wENMT6DVagNdpNRmDA47G4eRha4oD1ZO2YCFM0H8rEWDRSlaAHsGHLR59
|
||||
cJ5AgPqAVrEMfP6WzxXW2ThY6HD1LsE69T20/CfR8/k826BkcYVHKR/MQ/YZOWXb
|
||||
ccfb7D5o/oMop0E4+huCdF7ZDOt7/f5+BAfJZ08GCMLy5GSxU9gf8WiT/yNBYETS
|
||||
DAj+BAKhzlzvsaC3E2lAeyUepIMN0B8YHjqV
|
||||
-----END CERTIFICATE-----
|
29
src/test/resources/pem/node-4.key
Normal file
29
src/test/resources/pem/node-4.key
Normal file
@ -0,0 +1,29 @@
|
||||
-----BEGIN ENCRYPTED PRIVATE KEY-----
|
||||
MIIE6TAbBgkqhkiG9w0BBQMwDgQIAUztzPE48tECAggABIIEyMq0nF+vkpgA9vs1
|
||||
LrkGVinMLcl9kcnZ6sclulgUpar+agZ7yce3rtdFYrTFTRe9cLfOI/+nm3scsHaH
|
||||
kf0j6ZVAAyyXupivEV9jnFw6QjMql14EEEpzSjdUJ0e+yO8IIXO5q8dx7tFpiUUg
|
||||
WlSTaVqLS82OhuwD1VrDykR5XlmHp6COOhEJT7mVdvmNZFCwQ8VUg9k2hjAWB7vw
|
||||
PhJPNBnhI4Tr5Gb0/qFvpPcPkV5muxSkSJ2VA+YgHHgvZKpC/8E46uq7t2m45owM
|
||||
iCPOAVSy5nLigKcttP9Q8o7LY+l8iJdwkzTotu1gFjYfVp6+n1vHIKDf3kQz457v
|
||||
wCpSTa9p7PEreAo+SNUsigG23SsNIWP9/uUpPiy3G4X2kuNlxWdmqY8KSmblttGq
|
||||
6vmdIqpNwGOGDy6stfU9K7tgVdoEvRXfaNS1PwyF4V9ZVF9y6HEqmRcdpdjKIufW
|
||||
H49nF7AcNPGsEGCeX36ILnAGborvWstCOMl0WFkBg45sbLiT2Q9gAfSo37+Rfh11
|
||||
O+k6V8p5X30o6ftav3OR7j/dViKp/5j5dyAMjB/4tcDMkywHwm8Evyik8aWomQer
|
||||
1u6KPpE9hYn2YOY2cZouiC3d8KNLZJMdkcOlqYRs23N9QNNeFW3CvGGb0203+uWb
|
||||
185gjGHVX/lT8INlquPJyAt/3VT4EWTaSvIUS4pI75kDq/gzr56ak4/GgDEB4pK+
|
||||
yH7npm3U1p/jyoriJ3/1jMXkRp7HN42XSL2/m/Kzk5fX9JaNNO4ANHpuxMqV6MU/
|
||||
krWMa2bbC2shaVxZFOlx7LOUL7eHh7Vkk3T6/G28s57d9pW8qHBlwgNrYdegB8aC
|
||||
wF8SNmo75c4xHkpShx+FmGG/Q7h0VYzzr2j9XQTs7GspbEJo9ugTSVoAEVLI2avL
|
||||
sE6GS8AzKGTDKPNlzAru2+nzqQ4aG0RxYMpg9a+cPMQeoos7knjkkT1Twc1gcWQv
|
||||
r9O3vsY87pLKMSsstDtkZRONqxwPqbfDIMyV2JOF/x1EZ3+V1NMQErwGgl/tqlW7
|
||||
+PnW9JrIVFp+AEAzY666cta/RSJ2MNa7OrodIrgH5TtEwEy3qDH1YtVXUXG9A05W
|
||||
AGjLMFCQKEtrTrN4EotqXEXLmY54JF9WvT7hvtjYYhxkS+QtquujJb6En+Pte+Lm
|
||||
HN89dZToAY62LxhR4P1morg0jUwrAMssFa0YnMO3wN6ADQ8RSVT0cyOtGDM77DrI
|
||||
ps/K1tY+lQi9OV1pflP+Q6SukTWs+6dm8MpRcySPiKI+OZLVwy0MYub8UlCaO7PK
|
||||
QM+VcXVX3OyIKUe6BUiEE7KVnFh3V/I0KfNbYKInEM3gWPV06BWNSUo8TEXrxXWz
|
||||
xNRGG9r8RKf99cMzotox7G2YUSBJdI3SAqUse5ubdOW7TRsSMtdzMpSr62hambZ8
|
||||
BYLjtjYZm050vu3PHeYO6htCMj52m+w6IFrPGlmmKqwMsgnSC31Ns5zmMQP5Oeu9
|
||||
spLrr+oGsURF3DRVdAXGBY1OlvWCDLsCSp0kOF2Vpj4y7v9zPEEku8w6eGMbRKcc
|
||||
+Cg86Acrc1hOkDtzWtfpbDkkhXPkcYU8ic8c7gN3japCoH+RFLqoNhJow1vx6TW1
|
||||
9vCq0aTqdksLCNZ1Bw==
|
||||
-----END ENCRYPTED PRIVATE KEY-----
|
BIN
src/test/resources/pem/node-4.p12
Normal file
BIN
src/test/resources/pem/node-4.p12
Normal file
Binary file not shown.
83
src/test/resources/root-ca.crt
Normal file
83
src/test/resources/root-ca.crt
Normal file
@ -0,0 +1,83 @@
|
||||
Certificate:
|
||||
Data:
|
||||
Version: 3 (0x2)
|
||||
Serial Number: 1 (0x1)
|
||||
Signature Algorithm: sha256WithRSAEncryption
|
||||
Issuer: DC=com, DC=example, O=Example Com Inc., OU=Example Com Inc. Root CA, CN=Example Com Inc. Root CA
|
||||
Validity
|
||||
Not Before: May 5 14:37:08 2018 GMT
|
||||
Not After : May 4 14:37:08 2028 GMT
|
||||
Subject: DC=com, DC=example, O=Example Com Inc., OU=Example Com Inc. Root CA, CN=Example Com Inc. Root CA
|
||||
Subject Public Key Info:
|
||||
Public Key Algorithm: rsaEncryption
|
||||
Public-Key: (2048 bit)
|
||||
Modulus:
|
||||
00:a6:11:e1:5d:aa:74:36:e1:d8:43:32:37:14:2b:
|
||||
5e:3e:2e:72:60:3b:6f:4e:7c:b3:5c:ea:88:dc:18:
|
||||
41:84:66:42:e6:52:a7:68:42:98:d7:19:b8:e6:b6:
|
||||
e3:2b:74:7d:71:d2:0c:b6:0d:0d:d5:4a:80:2d:0a:
|
||||
f6:79:b6:e5:3c:b0:fd:9c:52:70:a7:62:1b:26:00:
|
||||
9b:32:be:d2:68:5a:4f:98:19:b2:8b:e9:1c:c4:9c:
|
||||
f2:d7:28:d7:4a:fa:7e:5a:31:0a:46:b3:2c:76:94:
|
||||
80:20:05:bf:5b:9a:36:f2:0a:2b:cf:0a:28:78:d7:
|
||||
9b:98:b4:34:f9:b1:ff:85:56:f4:89:09:b9:89:a2:
|
||||
fc:40:9d:79:ae:51:ef:a2:c0:07:6d:62:87:c9:2b:
|
||||
a1:52:34:79:18:47:07:55:73:6d:81:3d:8b:39:de:
|
||||
30:9e:54:05:f2:c7:17:68:8c:47:f4:53:8a:58:2c:
|
||||
e4:80:24:a5:d9:63:ea:0b:a1:0a:f4:89:b1:b3:a3:
|
||||
d1:f9:a6:70:44:94:ac:fc:0a:00:47:e1:19:51:9f:
|
||||
88:4e:db:d7:91:e8:e4:40:90:47:ac:a7:d4:20:e2:
|
||||
ba:5a:4e:2e:6b:61:a7:bc:dc:67:68:f1:07:37:af:
|
||||
b5:33:5e:5b:33:e8:9b:4d:b5:84:a1:b4:9e:bc:a8:
|
||||
1f:95
|
||||
Exponent: 65537 (0x10001)
|
||||
X509v3 extensions:
|
||||
X509v3 Key Usage: critical
|
||||
Certificate Sign, CRL Sign
|
||||
X509v3 Basic Constraints: critical
|
||||
CA:TRUE
|
||||
X509v3 Subject Key Identifier:
|
||||
5B:C7:B9:B0:46:EE:FF:F6:42:E6:5E:E4:CF:12:F8:57:4C:6A:30:15
|
||||
X509v3 Authority Key Identifier:
|
||||
keyid:5B:C7:B9:B0:46:EE:FF:F6:42:E6:5E:E4:CF:12:F8:57:4C:6A:30:15
|
||||
|
||||
Signature Algorithm: sha256WithRSAEncryption
|
||||
2a:5b:a0:b5:5c:a2:59:1f:a1:90:c9:d1:c5:71:44:e8:2e:99:
|
||||
b8:61:2c:a9:a9:9b:c3:d1:67:f7:f5:d5:cd:ca:08:a1:f2:cc:
|
||||
f2:76:dc:6d:28:46:23:16:2b:f1:3b:7a:0e:6b:8b:f7:27:fe:
|
||||
76:cb:8a:0d:73:69:2c:17:28:57:44:02:61:28:41:39:f0:d1:
|
||||
c3:1a:d6:fa:7a:a5:16:5a:df:64:d9:8a:e7:b2:f0:fc:93:48:
|
||||
62:6e:3c:ed:4e:60:16:4d:8c:58:20:c7:45:fb:81:34:85:f3:
|
||||
54:c6:41:66:5d:7b:53:84:ea:0c:85:d7:04:a9:46:15:5e:b5:
|
||||
5d:ad:43:85:f6:d5:66:e3:d0:42:b1:0a:eb:0a:44:30:43:4b:
|
||||
d6:be:04:da:8a:4d:2c:82:cc:f8:c9:a2:88:fa:23:91:b7:da:
|
||||
85:ef:8f:d6:7f:b2:a3:2c:fa:59:47:73:a4:90:4d:6c:ad:f5:
|
||||
a1:0a:cc:cd:cd:40:74:08:c0:f8:df:8b:fd:6c:84:56:b6:3c:
|
||||
ef:55:04:c2:34:d9:bd:3d:a0:76:b4:c9:10:99:e2:be:8c:e4:
|
||||
7b:cb:02:2d:3b:4f:a6:8a:3d:2f:0d:22:b7:6d:61:aa:4e:b7:
|
||||
e0:01:75:27:a5:32:08:7e:b4:1c:67:5b:eb:0e:0d:25:63:35:
|
||||
60:43:58:93
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIID/jCCAuagAwIBAgIBATANBgkqhkiG9w0BAQsFADCBjzETMBEGCgmSJomT8ixk
|
||||
ARkWA2NvbTEXMBUGCgmSJomT8ixkARkWB2V4YW1wbGUxGTAXBgNVBAoMEEV4YW1w
|
||||
bGUgQ29tIEluYy4xITAfBgNVBAsMGEV4YW1wbGUgQ29tIEluYy4gUm9vdCBDQTEh
|
||||
MB8GA1UEAwwYRXhhbXBsZSBDb20gSW5jLiBSb290IENBMB4XDTE4MDUwNTE0Mzcw
|
||||
OFoXDTI4MDUwNDE0MzcwOFowgY8xEzARBgoJkiaJk/IsZAEZFgNjb20xFzAVBgoJ
|
||||
kiaJk/IsZAEZFgdleGFtcGxlMRkwFwYDVQQKDBBFeGFtcGxlIENvbSBJbmMuMSEw
|
||||
HwYDVQQLDBhFeGFtcGxlIENvbSBJbmMuIFJvb3QgQ0ExITAfBgNVBAMMGEV4YW1w
|
||||
bGUgQ29tIEluYy4gUm9vdCBDQTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoC
|
||||
ggEBAKYR4V2qdDbh2EMyNxQrXj4ucmA7b058s1zqiNwYQYRmQuZSp2hCmNcZuOa2
|
||||
4yt0fXHSDLYNDdVKgC0K9nm25Tyw/ZxScKdiGyYAmzK+0mhaT5gZsovpHMSc8tco
|
||||
10r6floxCkazLHaUgCAFv1uaNvIKK88KKHjXm5i0NPmx/4VW9IkJuYmi/ECdea5R
|
||||
76LAB21ih8kroVI0eRhHB1VzbYE9izneMJ5UBfLHF2iMR/RTilgs5IAkpdlj6guh
|
||||
CvSJsbOj0fmmcESUrPwKAEfhGVGfiE7b15Ho5ECQR6yn1CDiulpOLmthp7zcZ2jx
|
||||
BzevtTNeWzPom021hKG0nryoH5UCAwEAAaNjMGEwDgYDVR0PAQH/BAQDAgEGMA8G
|
||||
A1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFFvHubBG7v/2QuZe5M8S+FdMajAVMB8G
|
||||
A1UdIwQYMBaAFFvHubBG7v/2QuZe5M8S+FdMajAVMA0GCSqGSIb3DQEBCwUAA4IB
|
||||
AQAqW6C1XKJZH6GQydHFcUToLpm4YSypqZvD0Wf39dXNygih8szydtxtKEYjFivx
|
||||
O3oOa4v3J/52y4oNc2ksFyhXRAJhKEE58NHDGtb6eqUWWt9k2YrnsvD8k0hibjzt
|
||||
TmAWTYxYIMdF+4E0hfNUxkFmXXtThOoMhdcEqUYVXrVdrUOF9tVm49BCsQrrCkQw
|
||||
Q0vWvgTaik0sgsz4yaKI+iORt9qF74/Wf7KjLPpZR3OkkE1srfWhCszNzUB0CMD4
|
||||
34v9bIRWtjzvVQTCNNm9PaB2tMkQmeK+jOR7ywItO0+mij0vDSK3bWGqTrfgAXUn
|
||||
pTIIfrQcZ1vrDg0lYzVgQ1iT
|
||||
-----END CERTIFICATE-----
|
24
src/test/resources/root-ca.pem
Normal file
24
src/test/resources/root-ca.pem
Normal file
@ -0,0 +1,24 @@
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIID/jCCAuagAwIBAgIBATANBgkqhkiG9w0BAQsFADCBjzETMBEGCgmSJomT8ixk
|
||||
ARkWA2NvbTEXMBUGCgmSJomT8ixkARkWB2V4YW1wbGUxGTAXBgNVBAoMEEV4YW1w
|
||||
bGUgQ29tIEluYy4xITAfBgNVBAsMGEV4YW1wbGUgQ29tIEluYy4gUm9vdCBDQTEh
|
||||
MB8GA1UEAwwYRXhhbXBsZSBDb20gSW5jLiBSb290IENBMB4XDTE4MDUwNTE0Mzcw
|
||||
OFoXDTI4MDUwNDE0MzcwOFowgY8xEzARBgoJkiaJk/IsZAEZFgNjb20xFzAVBgoJ
|
||||
kiaJk/IsZAEZFgdleGFtcGxlMRkwFwYDVQQKDBBFeGFtcGxlIENvbSBJbmMuMSEw
|
||||
HwYDVQQLDBhFeGFtcGxlIENvbSBJbmMuIFJvb3QgQ0ExITAfBgNVBAMMGEV4YW1w
|
||||
bGUgQ29tIEluYy4gUm9vdCBDQTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoC
|
||||
ggEBAKYR4V2qdDbh2EMyNxQrXj4ucmA7b058s1zqiNwYQYRmQuZSp2hCmNcZuOa2
|
||||
4yt0fXHSDLYNDdVKgC0K9nm25Tyw/ZxScKdiGyYAmzK+0mhaT5gZsovpHMSc8tco
|
||||
10r6floxCkazLHaUgCAFv1uaNvIKK88KKHjXm5i0NPmx/4VW9IkJuYmi/ECdea5R
|
||||
76LAB21ih8kroVI0eRhHB1VzbYE9izneMJ5UBfLHF2iMR/RTilgs5IAkpdlj6guh
|
||||
CvSJsbOj0fmmcESUrPwKAEfhGVGfiE7b15Ho5ECQR6yn1CDiulpOLmthp7zcZ2jx
|
||||
BzevtTNeWzPom021hKG0nryoH5UCAwEAAaNjMGEwDgYDVR0PAQH/BAQDAgEGMA8G
|
||||
A1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFFvHubBG7v/2QuZe5M8S+FdMajAVMB8G
|
||||
A1UdIwQYMBaAFFvHubBG7v/2QuZe5M8S+FdMajAVMA0GCSqGSIb3DQEBCwUAA4IB
|
||||
AQAqW6C1XKJZH6GQydHFcUToLpm4YSypqZvD0Wf39dXNygih8szydtxtKEYjFivx
|
||||
O3oOa4v3J/52y4oNc2ksFyhXRAJhKEE58NHDGtb6eqUWWt9k2YrnsvD8k0hibjzt
|
||||
TmAWTYxYIMdF+4E0hfNUxkFmXXtThOoMhdcEqUYVXrVdrUOF9tVm49BCsQrrCkQw
|
||||
Q0vWvgTaik0sgsz4yaKI+iORt9qF74/Wf7KjLPpZR3OkkE1srfWhCszNzUB0CMD4
|
||||
34v9bIRWtjzvVQTCNNm9PaB2tMkQmeK+jOR7ywItO0+mij0vDSK3bWGqTrfgAXUn
|
||||
pTIIfrQcZ1vrDg0lYzVgQ1iT
|
||||
-----END CERTIFICATE-----
|
BIN
src/test/resources/spock-keystore.jks
Normal file
BIN
src/test/resources/spock-keystore.jks
Normal file
Binary file not shown.
BIN
src/test/resources/spock-keystore.p12
Normal file
BIN
src/test/resources/spock-keystore.p12
Normal file
Binary file not shown.
30
src/test/resources/spock.crt.pem
Normal file
30
src/test/resources/spock.crt.pem
Normal file
@ -0,0 +1,30 @@
|
||||
Bag Attributes
|
||||
friendlyName: spock
|
||||
localKeyID: 54 69 6D 65 20 31 35 32 35 35 33 31 30 33 35 36 38 39
|
||||
subject=/C=DE/L=Test/O=client/OU=client/CN=spock
|
||||
issuer=/DC=com/DC=example/O=Example Com Inc./OU=Example Com Inc. Signing CA/CN=Example Com Inc. Signing CA
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIIEQTCCAymgAwIBAgIBBzANBgkqhkiG9w0BAQsFADCBlTETMBEGCgmSJomT8ixk
|
||||
ARkWA2NvbTEXMBUGCgmSJomT8ixkARkWB2V4YW1wbGUxGTAXBgNVBAoMEEV4YW1w
|
||||
bGUgQ29tIEluYy4xJDAiBgNVBAsMG0V4YW1wbGUgQ29tIEluYy4gU2lnbmluZyBD
|
||||
QTEkMCIGA1UEAwwbRXhhbXBsZSBDb20gSW5jLiBTaWduaW5nIENBMB4XDTE4MDUw
|
||||
NTE0MzcxNVoXDTI4MDUwMjE0MzcxNVowTjELMAkGA1UEBhMCREUxDTALBgNVBAcT
|
||||
BFRlc3QxDzANBgNVBAoTBmNsaWVudDEPMA0GA1UECxMGY2xpZW50MQ4wDAYDVQQD
|
||||
EwVzcG9jazCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAOtJCa7B8MJ3
|
||||
5PjnZ6OQbXtwt8bWHQgHiGKoIEqKGKRHzZZeTLvA/u++ihuHWQlSSeGF5flRiLW3
|
||||
5wZlSykcyabIC1rxV32SuJ/6ebxOHLnGhLagJ+ZS1+ehd9ksDu+y3bWQnJFLec6n
|
||||
4dThQAdNT6blqDcq5m/p7p/q/tJfNFLt6YMSrvxhopn5kC1tc5k5t6MbyLraXe7b
|
||||
u4ZaNNPsxho6ArJc5IktSwxgW1iqVxR2zC/5BghKFt3RKmZltVInX8IOZcWxSWvZ
|
||||
zdhBJonw/RGvBnvsXFW3NQ7v4yfAce4gWnZwvzKW6kXg1BZAh5vWcPnNzTkkl48n
|
||||
rMdfGP5tpF8CAwEAAaOB4TCB3jAOBgNVHQ8BAf8EBAMCBaAwCQYDVR0TBAIwADAd
|
||||
BgNVHSUEFjAUBggrBgEFBQcDAQYIKwYBBQUHAwIwHQYDVR0OBBYEFPUR3m9eT6lZ
|
||||
4rz7qj8hhxVe2VibMB8GA1UdIwQYMBaAFJR34pMxCz+258vljmpEpMTjBMHgMGIG
|
||||
A1UdHwRbMFkwV6BVoFOGUWh0dHBzOi8vcmF3LmdpdGh1YnVzZXJjb250ZW50LmNv
|
||||
bS9mbG9yYWd1bm5jb20vdW5pdHRlc3QtYXNzZXRzL21hc3Rlci9yZXZva2VkLmNy
|
||||
bDANBgkqhkiG9w0BAQsFAAOCAQEAL3COeHo9Dg1x78vhFmio0Nmfk46SmQz8n4vI
|
||||
qxWp0e+OoKdIZXpbVPV7SU4TEoXRG0tzOTd37kvDcMv95YUiYCuXbM23c7Y44JL2
|
||||
LHF0jIdUAuWFR/lchBB0rQiJshs6n0EqonAE/48zzSt7Vq6q+y8Q5sh4Eh1uyWMw
|
||||
vgH85r4+iRVQdnadPc3dv3clSkFhDgbAqyYPr27z9z92leqsyoP3Um4C3vX3bNXP
|
||||
/DxQE9YgT8E9AjAKoogyFGovG7RMZK9eh9FtnbwvGYGTBG6DE32l1xqrUfnMdSCs
|
||||
OzXIwhyhXaB/vafIZrOpFxZWRkyAsmsqlhTVHNf/QJy3CaEG4w==
|
||||
-----END CERTIFICATE-----
|
BIN
src/test/resources/truststore.jks
Normal file
BIN
src/test/resources/truststore.jks
Normal file
Binary file not shown.
BIN
src/test/resources/truststore_fail.jks
Normal file
BIN
src/test/resources/truststore_fail.jks
Normal file
Binary file not shown.
Loading…
Reference in New Issue
Block a user