Skip to content

Commit

Permalink
Merge branch 'master' into settings-version
Browse files Browse the repository at this point in the history
* master:
  Do not update number of replicas on no indices (elastic#34481)
  Core: Remove two methods from AbstractComponent (elastic#34336)
  Use RoleRetrievalResult for better caching (elastic#34197)
  Revert "Search: Fix spelling mistake in Javadoc (elastic#34480)"
  Search: Fix spelling mistake in Javadoc (elastic#34480)
  Docs: improve formatting of Query String Query doc page (elastic#34432)
  Tests: Handle epoch date formatters edge cases (elastic#34437)
  Test: Fix running with external cluster
  Fix handling of empty keyword in terms aggregation (elastic#34457)
  [DOCS] Fix tag in SecurityDocumentationIT
  [Monitoring] Add additional necessary mappings for apm-server (elastic#34392)
  SCRIPTING: Move Aggregation Script Context to its own class (elastic#33820)
  MINOR: Remove Deadcode in  ExpressionTermSetQuery (elastic#34442)
  HLRC: Get SSL Certificates API (elastic#34135)
  • Loading branch information
jasontedor committed Oct 15, 2018
2 parents 60c15be + 55dee53 commit 59d0f3d
Show file tree
Hide file tree
Showing 63 changed files with 1,539 additions and 369 deletions.
8 changes: 8 additions & 0 deletions client/rest-high-level/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,8 @@ forbiddenApisMain {
addSignatureFiles 'http-signatures'
signaturesFiles += files('src/main/resources/forbidden/rest-high-level-signatures.txt')
}
File nodeCert = file("./testnode.crt")
File nodeTrustStore = file("./testnode.jks")

integTestRunner {
systemProperty 'tests.rest.cluster.username', System.getProperty('tests.rest.cluster.username', 'test_user')
Expand All @@ -85,11 +87,17 @@ integTestRunner {
integTestCluster {
setting 'xpack.license.self_generated.type', 'trial'
setting 'xpack.security.enabled', 'true'
// Truststore settings are not used since TLS is not enabled. Included for testing the get certificates API
setting 'xpack.ssl.certificate_authorities', 'testnode.crt'
setting 'xpack.security.transport.ssl.truststore.path', 'testnode.jks'
setting 'xpack.security.transport.ssl.truststore.password', 'testnode'
setupCommand 'setupDummyUser',
'bin/elasticsearch-users',
'useradd', System.getProperty('tests.rest.cluster.username', 'test_user'),
'-p', System.getProperty('tests.rest.cluster.password', 'test-password'),
'-r', 'superuser'
extraConfigFile nodeCert.name, nodeCert
extraConfigFile nodeTrustStore.name, nodeTrustStore
waitCondition = { node, ant ->
File tmpFile = new File(node.cwd, 'wait.success')
ant.get(src: "http://${node.httpUri()}/_cluster/health?wait_for_nodes=>=${numNodes}&wait_for_status=yellow",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,8 @@
import org.elasticsearch.action.ActionListener;
import org.elasticsearch.client.security.DisableUserRequest;
import org.elasticsearch.client.security.EnableUserRequest;
import org.elasticsearch.client.security.GetSslCertificatesRequest;
import org.elasticsearch.client.security.GetSslCertificatesResponse;
import org.elasticsearch.client.security.PutUserRequest;
import org.elasticsearch.client.security.PutUserResponse;
import org.elasticsearch.client.security.EmptyResponse;
Expand Down Expand Up @@ -133,6 +135,33 @@ public void disableUserAsync(DisableUserRequest request, RequestOptions options,
EmptyResponse::fromXContent, listener, emptySet());
}

/**
* Synchronously retrieve the X.509 certificates that are used to encrypt communications in an Elasticsearch cluster.
* See <a href="https://www.elastic.co/guide/en/elasticsearch/reference/current/security-api-ssl.html">
* the docs</a> for more.
*
* @param options the request options (e.g. headers), use {@link RequestOptions#DEFAULT} if nothing needs to be customized
* @return the response from the get certificates call
* @throws IOException in case there is a problem sending the request or parsing back the response
*/
public GetSslCertificatesResponse getSslCertificates(RequestOptions options) throws IOException {
return restHighLevelClient.performRequestAndParseEntity(GetSslCertificatesRequest.INSTANCE, GetSslCertificatesRequest::getRequest,
options, GetSslCertificatesResponse::fromXContent, emptySet());
}

/**
* Asynchronously retrieve the X.509 certificates that are used to encrypt communications in an Elasticsearch cluster.
* See <a href="https://www.elastic.co/guide/en/elasticsearch/reference/current/security-api-ssl.html">
* the docs</a> for more.
*
* @param options the request options (e.g. headers), use {@link RequestOptions#DEFAULT} if nothing needs to be customized
* @param listener the listener to be notified upon request completion
*/
public void getSslCertificatesAsync(RequestOptions options, ActionListener<GetSslCertificatesResponse> listener) {
restHighLevelClient.performRequestAsyncAndParseEntity(GetSslCertificatesRequest.INSTANCE, GetSslCertificatesRequest::getRequest,
options, GetSslCertificatesResponse::fromXContent, listener, emptySet());
}

/**
* Change the password of a user of a native realm or built-in user synchronously.
* See <a href="https://www.elastic.co/guide/en/elasticsearch/reference/current/security-api-change-password.html">
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
/*
* Licensed to Elasticsearch under one or more contributor
* license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright
* ownership. Elasticsearch licenses this file to you 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.
*/

package org.elasticsearch.client.security;

import org.apache.http.client.methods.HttpGet;
import org.elasticsearch.client.Request;
import org.elasticsearch.client.Validatable;
import org.elasticsearch.common.xcontent.ToXContentObject;
import org.elasticsearch.common.xcontent.XContentBuilder;

import java.io.IOException;

/**
* Request object to retrieve the X.509 certificates that are used to encrypt communications in an Elasticsearch cluster.
*/
public final class GetSslCertificatesRequest implements Validatable, ToXContentObject {

public static final GetSslCertificatesRequest INSTANCE = new GetSslCertificatesRequest();
private final Request request;

private GetSslCertificatesRequest() {
request = new Request(HttpGet.METHOD_NAME, "/_xpack/ssl/certificates");
}

public Request getRequest() {
return request;
}

public XContentBuilder toXContent(XContentBuilder builder, Params params) throws IOException {
return builder.startObject().endObject();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
/*
* Licensed to Elasticsearch under one or more contributor
* license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright
* ownership. Elasticsearch licenses this file to you 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.
*/

package org.elasticsearch.client.security;

import org.elasticsearch.client.security.support.CertificateInfo;
import org.elasticsearch.common.xcontent.XContentParser;
import org.elasticsearch.common.xcontent.XContentParserUtils;

import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;

/**
* Response object when retrieving the X.509 certificates that are used to encrypt communications in an Elasticsearch cluster.
* Returns a list of {@link CertificateInfo} objects describing each of the certificates.
*/
public final class GetSslCertificatesResponse {

private final List<CertificateInfo> certificates;

public GetSslCertificatesResponse(List<CertificateInfo> certificates) {
this.certificates = certificates;
}

@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
final GetSslCertificatesResponse that = (GetSslCertificatesResponse) o;
return Objects.equals(this.certificates, that.certificates);
}

@Override
public int hashCode() {
return Objects.hash(certificates);
}

public static GetSslCertificatesResponse fromXContent(XContentParser parser) throws IOException {
List<CertificateInfo> certificates = new ArrayList<>();
XContentParserUtils.ensureExpectedToken(XContentParser.Token.START_ARRAY, parser.nextToken(), parser::getTokenLocation);
while (parser.nextToken() != XContentParser.Token.END_ARRAY) {
certificates.add(CertificateInfo.PARSER.parse(parser, null));
}
return new GetSslCertificatesResponse(certificates);
}

public List<CertificateInfo> getCertificates() {
return certificates;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,133 @@
/*
* Licensed to Elasticsearch under one or more contributor
* license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright
* ownership. Elasticsearch licenses this file to you 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.
*/

package org.elasticsearch.client.security.support;

import org.elasticsearch.common.Nullable;
import org.elasticsearch.common.ParseField;
import org.elasticsearch.common.xcontent.ConstructingObjectParser;
import org.elasticsearch.common.xcontent.XContentParser;

import java.io.IOException;
import java.util.Objects;

import static org.elasticsearch.common.xcontent.ConstructingObjectParser.constructorArg;

/**
* Simple model of an X.509 certificate
*/
public final class CertificateInfo {
public static final ParseField PATH = new ParseField("path");
public static final ParseField FORMAT = new ParseField("format");
public static final ParseField ALIAS = new ParseField("alias");
public static final ParseField SUBJECT_DN = new ParseField("subject_dn");
public static final ParseField SERIAL_NUMBER = new ParseField("serial_number");
public static final ParseField HAS_PRIVATE_KEY = new ParseField("has_private_key");
public static final ParseField EXPIRY = new ParseField("expiry");

private final String path;
private final String format;
private final String alias;
private final String subjectDn;
private final String serialNumber;
private final boolean hasPrivateKey;
private final String expiry;

public CertificateInfo(String path, String format, @Nullable String alias, String subjectDn, String serialNumber, boolean hasPrivateKey,
String expiry) {
this.path = path;
this.format = format;
this.alias = alias;
this.subjectDn = subjectDn;
this.serialNumber = serialNumber;
this.hasPrivateKey = hasPrivateKey;
this.expiry = expiry;
}

public String getPath() {
return path;
}

public String getFormat() {
return format;
}

public String getAlias() {
return alias;
}

public String getSubjectDn() {
return subjectDn;
}

public String getSerialNumber() {
return serialNumber;
}

public boolean isHasPrivateKey() {
return hasPrivateKey;
}

public String getExpiry() {
return expiry;
}

@SuppressWarnings("unchecked")
public static final ConstructingObjectParser<CertificateInfo, Void> PARSER = new ConstructingObjectParser<>("certificate_info",
true, args -> new CertificateInfo((String) args[0], (String) args[1], (String) args[2], (String) args[3], (String) args[4],
(boolean) args[5], (String) args[6]));

static {
PARSER.declareString(constructorArg(), PATH);
PARSER.declareString(constructorArg(), FORMAT);
PARSER.declareStringOrNull(constructorArg(), ALIAS);
PARSER.declareString(constructorArg(), SUBJECT_DN);
PARSER.declareString(constructorArg(), SERIAL_NUMBER);
PARSER.declareBoolean(constructorArg(), HAS_PRIVATE_KEY);
PARSER.declareString(constructorArg(), EXPIRY);
}

@Override
public boolean equals(Object other) {
if (this == other) {
return true;
}
if (other == null || getClass() != other.getClass()) {
return false;
}

final CertificateInfo that = (CertificateInfo) other;
return this.path.equals(that.path)
&& this.format.equals(that.format)
&& this.hasPrivateKey == that.hasPrivateKey
&& Objects.equals(this.alias, that.alias)
&& this.serialNumber.equals(that.serialNumber)
&& this.subjectDn.equals(that.subjectDn)
&& this.expiry.equals(that.expiry);
}

@Override
public int hashCode() {
return Objects.hash(path, format, alias, subjectDn, serialNumber, hasPrivateKey, expiry);
}

public static CertificateInfo fromXContent(XContentParser parser) throws IOException {
return PARSER.parse(parser, null);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -721,10 +721,16 @@ public void testApiNamingConventions() throws Exception {
methods.containsKey(apiName.substring(0, apiName.length() - 6)));
assertThat(method.getReturnType(), equalTo(Void.TYPE));
assertEquals(0, method.getExceptionTypes().length);
assertEquals(3, method.getParameterTypes().length);
assertThat(method.getParameterTypes()[0].getSimpleName(), endsWith("Request"));
assertThat(method.getParameterTypes()[1], equalTo(RequestOptions.class));
assertThat(method.getParameterTypes()[2], equalTo(ActionListener.class));
if (apiName.equals("security.get_ssl_certificates_async")) {
assertEquals(2, method.getParameterTypes().length);
assertThat(method.getParameterTypes()[0], equalTo(RequestOptions.class));
assertThat(method.getParameterTypes()[1], equalTo(ActionListener.class));
} else {
assertEquals(3, method.getParameterTypes().length);
assertThat(method.getParameterTypes()[0].getSimpleName(), endsWith("Request"));
assertThat(method.getParameterTypes()[1], equalTo(RequestOptions.class));
assertThat(method.getParameterTypes()[2], equalTo(ActionListener.class));
}
} else {
//A few methods return a boolean rather than a response object
if (apiName.equals("ping") || apiName.contains("exist")) {
Expand All @@ -735,7 +741,7 @@ public void testApiNamingConventions() throws Exception {

assertEquals(1, method.getExceptionTypes().length);
//a few methods don't accept a request object as argument
if (apiName.equals("ping") || apiName.equals("info")) {
if (apiName.equals("ping") || apiName.equals("info") || apiName.equals("security.get_ssl_certificates")) {
assertEquals(1, method.getParameterTypes().length);
assertThat(method.getParameterTypes()[0], equalTo(RequestOptions.class));
} else {
Expand Down
Loading

0 comments on commit 59d0f3d

Please sign in to comment.