[HLRC] Add support for get application privileges API (#35556)

This commits adds support for the Get Application Privileges
API to the HLRC

Relates: #29827
This commit is contained in:
Ioannis Kakavas 2018-11-21 16:38:17 +02:00 committed by GitHub
parent f0a3d32602
commit 25f83ae08c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
12 changed files with 970 additions and 6 deletions

View File

@ -38,6 +38,8 @@ import org.elasticsearch.client.security.DeleteRoleResponse;
import org.elasticsearch.client.security.DisableUserRequest;
import org.elasticsearch.client.security.EmptyResponse;
import org.elasticsearch.client.security.EnableUserRequest;
import org.elasticsearch.client.security.GetPrivilegesRequest;
import org.elasticsearch.client.security.GetPrivilegesResponse;
import org.elasticsearch.client.security.GetRoleMappingsRequest;
import org.elasticsearch.client.security.GetRoleMappingsResponse;
import org.elasticsearch.client.security.GetSslCertificatesRequest;
@ -505,10 +507,47 @@ public final class SecurityClient {
InvalidateTokenResponse::fromXContent, listener, emptySet());
}
/**
* Synchronously get application privilege(s).
* See <a href="https://www.elastic.co/guide/en/elasticsearch/reference/current/security-api-get-privileges.html">
* the docs</a> for more.
*
* @param request {@link GetPrivilegesRequest} with the application name and the privilege name.
* If no application name is provided, information about all privileges for all applications is retrieved.
* If no privilege name is provided, information about all privileges of the specified application is retrieved.
* @param options the request options (e.g. headers), use
* {@link RequestOptions#DEFAULT} if nothing needs to be customized
* @return the response from the get privileges call
* @throws IOException in case there is a problem sending the request or
* parsing back the response
*/
public GetPrivilegesResponse getPrivileges(final GetPrivilegesRequest request, final RequestOptions options) throws IOException {
return restHighLevelClient.performRequestAndParseEntity(request, SecurityRequestConverters::getPrivileges,
options, GetPrivilegesResponse::fromXContent, emptySet());
}
/**
* Asynchronously get application privilege(s).
* See <a href="https://www.elastic.co/guide/en/elasticsearch/reference/current/security-api-get-privileges.html">
* the docs</a> for more.
*
* @param request {@link GetPrivilegesRequest} with the application name and the privilege name.
* If no application name is provided, information about all privileges for all applications is retrieved.
* If no privilege name is provided, information about all privileges of the specified application is retrieved.
* @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 getPrivilegesAsync(final GetPrivilegesRequest request, final RequestOptions options,
final ActionListener<GetPrivilegesResponse> listener) {
restHighLevelClient.performRequestAsyncAndParseEntity(request, SecurityRequestConverters::getPrivileges,
options, GetPrivilegesResponse::fromXContent, listener, emptySet());
}
/**
* Removes application privilege(s)
* See <a href="https://www.elastic.co/guide/en/elasticsearch/reference/current/security-api-delete-privilege.html">
* the docs</a> for more.
*
* @param request the request with the application privilege to delete
* @param options the request options (e.g. headers), use {@link RequestOptions#DEFAULT} if nothing needs to be customized
* @return the response from the delete application privilege call
@ -523,12 +562,13 @@ public final class SecurityClient {
* Asynchronously removes an application privilege
* See <a href="https://www.elastic.co/guide/en/elasticsearch/reference/current/security-api-delete-privilege.html">
* the docs</a> for more.
* @param request the request with the application privilege to delete
* @param options the request options (e.g. headers), use {@link RequestOptions#DEFAULT} if nothing needs to be customized
*
* @param request the request with the application privilege to delete
* @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 deletePrivilegesAsync(DeletePrivilegesRequest request, RequestOptions options,
ActionListener<DeletePrivilegesResponse> listener) {
ActionListener<DeletePrivilegesResponse> listener) {
restHighLevelClient.performRequestAsyncAndParseEntity(request, SecurityRequestConverters::deletePrivileges, options,
DeletePrivilegesResponse::fromXContent, listener, singleton(404));
}

View File

@ -28,14 +28,15 @@ import org.elasticsearch.client.security.ClearRealmCacheRequest;
import org.elasticsearch.client.security.ClearRolesCacheRequest;
import org.elasticsearch.client.security.CreateTokenRequest;
import org.elasticsearch.client.security.DeletePrivilegesRequest;
import org.elasticsearch.client.security.GetPrivilegesRequest;
import org.elasticsearch.client.security.DeleteRoleMappingRequest;
import org.elasticsearch.client.security.DeleteRoleRequest;
import org.elasticsearch.client.security.InvalidateTokenRequest;
import org.elasticsearch.client.security.PutRoleMappingRequest;
import org.elasticsearch.client.security.HasPrivilegesRequest;
import org.elasticsearch.client.security.DisableUserRequest;
import org.elasticsearch.client.security.EnableUserRequest;
import org.elasticsearch.client.security.GetRoleMappingsRequest;
import org.elasticsearch.client.security.InvalidateTokenRequest;
import org.elasticsearch.client.security.PutRoleMappingRequest;
import org.elasticsearch.client.security.PutUserRequest;
import org.elasticsearch.client.security.SetUserEnabledRequest;
import org.elasticsearch.common.Strings;
@ -181,6 +182,15 @@ final class SecurityRequestConverters {
return request;
}
static Request getPrivileges(GetPrivilegesRequest getPrivilegesRequest) {
String endpoint = new RequestConverters.EndpointBuilder()
.addPathPartAsIs("_xpack/security/privilege")
.addPathPart(getPrivilegesRequest.getApplicationName())
.addCommaSeparatedPathParts(getPrivilegesRequest.getPrivilegeNames())
.build();
return new Request(HttpGet.METHOD_NAME, endpoint);
}
static Request deletePrivileges(DeletePrivilegesRequest deletePrivilegeRequest) {
String endpoint = new RequestConverters.EndpointBuilder()
.addPathPartAsIs("_xpack/security/privilege")

View File

@ -0,0 +1,93 @@
/*
* 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.Validatable;
import org.elasticsearch.common.Nullable;
import org.elasticsearch.common.Strings;
import org.elasticsearch.common.util.CollectionUtils;
import java.util.Arrays;
import java.util.Objects;
/**
* Request object to get application privilege(s)
*/
public final class GetPrivilegesRequest implements Validatable {
private final String applicationName;
private final String[] privilegeNames;
public GetPrivilegesRequest(@Nullable final String applicationName, @Nullable final String... privilegeNames) {
if ((CollectionUtils.isEmpty(privilegeNames) == false) && Strings.isNullOrEmpty(applicationName)) {
throw new IllegalArgumentException("privilege cannot be specified when application is missing");
}
this.applicationName = applicationName;
this.privilegeNames = privilegeNames;
}
/**
* Constructs a {@link GetPrivilegesRequest} to request all the privileges defined for all applications
*/
public static GetPrivilegesRequest getAllPrivileges() {
return new GetPrivilegesRequest(null);
}
/**
* Constructs a {@link GetPrivilegesRequest} to request all the privileges defined for the specified {@code applicationName}
*
* @param applicationName the name of the application for which the privileges are requested
*/
public static GetPrivilegesRequest getApplicationPrivileges(String applicationName) {
if (Strings.isNullOrEmpty(applicationName)) {
throw new IllegalArgumentException("application name is required");
}
return new GetPrivilegesRequest(applicationName);
}
/**
* @return the name of the application for which to return certain privileges
*/
public String getApplicationName() {
return applicationName;
}
/**
* @return an array of privilege names to return or null if all should be returned
*/
public String[] getPrivilegeNames() {
return privilegeNames;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
GetPrivilegesRequest that = (GetPrivilegesRequest) o;
return Objects.equals(applicationName, that.applicationName) &&
Arrays.equals(privilegeNames, that.privilegeNames);
}
@Override
public int hashCode() {
int result = Objects.hash(applicationName);
result = 31 * result + Arrays.hashCode(privilegeNames);
return result;
}
}

View File

@ -0,0 +1,77 @@
/*
* 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.user.privileges.ApplicationPrivilege;
import org.elasticsearch.common.xcontent.XContentParser;
import org.elasticsearch.common.xcontent.XContentParserUtils;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Objects;
import java.util.Set;
/**
* Get application privileges response
*/
public final class GetPrivilegesResponse {
private Set<ApplicationPrivilege> privileges;
public Set<ApplicationPrivilege> getPrivileges() {
return privileges;
}
public GetPrivilegesResponse(Collection<ApplicationPrivilege> privileges) {
this.privileges = Collections.unmodifiableSet(new HashSet<>(privileges));
}
public static GetPrivilegesResponse fromXContent(XContentParser parser) throws IOException {
XContentParserUtils.ensureExpectedToken(XContentParser.Token.START_OBJECT, parser.nextToken(), parser::getTokenLocation);
List<ApplicationPrivilege> privileges = new ArrayList<>();
XContentParser.Token token;
while ((token = parser.nextToken()) != null) {
if (token == XContentParser.Token.FIELD_NAME) {
XContentParserUtils.ensureExpectedToken(XContentParser.Token.START_OBJECT, parser.nextToken(), parser::getTokenLocation);
while (parser.nextToken() != XContentParser.Token.END_OBJECT) {
privileges.add(ApplicationPrivilege.PARSER.parse(parser, null));
}
}
}
return new GetPrivilegesResponse(new HashSet<>(privileges));
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
GetPrivilegesResponse that = (GetPrivilegesResponse) o;
return Objects.equals(privileges, that.privileges);
}
@Override
public int hashCode() {
return Objects.hash(privileges);
}
}

View File

@ -0,0 +1,174 @@
/*
* 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.user.privileges;
import org.elasticsearch.common.Nullable;
import org.elasticsearch.common.ParseField;
import org.elasticsearch.common.Strings;
import org.elasticsearch.common.xcontent.ConstructingObjectParser;
import org.elasticsearch.common.xcontent.ObjectParser;
import org.elasticsearch.common.xcontent.XContentParser;
import java.io.IOException;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.HashSet;
import java.util.Map;
import java.util.Objects;
import java.util.Set;
import static org.elasticsearch.common.xcontent.ConstructingObjectParser.constructorArg;
import static org.elasticsearch.common.xcontent.ConstructingObjectParser.optionalConstructorArg;
/**
* Represents an application specific privilege. The application name, privilege name,
* actions and metadata are completely managed by the client and can contain arbitrary
* string values.
*/
public final class ApplicationPrivilege {
private static final ParseField APPLICATION = new ParseField("application");
private static final ParseField NAME = new ParseField("name");
private static final ParseField ACTIONS = new ParseField("actions");
private static final ParseField METADATA = new ParseField("metadata");
private final String application;
private final String name;
private final Set<String> actions;
private final Map<String, Object> metadata;
public ApplicationPrivilege(String application, String name, Collection<String> actions, @Nullable Map<String, Object> metadata) {
if (Strings.isNullOrEmpty(application)) {
throw new IllegalArgumentException("application name must be provided");
} else {
this.application = application;
}
if (Strings.isNullOrEmpty(name)) {
throw new IllegalArgumentException("privilege name must be provided");
} else {
this.name = name;
}
if (actions == null || actions.isEmpty()) {
throw new IllegalArgumentException("actions must be provided");
} else {
this.actions = Collections.unmodifiableSet(new HashSet<>(actions));
}
if (metadata == null || metadata.isEmpty()) {
this.metadata = Collections.emptyMap();
} else {
this.metadata = Collections.unmodifiableMap(metadata);
}
}
public String getApplication() {
return application;
}
public String getName() {
return name;
}
public Set<String> getActions() {
return actions;
}
public Map<String, Object> getMetadata() {
return metadata;
}
@SuppressWarnings("unchecked")
public static final ConstructingObjectParser<ApplicationPrivilege, String> PARSER = new ConstructingObjectParser<>(
"application_privilege",
true, args -> new ApplicationPrivilege((String) args[0], (String) args[1], (Collection<String>) args[2],
(Map<String, Object>) args[3]));
static {
PARSER.declareString(constructorArg(), APPLICATION);
PARSER.declareString(constructorArg(), NAME);
PARSER.declareStringArray(constructorArg(), ACTIONS);
PARSER.declareField(optionalConstructorArg(), XContentParser::map, ApplicationPrivilege.METADATA, ObjectParser.ValueType.OBJECT);
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
ApplicationPrivilege that = (ApplicationPrivilege) o;
return Objects.equals(application, that.application) &&
Objects.equals(name, that.name) &&
Objects.equals(actions, that.actions) &&
Objects.equals(metadata, that.metadata);
}
@Override
public int hashCode() {
return Objects.hash(application, name, actions, metadata);
}
static ApplicationPrivilege fromXContent(XContentParser parser) throws IOException {
return PARSER.parse(parser, null);
}
public static Builder builder() {
return new Builder();
}
public static final class Builder {
private String applicationName = null;
private String privilegeName = null;
private Collection<String> actions = null;
private Map<String, Object> metadata = null;
private Builder() {
}
public Builder application(String applicationName) {
this.applicationName = Objects.requireNonNull(applicationName, "application name must be provided");
return this;
}
public Builder privilege(String privilegeName) {
this.privilegeName = Objects.requireNonNull(privilegeName, "privilege name must be provided");
return this;
}
public Builder actions(String... actions) {
this.actions = Arrays.asList(Objects.requireNonNull(actions));
return this;
}
public Builder actions(Collection<String> actions) {
this.actions = Objects.requireNonNull(actions);
return this;
}
public Builder metadata(Map<String, Object> metadata) {
this.metadata = metadata;
return this;
}
public ApplicationPrivilege build() {
return new ApplicationPrivilege(applicationName, privilegeName, actions, metadata);
}
}
}

View File

@ -29,6 +29,7 @@ import org.elasticsearch.client.security.DeleteRoleMappingRequest;
import org.elasticsearch.client.security.DeleteRoleRequest;
import org.elasticsearch.client.security.DisableUserRequest;
import org.elasticsearch.client.security.EnableUserRequest;
import org.elasticsearch.client.security.GetPrivilegesRequest;
import org.elasticsearch.client.security.GetRoleMappingsRequest;
import org.elasticsearch.client.security.ChangePasswordRequest;
import org.elasticsearch.client.security.PutRoleMappingRequest;
@ -243,6 +244,50 @@ public class SecurityRequestConvertersTests extends ESTestCase {
assertToXContentBody(createTokenRequest, request.getEntity());
}
public void testGetApplicationPrivilege() throws Exception {
final String application = randomAlphaOfLength(6);
final String privilege = randomAlphaOfLength(4);
GetPrivilegesRequest getPrivilegesRequest = new GetPrivilegesRequest(application, privilege);
Request request = SecurityRequestConverters.getPrivileges(getPrivilegesRequest);
assertEquals(HttpGet.METHOD_NAME, request.getMethod());
assertEquals("/_xpack/security/privilege/" + application + "/" + privilege, request.getEndpoint());
assertEquals(Collections.emptyMap(), request.getParameters());
assertNull(request.getEntity());
}
public void testGetAllApplicationPrivileges() throws Exception {
final String application = randomAlphaOfLength(6);
GetPrivilegesRequest getPrivilegesRequest = GetPrivilegesRequest.getApplicationPrivileges(application);
Request request = SecurityRequestConverters.getPrivileges(getPrivilegesRequest);
assertEquals(HttpGet.METHOD_NAME, request.getMethod());
assertEquals("/_xpack/security/privilege/" + application, request.getEndpoint());
assertEquals(Collections.emptyMap(), request.getParameters());
assertNull(request.getEntity());
}
public void testGetMultipleApplicationPrivileges() throws Exception {
final String application = randomAlphaOfLength(6);
final int numberOfPrivileges = randomIntBetween(1, 5);
final String[] privilegeNames =
randomArray(numberOfPrivileges, numberOfPrivileges, String[]::new, () -> randomAlphaOfLength(5));
GetPrivilegesRequest getPrivilegesRequest = new GetPrivilegesRequest(application, privilegeNames);
Request request = SecurityRequestConverters.getPrivileges(getPrivilegesRequest);
assertEquals(HttpGet.METHOD_NAME, request.getMethod());
assertEquals("/_xpack/security/privilege/" + application + "/" + Strings.arrayToCommaDelimitedString(privilegeNames),
request.getEndpoint());
assertEquals(Collections.emptyMap(), request.getParameters());
assertNull(request.getEntity());
}
public void testGetAllPrivileges() throws Exception {
GetPrivilegesRequest getPrivilegesRequest = GetPrivilegesRequest.getAllPrivileges();
Request request = SecurityRequestConverters.getPrivileges(getPrivilegesRequest);
assertEquals(HttpGet.METHOD_NAME, request.getMethod());
assertEquals("/_xpack/security/privilege", request.getEndpoint());
assertEquals(Collections.emptyMap(), request.getParameters());
assertNull(request.getEntity());
}
public void testDeletePrivileges() {
final String application = randomAlphaOfLengthBetween(1, 12);
final List<String> privileges = randomSubsetOf(randomIntBetween(1, 3), "read", "write", "all");

View File

@ -48,6 +48,8 @@ import org.elasticsearch.client.security.DisableUserRequest;
import org.elasticsearch.client.security.EmptyResponse;
import org.elasticsearch.client.security.EnableUserRequest;
import org.elasticsearch.client.security.ExpressionRoleMapping;
import org.elasticsearch.client.security.GetPrivilegesRequest;
import org.elasticsearch.client.security.GetPrivilegesResponse;
import org.elasticsearch.client.security.GetRoleMappingsRequest;
import org.elasticsearch.client.security.GetRoleMappingsResponse;
import org.elasticsearch.client.security.GetSslCertificatesResponse;
@ -65,6 +67,7 @@ import org.elasticsearch.client.security.support.expressiondsl.RoleMapperExpress
import org.elasticsearch.client.security.support.expressiondsl.expressions.AnyRoleMapperExpression;
import org.elasticsearch.client.security.support.expressiondsl.fields.FieldRoleMapperExpression;
import org.elasticsearch.client.security.user.User;
import org.elasticsearch.client.security.user.privileges.ApplicationPrivilege;
import org.elasticsearch.client.security.user.privileges.IndicesPrivileges;
import org.elasticsearch.common.Strings;
import org.elasticsearch.common.util.set.Sets;
@ -73,16 +76,19 @@ import org.elasticsearch.rest.RestStatus;
import org.hamcrest.Matchers;
import java.io.IOException;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
import static org.elasticsearch.common.xcontent.XContentFactory.jsonBuilder;
import static org.hamcrest.Matchers.contains;
import static org.hamcrest.Matchers.containsInAnyOrder;
import static org.hamcrest.Matchers.empty;
import static org.hamcrest.Matchers.emptyIterable;
import static org.hamcrest.Matchers.equalTo;
@ -475,7 +481,7 @@ public class SecurityDocumentationIT extends ESRestHighLevelClientTestCase {
}
{
HasPrivilegesRequest request = new HasPrivilegesRequest(Collections.singleton("monitor"),null,null);
HasPrivilegesRequest request = new HasPrivilegesRequest(Collections.singleton("monitor"), null, null);
// tag::has-privileges-execute-listener
ActionListener<HasPrivilegesResponse> listener = new ActionListener<HasPrivilegesResponse>() {
@ -987,6 +993,146 @@ public class SecurityDocumentationIT extends ESRestHighLevelClientTestCase {
}
}
public void testGetPrivileges() throws Exception {
final RestHighLevelClient client = highLevelClient();
final ApplicationPrivilege readTestappPrivilege =
new ApplicationPrivilege("testapp", "read", Arrays.asList("action:login", "data:read/*"), null);
final Map<String, Object> metadata = new HashMap<>();
metadata.put("key1", "value1");
final ApplicationPrivilege writeTestappPrivilege =
new ApplicationPrivilege("testapp", "write", Arrays.asList("action:login", "data:write/*"), metadata);
final ApplicationPrivilege allTestappPrivilege =
new ApplicationPrivilege("testapp", "all", Arrays.asList("action:login", "data:write/*", "manage:*"), null);
final Map<String, Object> metadata2 = new HashMap<>();
metadata2.put("key2", "value2");
final ApplicationPrivilege readTestapp2Privilege =
new ApplicationPrivilege("testapp2", "read", Arrays.asList("action:login", "data:read/*"), metadata2);
final ApplicationPrivilege writeTestapp2Privilege =
new ApplicationPrivilege("testapp2", "write", Arrays.asList("action:login", "data:write/*"), null);
final ApplicationPrivilege allTestapp2Privilege =
new ApplicationPrivilege("testapp2", "all", Arrays.asList("action:login", "data:write/*", "manage:*"), null);
{
//TODO Replace this with a call to PutPrivileges once it is implemented
final Request createPrivilegeRequest = new Request("POST", "/_xpack/security/privilege");
createPrivilegeRequest.setJsonEntity("{" +
" \"testapp\": {" +
" \"read\": {" +
" \"actions\": [ \"action:login\", \"data:read/*\" ]" +
" }," +
" \"write\": {" +
" \"actions\": [ \"action:login\", \"data:write/*\" ]," +
" \"metadata\": { \"key1\": \"value1\" }" +
" }," +
" \"all\": {" +
" \"actions\": [ \"action:login\", \"data:write/*\" , \"manage:*\"]" +
" }" +
" }," +
" \"testapp2\": {" +
" \"read\": {" +
" \"actions\": [ \"action:login\", \"data:read/*\" ]," +
" \"metadata\": { \"key2\": \"value2\" }" +
" }," +
" \"write\": {" +
" \"actions\": [ \"action:login\", \"data:write/*\" ]" +
" }," +
" \"all\": {" +
" \"actions\": [ \"action:login\", \"data:write/*\" , \"manage:*\"]" +
" }" +
" }" +
"}");
final Response createPrivilegeResponse = client.getLowLevelClient().performRequest(createPrivilegeRequest);
assertEquals(RestStatus.OK.getStatus(), createPrivilegeResponse.getStatusLine().getStatusCode());
}
{
//tag::get-privileges-request
GetPrivilegesRequest request = new GetPrivilegesRequest("testapp", "write");
//end::get-privileges-request
//tag::get-privileges-execute
GetPrivilegesResponse response = client.security().getPrivileges(request, RequestOptions.DEFAULT);
//end::get-privileges-execute
assertNotNull(response);
assertThat(response.getPrivileges().size(), equalTo(1));
assertThat(response.getPrivileges().contains(writeTestappPrivilege), equalTo(true));
}
{
//tag::get-all-application-privileges-request
GetPrivilegesRequest request = GetPrivilegesRequest.getApplicationPrivileges("testapp");
//end::get-all-application-privileges-request
GetPrivilegesResponse response = client.security().getPrivileges(request, RequestOptions.DEFAULT);
assertNotNull(response);
assertThat(response.getPrivileges().size(), equalTo(3));
final GetPrivilegesResponse exptectedResponse =
new GetPrivilegesResponse(Arrays.asList(readTestappPrivilege, writeTestappPrivilege, allTestappPrivilege));
assertThat(response, equalTo(exptectedResponse));
Set<ApplicationPrivilege> privileges = response.getPrivileges();
for (ApplicationPrivilege privilege : privileges) {
assertThat(privilege.getApplication(), equalTo("testapp"));
if (privilege.getName().equals("read")) {
assertThat(privilege.getActions(), containsInAnyOrder("action:login", "data:read/*"));
assertThat(privilege.getMetadata().isEmpty(), equalTo(true));
} else if (privilege.getName().equals("write")) {
assertThat(privilege.getActions(), containsInAnyOrder("action:login", "data:write/*"));
assertThat(privilege.getMetadata().isEmpty(), equalTo(false));
assertThat(privilege.getMetadata().get("key1"), equalTo("value1"));
} else if (privilege.getName().equals("all")) {
assertThat(privilege.getActions(), containsInAnyOrder("action:login", "data:write/*", "manage:*"));
assertThat(privilege.getMetadata().isEmpty(), equalTo(true));
}
}
}
{
//tag::get-all-privileges-request
GetPrivilegesRequest request = GetPrivilegesRequest.getAllPrivileges();
//end::get-all-privileges-request
GetPrivilegesResponse response = client.security().getPrivileges(request, RequestOptions.DEFAULT);
assertNotNull(response);
assertThat(response.getPrivileges().size(), equalTo(6));
final GetPrivilegesResponse exptectedResponse =
new GetPrivilegesResponse(Arrays.asList(readTestappPrivilege, writeTestappPrivilege, allTestappPrivilege,
readTestapp2Privilege, writeTestapp2Privilege, allTestapp2Privilege));
assertThat(response, equalTo(exptectedResponse));
}
{
GetPrivilegesRequest request = new GetPrivilegesRequest("testapp", "read");
//tag::get-privileges-execute-listener
ActionListener<GetPrivilegesResponse> listener = new ActionListener<GetPrivilegesResponse>() {
@Override
public void onResponse(GetPrivilegesResponse getPrivilegesResponse) {
// <1>
}
@Override
public void onFailure(Exception e) {
// <2>
}
};
//end::get-privileges-execute-listener
// Avoid unused variable warning
assertNotNull(listener);
// Replace the empty listener by a blocking listener in test
final PlainActionFuture<GetPrivilegesResponse> future = new PlainActionFuture<>();
listener = future;
//tag::get-privileges-execute-async
client.security().getPrivilegesAsync(request, RequestOptions.DEFAULT, listener); // <1>
//end::get-privileges-execute-async
final GetPrivilegesResponse response = future.get(30, TimeUnit.SECONDS);
assertNotNull(response);
assertThat(response.getPrivileges().size(), equalTo(1));
assertThat(response.getPrivileges().contains(readTestappPrivilege), equalTo(true));
}
}
public void testDeletePrivilege() throws Exception {
RestHighLevelClient client = highLevelClient();
{
@ -1061,3 +1207,4 @@ public class SecurityDocumentationIT extends ESRestHighLevelClientTestCase {
}
}
}

View File

@ -0,0 +1,65 @@
/*
* 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.test.ESTestCase;
import org.elasticsearch.test.EqualsHashCodeTestUtils;
import static org.hamcrest.Matchers.equalTo;
public class GetPrivilegesRequestTests extends ESTestCase {
public void testGetPrivilegesRequest() {
final String applicationName = randomAlphaOfLength(5);
final int numberOfPrivileges = randomIntBetween(0, 5);
final String[] privilegeNames = randomBoolean() ? null : randomArray(numberOfPrivileges, numberOfPrivileges, String[]::new,
() -> randomAlphaOfLength(5));
final GetPrivilegesRequest getPrivilegesRequest = new GetPrivilegesRequest(applicationName, privilegeNames);
assertThat(getPrivilegesRequest.getApplicationName(), equalTo(applicationName));
assertThat(getPrivilegesRequest.getPrivilegeNames(), equalTo(privilegeNames));
}
public void testPrivilegeWithoutApplication() {
IllegalArgumentException e = expectThrows(IllegalArgumentException.class, () -> {
new GetPrivilegesRequest(null, randomAlphaOfLength(5));
});
assertThat(e.getMessage(), equalTo("privilege cannot be specified when application is missing"));
}
public void testEqualsAndHashCode() {
final String applicationName = randomAlphaOfLength(5);
final int numberOfPrivileges = randomIntBetween(0, 5);
final String[] privilegeNames =
randomArray(numberOfPrivileges, numberOfPrivileges, String[]::new, () -> randomAlphaOfLength(5));
final GetPrivilegesRequest getPrivilegesRequest = new GetPrivilegesRequest(applicationName, privilegeNames);
final EqualsHashCodeTestUtils.MutateFunction<GetPrivilegesRequest> mutate = r -> {
if (randomBoolean()) {
final int numberOfNewPrivileges = randomIntBetween(1, 5);
final String[] newPrivilegeNames =
randomArray(numberOfNewPrivileges, numberOfNewPrivileges, String[]::new, () -> randomAlphaOfLength(5));
return new GetPrivilegesRequest(applicationName, newPrivilegeNames);
} else {
return GetPrivilegesRequest.getApplicationPrivileges(randomAlphaOfLength(6));
}
};
EqualsHashCodeTestUtils.checkEqualsAndHashCode(getPrivilegesRequest,
r -> new GetPrivilegesRequest(r.getApplicationName(), r.getPrivilegeNames()), mutate);
}
}

View File

@ -0,0 +1,154 @@
/*
* 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.user.privileges.ApplicationPrivilege;
import org.elasticsearch.common.xcontent.DeprecationHandler;
import org.elasticsearch.common.xcontent.NamedXContentRegistry;
import org.elasticsearch.common.xcontent.XContentType;
import org.elasticsearch.test.ESTestCase;
import org.elasticsearch.test.EqualsHashCodeTestUtils;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import static org.hamcrest.Matchers.equalTo;
public class GetPrivilegesResponseTests extends ESTestCase {
public void testFromXContent() throws IOException {
final String json = "{" +
" \"testapp\": {" +
" \"read\": {" +
" \"application\": \"testapp\"," +
" \"name\": \"read\"," +
" \"actions\": [ \"action:login\", \"data:read/*\" ]" +
" }," +
" \"write\": {" +
" \"application\": \"testapp\"," +
" \"name\": \"write\"," +
" \"actions\": [ \"action:login\", \"data:write/*\" ]," +
" \"metadata\": { \"key1\": \"value1\" }" +
" }," +
" \"all\": {" +
" \"application\": \"testapp\"," +
" \"name\": \"all\"," +
" \"actions\": [ \"action:login\", \"data:write/*\" , \"manage:*\"]" +
" }" +
" }," +
" \"testapp2\": {" +
" \"read\": {" +
" \"application\": \"testapp2\"," +
" \"name\": \"read\"," +
" \"actions\": [ \"action:login\", \"data:read/*\" ]," +
" \"metadata\": { \"key2\": \"value2\" }" +
" }," +
" \"write\": {" +
" \"application\": \"testapp2\"," +
" \"name\": \"write\"," +
" \"actions\": [ \"action:login\", \"data:write/*\" ]" +
" }," +
" \"all\": {" +
" \"application\": \"testapp2\"," +
" \"name\": \"all\"," +
" \"actions\": [ \"action:login\", \"data:write/*\" , \"manage:*\"]" +
" }" +
" }" +
"}";
final GetPrivilegesResponse response = GetPrivilegesResponse.fromXContent(XContentType.JSON.xContent().createParser(
new NamedXContentRegistry(Collections.emptyList()), new DeprecationHandler() {
@Override
public void usedDeprecatedName(String usedName, String modernName) {
}
@Override
public void usedDeprecatedField(String usedName, String replacedWith) {
}
}, json));
final ApplicationPrivilege readTestappPrivilege =
new ApplicationPrivilege("testapp", "read", Arrays.asList("action:login", "data:read/*"), null);
final Map<String, Object> metadata = new HashMap<>();
metadata.put("key1", "value1");
final ApplicationPrivilege writeTestappPrivilege =
new ApplicationPrivilege("testapp", "write", Arrays.asList("action:login", "data:write/*"), metadata);
final ApplicationPrivilege allTestappPrivilege =
new ApplicationPrivilege("testapp", "all", Arrays.asList("action:login", "data:write/*", "manage:*"), null);
final Map<String, Object> metadata2 = new HashMap<>();
metadata2.put("key2", "value2");
final ApplicationPrivilege readTestapp2Privilege =
new ApplicationPrivilege("testapp2", "read", Arrays.asList("action:login", "data:read/*"), metadata2);
final ApplicationPrivilege writeTestapp2Privilege =
new ApplicationPrivilege("testapp2", "write", Arrays.asList("action:login", "data:write/*"), null);
final ApplicationPrivilege allTestapp2Privilege =
new ApplicationPrivilege("testapp2", "all", Arrays.asList("action:login", "data:write/*", "manage:*"), null);
final GetPrivilegesResponse exptectedResponse =
new GetPrivilegesResponse(Arrays.asList(readTestappPrivilege, writeTestappPrivilege, allTestappPrivilege,
readTestapp2Privilege, writeTestapp2Privilege, allTestapp2Privilege));
assertThat(response, equalTo(exptectedResponse));
}
public void testEqualsHashCode() {
final List<ApplicationPrivilege> privileges = new ArrayList<>();
final List<ApplicationPrivilege> privileges2 = new ArrayList<>();
final Map<String, Object> metadata = new HashMap<>();
metadata.put("key1", "value1");
final ApplicationPrivilege writePrivilege =
new ApplicationPrivilege("testapp", "write", Arrays.asList("action:login", "data:write/*"),
metadata);
final ApplicationPrivilege readPrivilege =
new ApplicationPrivilege("testapp", "read", Arrays.asList("data:read/*", "action:login"),
metadata);
privileges.add(readPrivilege);
privileges.add(writePrivilege);
privileges2.add(writePrivilege);
privileges2.add(readPrivilege);
final GetPrivilegesResponse response = new GetPrivilegesResponse(privileges);
EqualsHashCodeTestUtils.checkEqualsAndHashCode(response, (original) -> {
return new GetPrivilegesResponse(original.getPrivileges());
});
EqualsHashCodeTestUtils.checkEqualsAndHashCode(response, (original) -> {
return new GetPrivilegesResponse(original.getPrivileges());
}, GetPrivilegesResponseTests::mutateTestItem);
}
private static GetPrivilegesResponse mutateTestItem(GetPrivilegesResponse original) {
if (randomBoolean()) {
Set<ApplicationPrivilege> originalPrivileges = original.getPrivileges();
List<ApplicationPrivilege> privileges = new ArrayList<>();
privileges.addAll(originalPrivileges);
privileges.add(new ApplicationPrivilege("testapp", "all", Arrays.asList("action:login", "data:read/*", "manage:*"), null));
return new GetPrivilegesResponse(privileges);
} else {
final List<ApplicationPrivilege> privileges = new ArrayList<>();
final ApplicationPrivilege privilege =
new ApplicationPrivilege("testapp", "all", Arrays.asList("action:login", "data:write/*", "manage:*"), null);
privileges.add(privilege);
return new GetPrivilegesResponse(privileges);
}
}
}

View File

@ -0,0 +1,110 @@
/*
* 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.user.privileges;
import org.elasticsearch.common.xcontent.DeprecationHandler;
import org.elasticsearch.common.xcontent.NamedXContentRegistry;
import org.elasticsearch.common.xcontent.XContentType;
import org.elasticsearch.test.ESTestCase;
import java.io.IOException;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import static org.hamcrest.Matchers.containsInAnyOrder;
import static org.hamcrest.Matchers.equalTo;
public class ApplicationPrivilegeTests extends ESTestCase {
public void testFromXContent() throws IOException {
String json =
" {" +
" \"application\": \"myapp\"," +
" \"name\": \"read\"," +
" \"actions\": [" +
" \"data:read/*\"," +
" \"action:login\"" +
" ],\n" +
" \"metadata\": {" +
" \"description\": \"Read access to myapp\"" +
" }" +
" }";
final ApplicationPrivilege privilege = ApplicationPrivilege.fromXContent(XContentType.JSON.xContent().createParser(
new NamedXContentRegistry(Collections.emptyList()), new DeprecationHandler() {
@Override
public void usedDeprecatedName(String usedName, String modernName) {
}
@Override
public void usedDeprecatedField(String usedName, String replacedWith) {
}
}, json));
final Map<String, Object> metadata = new HashMap<>();
metadata.put("description", "Read access to myapp");
final ApplicationPrivilege expectedPrivilege =
new ApplicationPrivilege("myapp", "read", Arrays.asList("data:read/*", "action:login"), metadata);
assertThat(privilege, equalTo(expectedPrivilege));
}
public void testEmptyApplicationName() {
final Map<String, Object> metadata = new HashMap<>();
metadata.put("description", "Read access to myapp");
final String applicationName = randomBoolean() ? null : "";
final IllegalArgumentException e = expectThrows(IllegalArgumentException.class, () ->
new ApplicationPrivilege(applicationName, "read", Arrays.asList("data:read/*", "action:login"), metadata));
assertThat(e.getMessage(), equalTo("application name must be provided"));
}
public void testEmptyPrivilegeName() {
final Map<String, Object> metadata = new HashMap<>();
metadata.put("description", "Read access to myapp");
final String privilegenName = randomBoolean() ? null : "";
final IllegalArgumentException e = expectThrows(IllegalArgumentException.class, () ->
new ApplicationPrivilege("myapp", privilegenName, Arrays.asList("data:read/*", "action:login"), metadata));
assertThat(e.getMessage(), equalTo("privilege name must be provided"));
}
public void testEmptyActions() {
final Map<String, Object> metadata = new HashMap<>();
metadata.put("description", "Read access to myapp");
final List<String> actions = randomBoolean() ? null : Collections.emptyList();
final IllegalArgumentException e = expectThrows(IllegalArgumentException.class, () ->
new ApplicationPrivilege("myapp", "read", actions, metadata));
assertThat(e.getMessage(), equalTo("actions must be provided"));
}
public void testBuilder() {
final Map<String, Object> metadata = new HashMap<>();
metadata.put("description", "Read access to myapp");
ApplicationPrivilege privilege = ApplicationPrivilege.builder()
.application("myapp")
.privilege("read")
.actions("data:read/*", "action:login")
.metadata(metadata)
.build();
assertThat(privilege.getApplication(), equalTo("myapp"));
assertThat(privilege.getName(), equalTo("read"));
assertThat(privilege.getActions(), containsInAnyOrder("data:read/*", "action:login"));
assertThat(privilege.getMetadata(), equalTo(metadata));
}
}

View File

@ -0,0 +1,47 @@
--
:api: get-privileges
:request: GetPrivilegesRequest
:respnse: GetPrivilegesResponse
--
[id="{upid}-{api}"]
=== Get Privileges API
[id="{upid}-{api}-request"]
==== Get Privileges Request
The +{request}+ supports getting privilege(s) for all or for specific applications.
===== Specific privilege of a specific application
["source","java",subs="attributes,callouts,macros"]
--------------------------------------------------
include-tagged::{doc-tests-file}[{api}-request]
--------------------------------------------------
===== All privileges of a specific application
["source","java",subs="attributes,callouts,macros"]
--------------------------------------------------
include-tagged::{doc-tests-file}[get-all-application-privileges-request]
--------------------------------------------------
===== All privileges of all applications
["source","java",subs="attributes,callouts,macros"]
--------------------------------------------------
include-tagged::{doc-tests-file}[get-all-privileges-request]
--------------------------------------------------
include::../execution.asciidoc[]
[id="{upid}-{api}-response"]
==== Get Privileges Response
The returned +{response}+ allows to get information about the retrieved privileges as follows.
["source","java",subs="attributes,callouts,macros"]
--------------------------------------------------
include-tagged::{doc-tests-file}[{api}-response]
--------------------------------------------------

View File

@ -375,6 +375,7 @@ The Java High Level REST Client supports the following Security APIs:
* <<java-rest-high-security-delete-role-mapping>>
* <<java-rest-high-security-create-token>>
* <<{upid}-invalidate-token>>
* <<{upid}-get-privileges>>
* <<{upid}-delete-privileges>>
include::security/put-user.asciidoc[]
@ -383,6 +384,7 @@ include::security/disable-user.asciidoc[]
include::security/change-password.asciidoc[]
include::security/delete-role.asciidoc[]
include::security/delete-privileges.asciidoc[]
include::security/get-privileges.asciidoc[]
include::security/clear-roles-cache.asciidoc[]
include::security/clear-realm-cache.asciidoc[]
include::security/authenticate.asciidoc[]