[HLRC] Add support for put privileges API (#35679)
This commit adds support for API to create or update application privileges in high-level rest client.
This commit is contained in:
parent
902d6f579a
commit
32c4f99238
|
@ -52,6 +52,8 @@ import org.elasticsearch.client.security.HasPrivilegesRequest;
|
||||||
import org.elasticsearch.client.security.HasPrivilegesResponse;
|
import org.elasticsearch.client.security.HasPrivilegesResponse;
|
||||||
import org.elasticsearch.client.security.InvalidateTokenRequest;
|
import org.elasticsearch.client.security.InvalidateTokenRequest;
|
||||||
import org.elasticsearch.client.security.InvalidateTokenResponse;
|
import org.elasticsearch.client.security.InvalidateTokenResponse;
|
||||||
|
import org.elasticsearch.client.security.PutPrivilegesRequest;
|
||||||
|
import org.elasticsearch.client.security.PutPrivilegesResponse;
|
||||||
import org.elasticsearch.client.security.PutRoleMappingRequest;
|
import org.elasticsearch.client.security.PutRoleMappingRequest;
|
||||||
import org.elasticsearch.client.security.PutRoleMappingResponse;
|
import org.elasticsearch.client.security.PutRoleMappingResponse;
|
||||||
import org.elasticsearch.client.security.PutUserRequest;
|
import org.elasticsearch.client.security.PutUserRequest;
|
||||||
|
@ -603,6 +605,38 @@ public final class SecurityClient {
|
||||||
options, GetPrivilegesResponse::fromXContent, listener, emptySet());
|
options, GetPrivilegesResponse::fromXContent, listener, emptySet());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create or update application privileges.
|
||||||
|
* See <a href="https://www.elastic.co/guide/en/elasticsearch/reference/current/security-api-put-privileges.html">
|
||||||
|
* the docs</a> for more.
|
||||||
|
*
|
||||||
|
* @param request the request to create or update application privileges
|
||||||
|
* @param options the request options (e.g. headers), use {@link RequestOptions#DEFAULT} if nothing needs to be customized
|
||||||
|
* @return the response from the create or update application privileges call
|
||||||
|
* @throws IOException in case there is a problem sending the request or parsing back the response
|
||||||
|
*/
|
||||||
|
public PutPrivilegesResponse putPrivileges(final PutPrivilegesRequest request, final RequestOptions options) throws IOException {
|
||||||
|
return restHighLevelClient.performRequestAndParseEntity(request, SecurityRequestConverters::putPrivileges, options,
|
||||||
|
PutPrivilegesResponse::fromXContent, emptySet());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Asynchronously create or update application privileges.<br>
|
||||||
|
* See <a href=
|
||||||
|
* "https://www.elastic.co/guide/en/elasticsearch/reference/current/security-api-put-privileges.html">
|
||||||
|
* the docs</a> for more.
|
||||||
|
*
|
||||||
|
* @param request the request to create or update application privileges
|
||||||
|
* @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 putPrivilegesAsync(final PutPrivilegesRequest request, final RequestOptions options,
|
||||||
|
final ActionListener<PutPrivilegesResponse> listener) {
|
||||||
|
restHighLevelClient.performRequestAsyncAndParseEntity(request, SecurityRequestConverters::putPrivileges, options,
|
||||||
|
PutPrivilegesResponse::fromXContent, listener, emptySet());
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Removes application privilege(s)
|
* Removes application privilege(s)
|
||||||
* See <a href="https://www.elastic.co/guide/en/elasticsearch/reference/current/security-api-delete-privilege.html">
|
* See <a href="https://www.elastic.co/guide/en/elasticsearch/reference/current/security-api-delete-privilege.html">
|
||||||
|
|
|
@ -28,17 +28,18 @@ import org.elasticsearch.client.security.ClearRealmCacheRequest;
|
||||||
import org.elasticsearch.client.security.ClearRolesCacheRequest;
|
import org.elasticsearch.client.security.ClearRolesCacheRequest;
|
||||||
import org.elasticsearch.client.security.CreateTokenRequest;
|
import org.elasticsearch.client.security.CreateTokenRequest;
|
||||||
import org.elasticsearch.client.security.DeletePrivilegesRequest;
|
import org.elasticsearch.client.security.DeletePrivilegesRequest;
|
||||||
import org.elasticsearch.client.security.GetPrivilegesRequest;
|
|
||||||
import org.elasticsearch.client.security.DeleteRoleMappingRequest;
|
import org.elasticsearch.client.security.DeleteRoleMappingRequest;
|
||||||
import org.elasticsearch.client.security.DeleteRoleRequest;
|
import org.elasticsearch.client.security.DeleteRoleRequest;
|
||||||
import org.elasticsearch.client.security.DeleteUserRequest;
|
import org.elasticsearch.client.security.DeleteUserRequest;
|
||||||
import org.elasticsearch.client.security.InvalidateTokenRequest;
|
|
||||||
import org.elasticsearch.client.security.GetRolesRequest;
|
|
||||||
import org.elasticsearch.client.security.PutRoleMappingRequest;
|
|
||||||
import org.elasticsearch.client.security.HasPrivilegesRequest;
|
|
||||||
import org.elasticsearch.client.security.DisableUserRequest;
|
import org.elasticsearch.client.security.DisableUserRequest;
|
||||||
import org.elasticsearch.client.security.EnableUserRequest;
|
import org.elasticsearch.client.security.EnableUserRequest;
|
||||||
|
import org.elasticsearch.client.security.GetPrivilegesRequest;
|
||||||
import org.elasticsearch.client.security.GetRoleMappingsRequest;
|
import org.elasticsearch.client.security.GetRoleMappingsRequest;
|
||||||
|
import org.elasticsearch.client.security.GetRolesRequest;
|
||||||
|
import org.elasticsearch.client.security.HasPrivilegesRequest;
|
||||||
|
import org.elasticsearch.client.security.InvalidateTokenRequest;
|
||||||
|
import org.elasticsearch.client.security.PutPrivilegesRequest;
|
||||||
|
import org.elasticsearch.client.security.PutRoleMappingRequest;
|
||||||
import org.elasticsearch.client.security.PutUserRequest;
|
import org.elasticsearch.client.security.PutUserRequest;
|
||||||
import org.elasticsearch.client.security.SetUserEnabledRequest;
|
import org.elasticsearch.client.security.SetUserEnabledRequest;
|
||||||
import org.elasticsearch.common.Strings;
|
import org.elasticsearch.common.Strings;
|
||||||
|
@ -213,6 +214,14 @@ final class SecurityRequestConverters {
|
||||||
return new Request(HttpGet.METHOD_NAME, endpoint);
|
return new Request(HttpGet.METHOD_NAME, endpoint);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static Request putPrivileges(final PutPrivilegesRequest putPrivilegesRequest) throws IOException {
|
||||||
|
Request request = new Request(HttpPut.METHOD_NAME, "/_xpack/security/privilege");
|
||||||
|
request.setEntity(createEntity(putPrivilegesRequest, REQUEST_BODY_CONTENT_TYPE));
|
||||||
|
RequestConverters.Params params = new RequestConverters.Params(request);
|
||||||
|
params.withRefreshPolicy(putPrivilegesRequest.getRefreshPolicy());
|
||||||
|
return request;
|
||||||
|
}
|
||||||
|
|
||||||
static Request deletePrivileges(DeletePrivilegesRequest deletePrivilegeRequest) {
|
static Request deletePrivileges(DeletePrivilegesRequest deletePrivilegeRequest) {
|
||||||
String endpoint = new RequestConverters.EndpointBuilder()
|
String endpoint = new RequestConverters.EndpointBuilder()
|
||||||
.addPathPartAsIs("_xpack/security/privilege")
|
.addPathPartAsIs("_xpack/security/privilege")
|
||||||
|
|
|
@ -0,0 +1,98 @@
|
||||||
|
/*
|
||||||
|
* 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.client.security.user.privileges.ApplicationPrivilege;
|
||||||
|
import org.elasticsearch.common.Nullable;
|
||||||
|
import org.elasticsearch.common.xcontent.ToXContentObject;
|
||||||
|
import org.elasticsearch.common.xcontent.XContentBuilder;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Map.Entry;
|
||||||
|
import java.util.Objects;
|
||||||
|
import java.util.TreeMap;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Request object for creating/updating application privileges.
|
||||||
|
*/
|
||||||
|
public final class PutPrivilegesRequest implements Validatable, ToXContentObject {
|
||||||
|
|
||||||
|
private final Map<String, List<ApplicationPrivilege>> privileges;
|
||||||
|
private final RefreshPolicy refreshPolicy;
|
||||||
|
|
||||||
|
public PutPrivilegesRequest(final List<ApplicationPrivilege> privileges, @Nullable final RefreshPolicy refreshPolicy) {
|
||||||
|
if (privileges == null || privileges.isEmpty()) {
|
||||||
|
throw new IllegalArgumentException("privileges are required");
|
||||||
|
}
|
||||||
|
this.privileges = Collections.unmodifiableMap(privileges.stream()
|
||||||
|
.collect(Collectors.groupingBy(ApplicationPrivilege::getApplication, TreeMap::new, Collectors.toList())));
|
||||||
|
this.refreshPolicy = refreshPolicy == null ? RefreshPolicy.IMMEDIATE : refreshPolicy;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return a map of application name to list of
|
||||||
|
* {@link ApplicationPrivilege}s
|
||||||
|
*/
|
||||||
|
public Map<String, List<ApplicationPrivilege>> getPrivileges() {
|
||||||
|
return privileges;
|
||||||
|
}
|
||||||
|
|
||||||
|
public RefreshPolicy getRefreshPolicy() {
|
||||||
|
return refreshPolicy;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int hashCode() {
|
||||||
|
return Objects.hash(privileges, refreshPolicy);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean equals(Object o) {
|
||||||
|
if (this == o) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (o == null || (this.getClass() != o.getClass())) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
final PutPrivilegesRequest that = (PutPrivilegesRequest) o;
|
||||||
|
return privileges.equals(that.privileges) && (refreshPolicy == that.refreshPolicy);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public XContentBuilder toXContent(final XContentBuilder builder, final Params params) throws IOException {
|
||||||
|
builder.startObject();
|
||||||
|
for (Entry<String, List<ApplicationPrivilege>> entry : privileges.entrySet()) {
|
||||||
|
builder.field(entry.getKey());
|
||||||
|
builder.startObject();
|
||||||
|
for (ApplicationPrivilege applicationPrivilege : entry.getValue()) {
|
||||||
|
builder.field(applicationPrivilege.getName());
|
||||||
|
applicationPrivilege.toXContent(builder, params);
|
||||||
|
}
|
||||||
|
builder.endObject();
|
||||||
|
}
|
||||||
|
return builder.endObject();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,105 @@
|
||||||
|
/*
|
||||||
|
* 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.common.ParsingException;
|
||||||
|
import org.elasticsearch.common.Strings;
|
||||||
|
import org.elasticsearch.common.xcontent.XContentParser;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Map.Entry;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Response when creating/updating one or more application privileges to the
|
||||||
|
* security index.
|
||||||
|
*/
|
||||||
|
public final class PutPrivilegesResponse {
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Map of application name to a map of privilege name to boolean denoting
|
||||||
|
* created or update status.
|
||||||
|
*/
|
||||||
|
private final Map<String, Map<String, Boolean>> applicationPrivilegesCreatedOrUpdated;
|
||||||
|
|
||||||
|
public PutPrivilegesResponse(final Map<String, Map<String, Boolean>> applicationPrivilegesCreatedOrUpdated) {
|
||||||
|
this.applicationPrivilegesCreatedOrUpdated = Collections.unmodifiableMap(applicationPrivilegesCreatedOrUpdated);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get response status for the request to create or update application
|
||||||
|
* privileges.
|
||||||
|
*
|
||||||
|
* @param applicationName application name as specified in the request
|
||||||
|
* @param privilegeName privilege name as specified in the request
|
||||||
|
* @return {@code true} if the privilege was created, {@code false} if the
|
||||||
|
* privilege was updated
|
||||||
|
* @throws IllegalArgumentException thrown for unknown application name or
|
||||||
|
* privilege name.
|
||||||
|
*/
|
||||||
|
public boolean wasCreated(final String applicationName, final String privilegeName) {
|
||||||
|
if (Strings.hasText(applicationName) == false) {
|
||||||
|
throw new IllegalArgumentException("application name is required");
|
||||||
|
}
|
||||||
|
if (Strings.hasText(privilegeName) == false) {
|
||||||
|
throw new IllegalArgumentException("privilege name is required");
|
||||||
|
}
|
||||||
|
if (applicationPrivilegesCreatedOrUpdated.get(applicationName) == null
|
||||||
|
|| applicationPrivilegesCreatedOrUpdated.get(applicationName).get(privilegeName) == null) {
|
||||||
|
throw new IllegalArgumentException("application name or privilege name not found in the response");
|
||||||
|
}
|
||||||
|
return applicationPrivilegesCreatedOrUpdated.get(applicationName).get(privilegeName);
|
||||||
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
public static PutPrivilegesResponse fromXContent(final XContentParser parser) throws IOException {
|
||||||
|
final Map<String, Map<String, Boolean>> applicationPrivilegesCreatedOrUpdated = new HashMap<>();
|
||||||
|
XContentParser.Token token = parser.currentToken();
|
||||||
|
if (token == null) {
|
||||||
|
token = parser.nextToken();
|
||||||
|
}
|
||||||
|
final Map<String, Object> appNameToPrivStatus = parser.map();
|
||||||
|
for (Entry<String, Object> entry : appNameToPrivStatus.entrySet()) {
|
||||||
|
if (entry.getValue() instanceof Map) {
|
||||||
|
final Map<String, Boolean> privilegeToStatus = applicationPrivilegesCreatedOrUpdated.computeIfAbsent(entry.getKey(),
|
||||||
|
(a) -> new HashMap<>());
|
||||||
|
final Map<String, Object> createdOrUpdated = (Map<String, Object>) entry.getValue();
|
||||||
|
for (String privilegeName : createdOrUpdated.keySet()) {
|
||||||
|
if (createdOrUpdated.get(privilegeName) instanceof Map) {
|
||||||
|
final Map<String, Object> statusMap = (Map<String, Object>) createdOrUpdated.get(privilegeName);
|
||||||
|
final Object status = statusMap.get("created");
|
||||||
|
if (status instanceof Boolean) {
|
||||||
|
privilegeToStatus.put(privilegeName, (Boolean) status);
|
||||||
|
} else {
|
||||||
|
throw new ParsingException(parser.getTokenLocation(), "Failed to parse object, unexpected structure");
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
throw new ParsingException(parser.getTokenLocation(), "Failed to parse object, unexpected structure");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
throw new ParsingException(parser.getTokenLocation(), "Failed to parse object, unexpected structure");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return new PutPrivilegesResponse(applicationPrivilegesCreatedOrUpdated);
|
||||||
|
}
|
||||||
|
}
|
|
@ -24,6 +24,8 @@ import org.elasticsearch.common.ParseField;
|
||||||
import org.elasticsearch.common.Strings;
|
import org.elasticsearch.common.Strings;
|
||||||
import org.elasticsearch.common.xcontent.ConstructingObjectParser;
|
import org.elasticsearch.common.xcontent.ConstructingObjectParser;
|
||||||
import org.elasticsearch.common.xcontent.ObjectParser;
|
import org.elasticsearch.common.xcontent.ObjectParser;
|
||||||
|
import org.elasticsearch.common.xcontent.ToXContentObject;
|
||||||
|
import org.elasticsearch.common.xcontent.XContentBuilder;
|
||||||
import org.elasticsearch.common.xcontent.XContentParser;
|
import org.elasticsearch.common.xcontent.XContentParser;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
@ -44,7 +46,7 @@ import static org.elasticsearch.common.xcontent.ConstructingObjectParser.optiona
|
||||||
* actions and metadata are completely managed by the client and can contain arbitrary
|
* actions and metadata are completely managed by the client and can contain arbitrary
|
||||||
* string values.
|
* string values.
|
||||||
*/
|
*/
|
||||||
public final class ApplicationPrivilege {
|
public final class ApplicationPrivilege implements ToXContentObject {
|
||||||
|
|
||||||
private static final ParseField APPLICATION = new ParseField("application");
|
private static final ParseField APPLICATION = new ParseField("application");
|
||||||
private static final ParseField NAME = new ParseField("name");
|
private static final ParseField NAME = new ParseField("name");
|
||||||
|
@ -171,4 +173,16 @@ public final class ApplicationPrivilege {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public XContentBuilder toXContent(XContentBuilder builder, Params params) throws IOException {
|
||||||
|
builder.startObject()
|
||||||
|
.field(APPLICATION.getPreferredName(), application)
|
||||||
|
.field(NAME.getPreferredName(), name)
|
||||||
|
.field(ACTIONS.getPreferredName(), actions);
|
||||||
|
if (metadata != null && metadata.isEmpty() == false) {
|
||||||
|
builder.field(METADATA.getPreferredName(), metadata);
|
||||||
|
}
|
||||||
|
return builder.endObject();
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -19,10 +19,11 @@
|
||||||
|
|
||||||
package org.elasticsearch.client;
|
package org.elasticsearch.client;
|
||||||
|
|
||||||
import org.apache.http.client.methods.HttpGet;
|
|
||||||
import org.apache.http.client.methods.HttpDelete;
|
import org.apache.http.client.methods.HttpDelete;
|
||||||
|
import org.apache.http.client.methods.HttpGet;
|
||||||
import org.apache.http.client.methods.HttpPost;
|
import org.apache.http.client.methods.HttpPost;
|
||||||
import org.apache.http.client.methods.HttpPut;
|
import org.apache.http.client.methods.HttpPut;
|
||||||
|
import org.elasticsearch.client.security.ChangePasswordRequest;
|
||||||
import org.elasticsearch.client.security.CreateTokenRequest;
|
import org.elasticsearch.client.security.CreateTokenRequest;
|
||||||
import org.elasticsearch.client.security.DeletePrivilegesRequest;
|
import org.elasticsearch.client.security.DeletePrivilegesRequest;
|
||||||
import org.elasticsearch.client.security.DeleteRoleMappingRequest;
|
import org.elasticsearch.client.security.DeleteRoleMappingRequest;
|
||||||
|
@ -32,8 +33,8 @@ import org.elasticsearch.client.security.DisableUserRequest;
|
||||||
import org.elasticsearch.client.security.EnableUserRequest;
|
import org.elasticsearch.client.security.EnableUserRequest;
|
||||||
import org.elasticsearch.client.security.GetPrivilegesRequest;
|
import org.elasticsearch.client.security.GetPrivilegesRequest;
|
||||||
import org.elasticsearch.client.security.GetRoleMappingsRequest;
|
import org.elasticsearch.client.security.GetRoleMappingsRequest;
|
||||||
import org.elasticsearch.client.security.ChangePasswordRequest;
|
|
||||||
import org.elasticsearch.client.security.GetRolesRequest;
|
import org.elasticsearch.client.security.GetRolesRequest;
|
||||||
|
import org.elasticsearch.client.security.PutPrivilegesRequest;
|
||||||
import org.elasticsearch.client.security.PutRoleMappingRequest;
|
import org.elasticsearch.client.security.PutRoleMappingRequest;
|
||||||
import org.elasticsearch.client.security.PutUserRequest;
|
import org.elasticsearch.client.security.PutUserRequest;
|
||||||
import org.elasticsearch.client.security.RefreshPolicy;
|
import org.elasticsearch.client.security.RefreshPolicy;
|
||||||
|
@ -41,10 +42,13 @@ import org.elasticsearch.client.security.support.expressiondsl.RoleMapperExpress
|
||||||
import org.elasticsearch.client.security.support.expressiondsl.expressions.AnyRoleMapperExpression;
|
import org.elasticsearch.client.security.support.expressiondsl.expressions.AnyRoleMapperExpression;
|
||||||
import org.elasticsearch.client.security.support.expressiondsl.fields.FieldRoleMapperExpression;
|
import org.elasticsearch.client.security.support.expressiondsl.fields.FieldRoleMapperExpression;
|
||||||
import org.elasticsearch.client.security.user.User;
|
import org.elasticsearch.client.security.user.User;
|
||||||
|
import org.elasticsearch.client.security.user.privileges.ApplicationPrivilege;
|
||||||
import org.elasticsearch.common.Strings;
|
import org.elasticsearch.common.Strings;
|
||||||
|
import org.elasticsearch.common.util.set.Sets;
|
||||||
import org.elasticsearch.test.ESTestCase;
|
import org.elasticsearch.test.ESTestCase;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
import java.util.ArrayList;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
|
@ -318,6 +322,27 @@ public class SecurityRequestConvertersTests extends ESTestCase {
|
||||||
assertNull(request.getEntity());
|
assertNull(request.getEntity());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void testPutPrivileges() throws Exception {
|
||||||
|
int noOfApplicationPrivileges = randomIntBetween(2, 4);
|
||||||
|
final List<ApplicationPrivilege> privileges = new ArrayList<>();
|
||||||
|
for (int count = 0; count < noOfApplicationPrivileges; count++) {
|
||||||
|
privileges.add(ApplicationPrivilege.builder()
|
||||||
|
.application(randomAlphaOfLength(4))
|
||||||
|
.privilege(randomAlphaOfLengthBetween(3, 5))
|
||||||
|
.actions(Sets.newHashSet(generateRandomStringArray(3, 5, false, false)))
|
||||||
|
.metadata(Collections.singletonMap("k1", "v1"))
|
||||||
|
.build());
|
||||||
|
}
|
||||||
|
final RefreshPolicy refreshPolicy = randomFrom(RefreshPolicy.values());
|
||||||
|
final Map<String, String> expectedParams = getExpectedParamsFromRefreshPolicy(refreshPolicy);
|
||||||
|
final PutPrivilegesRequest putPrivilegesRequest = new PutPrivilegesRequest(privileges, refreshPolicy);
|
||||||
|
final Request request = SecurityRequestConverters.putPrivileges(putPrivilegesRequest);
|
||||||
|
assertEquals(HttpPut.METHOD_NAME, request.getMethod());
|
||||||
|
assertEquals("/_xpack/security/privilege", request.getEndpoint());
|
||||||
|
assertEquals(expectedParams, request.getParameters());
|
||||||
|
assertToXContentBody(putPrivilegesRequest, request.getEntity());
|
||||||
|
}
|
||||||
|
|
||||||
public void testDeletePrivileges() {
|
public void testDeletePrivileges() {
|
||||||
final String application = randomAlphaOfLengthBetween(1, 12);
|
final String application = randomAlphaOfLengthBetween(1, 12);
|
||||||
final List<String> privileges = randomSubsetOf(randomIntBetween(1, 3), "read", "write", "all");
|
final List<String> privileges = randomSubsetOf(randomIntBetween(1, 3), "read", "write", "all");
|
||||||
|
|
|
@ -29,7 +29,6 @@ import org.elasticsearch.action.support.PlainActionFuture;
|
||||||
import org.elasticsearch.client.ESRestHighLevelClientTestCase;
|
import org.elasticsearch.client.ESRestHighLevelClientTestCase;
|
||||||
import org.elasticsearch.client.Request;
|
import org.elasticsearch.client.Request;
|
||||||
import org.elasticsearch.client.RequestOptions;
|
import org.elasticsearch.client.RequestOptions;
|
||||||
import org.elasticsearch.client.Response;
|
|
||||||
import org.elasticsearch.client.RestHighLevelClient;
|
import org.elasticsearch.client.RestHighLevelClient;
|
||||||
import org.elasticsearch.client.security.AuthenticateResponse;
|
import org.elasticsearch.client.security.AuthenticateResponse;
|
||||||
import org.elasticsearch.client.security.ChangePasswordRequest;
|
import org.elasticsearch.client.security.ChangePasswordRequest;
|
||||||
|
@ -62,6 +61,8 @@ import org.elasticsearch.client.security.HasPrivilegesRequest;
|
||||||
import org.elasticsearch.client.security.HasPrivilegesResponse;
|
import org.elasticsearch.client.security.HasPrivilegesResponse;
|
||||||
import org.elasticsearch.client.security.InvalidateTokenRequest;
|
import org.elasticsearch.client.security.InvalidateTokenRequest;
|
||||||
import org.elasticsearch.client.security.InvalidateTokenResponse;
|
import org.elasticsearch.client.security.InvalidateTokenResponse;
|
||||||
|
import org.elasticsearch.client.security.PutPrivilegesRequest;
|
||||||
|
import org.elasticsearch.client.security.PutPrivilegesResponse;
|
||||||
import org.elasticsearch.client.security.PutRoleMappingRequest;
|
import org.elasticsearch.client.security.PutRoleMappingRequest;
|
||||||
import org.elasticsearch.client.security.PutRoleMappingResponse;
|
import org.elasticsearch.client.security.PutRoleMappingResponse;
|
||||||
import org.elasticsearch.client.security.PutUserRequest;
|
import org.elasticsearch.client.security.PutUserRequest;
|
||||||
|
@ -78,7 +79,6 @@ import org.elasticsearch.client.security.user.privileges.IndicesPrivileges;
|
||||||
import org.elasticsearch.common.Strings;
|
import org.elasticsearch.common.Strings;
|
||||||
import org.elasticsearch.common.util.set.Sets;
|
import org.elasticsearch.common.util.set.Sets;
|
||||||
import org.elasticsearch.common.xcontent.XContentBuilder;
|
import org.elasticsearch.common.xcontent.XContentBuilder;
|
||||||
import org.elasticsearch.rest.RestStatus;
|
|
||||||
import org.hamcrest.Matchers;
|
import org.hamcrest.Matchers;
|
||||||
|
|
||||||
import javax.crypto.SecretKeyFactory;
|
import javax.crypto.SecretKeyFactory;
|
||||||
|
@ -86,6 +86,7 @@ import javax.crypto.spec.PBEKeySpec;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.security.SecureRandom;
|
import java.security.SecureRandom;
|
||||||
import java.util.Base64;
|
import java.util.Base64;
|
||||||
|
import java.util.ArrayList;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
|
@ -1205,36 +1206,23 @@ public class SecurityDocumentationIT extends ESRestHighLevelClientTestCase {
|
||||||
new ApplicationPrivilege("testapp2", "all", Arrays.asList("action:login", "data:write/*", "manage:*"), null);
|
new ApplicationPrivilege("testapp2", "all", Arrays.asList("action:login", "data:write/*", "manage:*"), null);
|
||||||
|
|
||||||
{
|
{
|
||||||
//TODO Replace this with a call to PutPrivileges once it is implemented
|
List<ApplicationPrivilege> applicationPrivileges = new ArrayList<>();
|
||||||
final Request createPrivilegeRequest = new Request("POST", "/_xpack/security/privilege");
|
applicationPrivileges.add(readTestappPrivilege);
|
||||||
createPrivilegeRequest.setJsonEntity("{" +
|
applicationPrivileges.add(writeTestappPrivilege);
|
||||||
" \"testapp\": {" +
|
applicationPrivileges.add(allTestappPrivilege);
|
||||||
" \"read\": {" +
|
applicationPrivileges.add(readTestapp2Privilege);
|
||||||
" \"actions\": [ \"action:login\", \"data:read/*\" ]" +
|
applicationPrivileges.add(writeTestapp2Privilege);
|
||||||
" }," +
|
applicationPrivileges.add(allTestapp2Privilege);
|
||||||
" \"write\": {" +
|
PutPrivilegesRequest putPrivilegesRequest = new PutPrivilegesRequest(applicationPrivileges, RefreshPolicy.IMMEDIATE);
|
||||||
" \"actions\": [ \"action:login\", \"data:write/*\" ]," +
|
PutPrivilegesResponse putPrivilegesResponse = client.security().putPrivileges(putPrivilegesRequest, RequestOptions.DEFAULT);
|
||||||
" \"metadata\": { \"key1\": \"value1\" }" +
|
|
||||||
" }," +
|
assertNotNull(putPrivilegesResponse);
|
||||||
" \"all\": {" +
|
assertThat(putPrivilegesResponse.wasCreated("testapp", "write"), is(true));
|
||||||
" \"actions\": [ \"action:login\", \"data:write/*\" , \"manage:*\"]" +
|
assertThat(putPrivilegesResponse.wasCreated("testapp", "read"), is(true));
|
||||||
" }" +
|
assertThat(putPrivilegesResponse.wasCreated("testapp", "all"), is(true));
|
||||||
" }," +
|
assertThat(putPrivilegesResponse.wasCreated("testapp2", "all"), is(true));
|
||||||
" \"testapp2\": {" +
|
assertThat(putPrivilegesResponse.wasCreated("testapp2", "write"), is(true));
|
||||||
" \"read\": {" +
|
assertThat(putPrivilegesResponse.wasCreated("testapp2", "read"), is(true));
|
||||||
" \"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());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
|
@ -1327,26 +1315,105 @@ public class SecurityDocumentationIT extends ESRestHighLevelClientTestCase {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void testPutPrivileges() throws Exception {
|
||||||
|
RestHighLevelClient client = highLevelClient();
|
||||||
|
|
||||||
|
{
|
||||||
|
// tag::put-privileges-request
|
||||||
|
final List<ApplicationPrivilege> privileges = new ArrayList<>();
|
||||||
|
privileges.add(ApplicationPrivilege.builder()
|
||||||
|
.application("app01")
|
||||||
|
.privilege("all")
|
||||||
|
.actions(Sets.newHashSet("action:login"))
|
||||||
|
.metadata(Collections.singletonMap("k1", "v1"))
|
||||||
|
.build());
|
||||||
|
privileges.add(ApplicationPrivilege.builder()
|
||||||
|
.application("app01")
|
||||||
|
.privilege("write")
|
||||||
|
.actions(Sets.newHashSet("action:write"))
|
||||||
|
.build());
|
||||||
|
final PutPrivilegesRequest putPrivilegesRequest = new PutPrivilegesRequest(privileges, RefreshPolicy.IMMEDIATE);
|
||||||
|
// end::put-privileges-request
|
||||||
|
|
||||||
|
// tag::put-privileges-execute
|
||||||
|
final PutPrivilegesResponse putPrivilegesResponse = client.security().putPrivileges(putPrivilegesRequest,
|
||||||
|
RequestOptions.DEFAULT);
|
||||||
|
// end::put-privileges-execute
|
||||||
|
|
||||||
|
final String applicationName = "app01";
|
||||||
|
final String privilegeName = "all";
|
||||||
|
// tag::put-privileges-response
|
||||||
|
final boolean status = putPrivilegesResponse.wasCreated(applicationName, privilegeName); // <1>
|
||||||
|
// end::put-privileges-response
|
||||||
|
assertThat(status, is(true));
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
final List<ApplicationPrivilege> privileges = new ArrayList<>();
|
||||||
|
privileges.add(ApplicationPrivilege.builder()
|
||||||
|
.application("app01")
|
||||||
|
.privilege("all")
|
||||||
|
.actions(Sets.newHashSet("action:login"))
|
||||||
|
.metadata(Collections.singletonMap("k1", "v1"))
|
||||||
|
.build());
|
||||||
|
final PutPrivilegesRequest putPrivilegesRequest = new PutPrivilegesRequest(privileges, RefreshPolicy.IMMEDIATE);
|
||||||
|
|
||||||
|
// tag::put-privileges-execute-listener
|
||||||
|
ActionListener<PutPrivilegesResponse> listener = new ActionListener<PutPrivilegesResponse>() {
|
||||||
|
@Override
|
||||||
|
public void onResponse(PutPrivilegesResponse response) {
|
||||||
|
// <1>
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onFailure(Exception e) {
|
||||||
|
// <2>
|
||||||
|
}
|
||||||
|
};
|
||||||
|
// end::put-privileges-execute-listener
|
||||||
|
|
||||||
|
// Avoid unused variable warning
|
||||||
|
assertNotNull(listener);
|
||||||
|
|
||||||
|
// Replace the empty listener by a blocking listener in test
|
||||||
|
final PlainActionFuture<PutPrivilegesResponse> future = new PlainActionFuture<>();
|
||||||
|
listener = future;
|
||||||
|
|
||||||
|
//tag::put-privileges-execute-async
|
||||||
|
client.security().putPrivilegesAsync(putPrivilegesRequest, RequestOptions.DEFAULT, listener); // <1>
|
||||||
|
//end::put-privileges-execute-async
|
||||||
|
|
||||||
|
assertNotNull(future.get(30, TimeUnit.SECONDS));
|
||||||
|
assertThat(future.get().wasCreated("app01", "all"), is(false));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public void testDeletePrivilege() throws Exception {
|
public void testDeletePrivilege() throws Exception {
|
||||||
RestHighLevelClient client = highLevelClient();
|
RestHighLevelClient client = highLevelClient();
|
||||||
{
|
{
|
||||||
final Request createPrivilegeRequest = new Request("POST", "/_xpack/security/privilege");
|
List<ApplicationPrivilege> applicationPrivileges = new ArrayList<>();
|
||||||
createPrivilegeRequest.setJsonEntity("{" +
|
applicationPrivileges.add(ApplicationPrivilege.builder()
|
||||||
" \"testapp\": {" +
|
.application("testapp")
|
||||||
" \"read\": {" +
|
.privilege("read")
|
||||||
" \"actions\": [ \"action:login\", \"data:read/*\" ]" +
|
.actions("action:login", "data:read/*")
|
||||||
" }," +
|
.build());
|
||||||
" \"write\": {" +
|
applicationPrivileges.add(ApplicationPrivilege.builder()
|
||||||
" \"actions\": [ \"action:login\", \"data:write/*\" ]" +
|
.application("testapp")
|
||||||
" }," +
|
.privilege("write")
|
||||||
" \"all\": {" +
|
.actions("action:login", "data:write/*")
|
||||||
" \"actions\": [ \"action:login\", \"data:write/*\" ]" +
|
.build());
|
||||||
" }" +
|
applicationPrivileges.add(ApplicationPrivilege.builder()
|
||||||
" }" +
|
.application("testapp")
|
||||||
"}");
|
.privilege("all")
|
||||||
|
.actions("action:login", "data:write/*")
|
||||||
|
.build());
|
||||||
|
PutPrivilegesRequest putPrivilegesRequest = new PutPrivilegesRequest(applicationPrivileges, RefreshPolicy.IMMEDIATE);
|
||||||
|
PutPrivilegesResponse putPrivilegesResponse = client.security().putPrivileges(putPrivilegesRequest, RequestOptions.DEFAULT);
|
||||||
|
|
||||||
final Response createPrivilegeResponse = client.getLowLevelClient().performRequest(createPrivilegeRequest);
|
assertNotNull(putPrivilegesResponse);
|
||||||
assertEquals(RestStatus.OK.getStatus(), createPrivilegeResponse.getStatusLine().getStatusCode());
|
assertThat(putPrivilegesResponse.wasCreated("testapp", "write"), is(true));
|
||||||
|
assertThat(putPrivilegesResponse.wasCreated("testapp", "read"), is(true));
|
||||||
|
assertThat(putPrivilegesResponse.wasCreated("testapp", "all"), is(true));
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
// tag::delete-privileges-request
|
// tag::delete-privileges-request
|
||||||
|
|
|
@ -0,0 +1,170 @@
|
||||||
|
/*
|
||||||
|
* 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.Strings;
|
||||||
|
import org.elasticsearch.common.util.set.Sets;
|
||||||
|
import org.elasticsearch.common.xcontent.ToXContent;
|
||||||
|
import org.elasticsearch.common.xcontent.XContentBuilder;
|
||||||
|
import org.elasticsearch.common.xcontent.XContentFactory;
|
||||||
|
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.List;
|
||||||
|
import java.util.Set;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
|
import static org.hamcrest.Matchers.equalTo;
|
||||||
|
|
||||||
|
public class PutPrivilegesRequestTests extends ESTestCase {
|
||||||
|
|
||||||
|
public void testConstructor() {
|
||||||
|
final List<ApplicationPrivilege> privileges = randomFrom(
|
||||||
|
Arrays.asList(Collections.singletonList(ApplicationPrivilege.builder()
|
||||||
|
.application("app01")
|
||||||
|
.privilege("all")
|
||||||
|
.actions(Sets.newHashSet("action:login", "action:logout"))
|
||||||
|
.metadata(Collections.singletonMap("k1", "v1"))
|
||||||
|
.build()),
|
||||||
|
null, Collections.emptyList()));
|
||||||
|
final RefreshPolicy refreshPolicy = randomFrom(RefreshPolicy.values());
|
||||||
|
if (privileges == null || privileges.isEmpty()) {
|
||||||
|
final IllegalArgumentException ile = expectThrows(IllegalArgumentException.class,
|
||||||
|
() -> new PutPrivilegesRequest(privileges, refreshPolicy));
|
||||||
|
assertThat(ile.getMessage(), equalTo("privileges are required"));
|
||||||
|
} else {
|
||||||
|
final PutPrivilegesRequest putPrivilegesRequest = new PutPrivilegesRequest(privileges, refreshPolicy);
|
||||||
|
assertThat(putPrivilegesRequest.getPrivileges().values().stream().flatMap(List::stream).collect(Collectors.toList()),
|
||||||
|
equalTo(privileges));
|
||||||
|
assertThat(putPrivilegesRequest.getRefreshPolicy(), equalTo(refreshPolicy));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testToXContent() throws IOException {
|
||||||
|
final String expected = "{\n"
|
||||||
|
+ " \"app01\" : {\n"
|
||||||
|
+ " \"all\" : {\n"
|
||||||
|
+ " \"application\" : \"app01\",\n"
|
||||||
|
+ " \"name\" : \"all\",\n"
|
||||||
|
+ " \"actions\" : [\n"
|
||||||
|
+ " \"action:logout\",\n"
|
||||||
|
+ " \"action:login\"\n"
|
||||||
|
+ " ],\n"
|
||||||
|
+ " \"metadata\" : {\n"
|
||||||
|
+ " \"k1\" : \"v1\"\n"
|
||||||
|
+ " }\n"
|
||||||
|
+ " },\n"
|
||||||
|
+ " \"read\" : {\n"
|
||||||
|
+ " \"application\" : \"app01\",\n"
|
||||||
|
+ " \"name\" : \"read\",\n"
|
||||||
|
+ " \"actions\" : [\n"
|
||||||
|
+ " \"data:read\"\n"
|
||||||
|
+ " ]\n" + " }\n"
|
||||||
|
+ " },\n"
|
||||||
|
+ " \"app02\" : {\n"
|
||||||
|
+ " \"all\" : {\n"
|
||||||
|
+ " \"application\" : \"app02\",\n"
|
||||||
|
+ " \"name\" : \"all\",\n"
|
||||||
|
+ " \"actions\" : [\n"
|
||||||
|
+ " \"action:logout\",\n"
|
||||||
|
+ " \"action:login\"\n"
|
||||||
|
+ " ],\n"
|
||||||
|
+ " \"metadata\" : {\n"
|
||||||
|
+ " \"k2\" : \"v2\"\n"
|
||||||
|
+ " }\n"
|
||||||
|
+ " }\n"
|
||||||
|
+ " }\n"
|
||||||
|
+ "}";
|
||||||
|
List<ApplicationPrivilege> privileges = new ArrayList<>();
|
||||||
|
privileges.add(ApplicationPrivilege.builder()
|
||||||
|
.application("app01")
|
||||||
|
.privilege("all")
|
||||||
|
.actions(Sets.newHashSet("action:login", "action:logout"))
|
||||||
|
.metadata(Collections.singletonMap("k1", "v1"))
|
||||||
|
.build());
|
||||||
|
privileges.add(ApplicationPrivilege.builder()
|
||||||
|
.application("app01")
|
||||||
|
.privilege("read")
|
||||||
|
.actions(Sets.newHashSet("data:read"))
|
||||||
|
.build());
|
||||||
|
privileges.add(ApplicationPrivilege.builder()
|
||||||
|
.application("app02")
|
||||||
|
.privilege("all")
|
||||||
|
.actions(Sets.newHashSet("action:login", "action:logout"))
|
||||||
|
.metadata(Collections.singletonMap("k2", "v2"))
|
||||||
|
.build());
|
||||||
|
final RefreshPolicy refreshPolicy = randomFrom(RefreshPolicy.values());
|
||||||
|
final PutPrivilegesRequest putPrivilegesRequest = new PutPrivilegesRequest(privileges, refreshPolicy);
|
||||||
|
final XContentBuilder builder = XContentFactory.jsonBuilder().prettyPrint();
|
||||||
|
assertThat(Strings.toString(putPrivilegesRequest.toXContent(builder, ToXContent.EMPTY_PARAMS)), equalTo(expected));
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testEqualsHashCode() {
|
||||||
|
final List<ApplicationPrivilege> privileges = new ArrayList<>();
|
||||||
|
privileges.add(ApplicationPrivilege.builder()
|
||||||
|
.application(randomAlphaOfLength(5))
|
||||||
|
.privilege(randomAlphaOfLength(3))
|
||||||
|
.actions(Sets.newHashSet(randomAlphaOfLength(5), randomAlphaOfLength(5)))
|
||||||
|
.metadata(Collections.singletonMap(randomAlphaOfLength(3), randomAlphaOfLength(3)))
|
||||||
|
.build());
|
||||||
|
privileges.add(ApplicationPrivilege.builder()
|
||||||
|
.application(randomAlphaOfLength(5))
|
||||||
|
.privilege(randomAlphaOfLength(3))
|
||||||
|
.actions(Sets.newHashSet(randomAlphaOfLength(5), randomAlphaOfLength(5)))
|
||||||
|
.metadata(Collections.singletonMap(randomAlphaOfLength(3), randomAlphaOfLength(3)))
|
||||||
|
.build());
|
||||||
|
final RefreshPolicy refreshPolicy = randomFrom(RefreshPolicy.values());
|
||||||
|
PutPrivilegesRequest putPrivilegesRequest = new PutPrivilegesRequest(privileges, refreshPolicy);
|
||||||
|
|
||||||
|
EqualsHashCodeTestUtils.checkEqualsAndHashCode(putPrivilegesRequest, (original) -> {
|
||||||
|
return new PutPrivilegesRequest(privileges, refreshPolicy);
|
||||||
|
});
|
||||||
|
EqualsHashCodeTestUtils.checkEqualsAndHashCode(putPrivilegesRequest, (original) -> {
|
||||||
|
return new PutPrivilegesRequest(original.getPrivileges().values().stream().flatMap(List::stream).collect(Collectors.toList()),
|
||||||
|
original.getRefreshPolicy());
|
||||||
|
}, PutPrivilegesRequestTests::mutateTestItem);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static PutPrivilegesRequest mutateTestItem(PutPrivilegesRequest original) {
|
||||||
|
final Set<RefreshPolicy> policies = Sets.newHashSet(RefreshPolicy.values());
|
||||||
|
policies.remove(original.getRefreshPolicy());
|
||||||
|
switch (randomIntBetween(0, 1)) {
|
||||||
|
case 0:
|
||||||
|
final List<ApplicationPrivilege> privileges = new ArrayList<>();
|
||||||
|
privileges.add(ApplicationPrivilege.builder()
|
||||||
|
.application(randomAlphaOfLength(5))
|
||||||
|
.privilege(randomAlphaOfLength(3))
|
||||||
|
.actions(Sets.newHashSet(randomAlphaOfLength(6)))
|
||||||
|
.build());
|
||||||
|
return new PutPrivilegesRequest(privileges, original.getRefreshPolicy());
|
||||||
|
case 1:
|
||||||
|
return new PutPrivilegesRequest(original.getPrivileges().values().stream().flatMap(List::stream).collect(Collectors.toList()),
|
||||||
|
randomFrom(policies));
|
||||||
|
default:
|
||||||
|
return new PutPrivilegesRequest(original.getPrivileges().values().stream().flatMap(List::stream).collect(Collectors.toList()),
|
||||||
|
randomFrom(policies));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,86 @@
|
||||||
|
/*
|
||||||
|
* 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.common.xcontent.XContentType;
|
||||||
|
import org.elasticsearch.test.ESTestCase;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.Collections;
|
||||||
|
|
||||||
|
import static org.hamcrest.Matchers.equalTo;
|
||||||
|
import static org.hamcrest.Matchers.is;
|
||||||
|
|
||||||
|
public class PutPrivilegesResponseTests extends ESTestCase {
|
||||||
|
|
||||||
|
public void testFromXContent() throws IOException {
|
||||||
|
final String json = "{\n" +
|
||||||
|
" \"app02\": {\n" +
|
||||||
|
" \"all\": {\n" +
|
||||||
|
" \"created\": true\n" +
|
||||||
|
" }\n" +
|
||||||
|
" },\n" +
|
||||||
|
" \"app01\": {\n" +
|
||||||
|
" \"read\": {\n" +
|
||||||
|
" \"created\": false\n" +
|
||||||
|
" },\n" +
|
||||||
|
" \"write\": {\n" +
|
||||||
|
" \"created\": true\n" +
|
||||||
|
" }\n" +
|
||||||
|
" }\n" +
|
||||||
|
"}";
|
||||||
|
|
||||||
|
final PutPrivilegesResponse putPrivilegesResponse = PutPrivilegesResponse
|
||||||
|
.fromXContent(createParser(XContentType.JSON.xContent(), json));
|
||||||
|
|
||||||
|
assertThat(putPrivilegesResponse.wasCreated("app02", "all"), is(true));
|
||||||
|
assertThat(putPrivilegesResponse.wasCreated("app01", "read"), is(false));
|
||||||
|
assertThat(putPrivilegesResponse.wasCreated("app01", "write"), is(true));
|
||||||
|
expectThrows(IllegalArgumentException.class, () -> putPrivilegesResponse.wasCreated("unknown-app", "unknown-priv"));
|
||||||
|
expectThrows(IllegalArgumentException.class, () -> putPrivilegesResponse.wasCreated("app01", "unknown-priv"));
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testGetStatusFailsForUnknownApplicationOrPrivilegeName() {
|
||||||
|
final PutPrivilegesResponse putPrivilegesResponse = new PutPrivilegesResponse(
|
||||||
|
Collections.singletonMap("app-1", Collections.singletonMap("priv", true)));
|
||||||
|
|
||||||
|
final boolean invalidAppName = randomBoolean();
|
||||||
|
final String applicationName = (invalidAppName) ? randomAlphaOfLength(4) : "app-1";
|
||||||
|
final String privilegeName = randomAlphaOfLength(4);
|
||||||
|
|
||||||
|
final IllegalArgumentException ile = expectThrows(IllegalArgumentException.class,
|
||||||
|
() -> putPrivilegesResponse.wasCreated(applicationName, privilegeName));
|
||||||
|
assertThat(ile.getMessage(), equalTo("application name or privilege name not found in the response"));
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testGetStatusFailsForNullOrEmptyApplicationOrPrivilegeName() {
|
||||||
|
final PutPrivilegesResponse putPrivilegesResponse = new PutPrivilegesResponse(
|
||||||
|
Collections.singletonMap("app-1", Collections.singletonMap("priv", true)));
|
||||||
|
|
||||||
|
final boolean nullOrEmptyAppName = randomBoolean();
|
||||||
|
final String applicationName = (nullOrEmptyAppName) ? randomFrom(Arrays.asList("", " ", null)) : "app-1";
|
||||||
|
final String privilegeName = randomFrom(Arrays.asList("", " ", null));
|
||||||
|
final IllegalArgumentException ile = expectThrows(IllegalArgumentException.class,
|
||||||
|
() -> putPrivilegesResponse.wasCreated(applicationName, privilegeName));
|
||||||
|
assertThat(ile.getMessage(),
|
||||||
|
(nullOrEmptyAppName ? equalTo("application name is required") : equalTo("privilege name is required")));
|
||||||
|
}
|
||||||
|
}
|
|
@ -19,8 +19,12 @@
|
||||||
|
|
||||||
package org.elasticsearch.client.security.user.privileges;
|
package org.elasticsearch.client.security.user.privileges;
|
||||||
|
|
||||||
|
import org.elasticsearch.common.Strings;
|
||||||
import org.elasticsearch.common.xcontent.DeprecationHandler;
|
import org.elasticsearch.common.xcontent.DeprecationHandler;
|
||||||
import org.elasticsearch.common.xcontent.NamedXContentRegistry;
|
import org.elasticsearch.common.xcontent.NamedXContentRegistry;
|
||||||
|
import org.elasticsearch.common.xcontent.ToXContent;
|
||||||
|
import org.elasticsearch.common.xcontent.XContentBuilder;
|
||||||
|
import org.elasticsearch.common.xcontent.XContentFactory;
|
||||||
import org.elasticsearch.common.xcontent.XContentType;
|
import org.elasticsearch.common.xcontent.XContentType;
|
||||||
import org.elasticsearch.test.ESTestCase;
|
import org.elasticsearch.test.ESTestCase;
|
||||||
|
|
||||||
|
@ -36,19 +40,19 @@ import static org.hamcrest.Matchers.equalTo;
|
||||||
|
|
||||||
public class ApplicationPrivilegeTests extends ESTestCase {
|
public class ApplicationPrivilegeTests extends ESTestCase {
|
||||||
|
|
||||||
public void testFromXContent() throws IOException {
|
public void testFromXContentAndToXContent() throws IOException {
|
||||||
String json =
|
String json =
|
||||||
" {" +
|
"{\n"
|
||||||
" \"application\": \"myapp\"," +
|
+ " \"application\" : \"myapp\",\n"
|
||||||
" \"name\": \"read\"," +
|
+ " \"name\" : \"read\",\n"
|
||||||
" \"actions\": [" +
|
+ " \"actions\" : [\n"
|
||||||
" \"data:read/*\"," +
|
+ " \"data:read/*\",\n"
|
||||||
" \"action:login\"" +
|
+ " \"action:login\"\n"
|
||||||
" ],\n" +
|
+ " ],\n"
|
||||||
" \"metadata\": {" +
|
+ " \"metadata\" : {\n"
|
||||||
" \"description\": \"Read access to myapp\"" +
|
+ " \"description\" : \"Read access to myapp\"\n"
|
||||||
" }" +
|
+ " }\n"
|
||||||
" }";
|
+ "}";
|
||||||
final ApplicationPrivilege privilege = ApplicationPrivilege.fromXContent(XContentType.JSON.xContent().createParser(
|
final ApplicationPrivilege privilege = ApplicationPrivilege.fromXContent(XContentType.JSON.xContent().createParser(
|
||||||
new NamedXContentRegistry(Collections.emptyList()), new DeprecationHandler() {
|
new NamedXContentRegistry(Collections.emptyList()), new DeprecationHandler() {
|
||||||
@Override
|
@Override
|
||||||
|
@ -64,6 +68,10 @@ public class ApplicationPrivilegeTests extends ESTestCase {
|
||||||
final ApplicationPrivilege expectedPrivilege =
|
final ApplicationPrivilege expectedPrivilege =
|
||||||
new ApplicationPrivilege("myapp", "read", Arrays.asList("data:read/*", "action:login"), metadata);
|
new ApplicationPrivilege("myapp", "read", Arrays.asList("data:read/*", "action:login"), metadata);
|
||||||
assertThat(privilege, equalTo(expectedPrivilege));
|
assertThat(privilege, equalTo(expectedPrivilege));
|
||||||
|
|
||||||
|
XContentBuilder builder = privilege.toXContent(XContentFactory.jsonBuilder().prettyPrint(), ToXContent.EMPTY_PARAMS);
|
||||||
|
String toJson = Strings.toString(builder);
|
||||||
|
assertThat(toJson, equalTo(json));
|
||||||
}
|
}
|
||||||
|
|
||||||
public void testEmptyApplicationName() {
|
public void testEmptyApplicationName() {
|
||||||
|
|
|
@ -0,0 +1,39 @@
|
||||||
|
--
|
||||||
|
:api: put-privileges
|
||||||
|
:request: PutPrivilegesRequest
|
||||||
|
:response: PutPrivilegesResponse
|
||||||
|
--
|
||||||
|
|
||||||
|
[id="{upid}-{api}"]
|
||||||
|
=== Put Privileges API
|
||||||
|
|
||||||
|
Application privileges can be created or updated using this API.
|
||||||
|
|
||||||
|
[id="{upid}-{api}-request"]
|
||||||
|
==== Put Privileges Request
|
||||||
|
A +{request}+ contains list of application privileges that
|
||||||
|
need to be created or updated. Each application privilege
|
||||||
|
consists of an application name, application privilege,
|
||||||
|
set of actions and optional metadata.
|
||||||
|
|
||||||
|
["source","java",subs="attributes,callouts,macros"]
|
||||||
|
--------------------------------------------------
|
||||||
|
include-tagged::{doc-tests-file}[{api}-request]
|
||||||
|
--------------------------------------------------
|
||||||
|
|
||||||
|
include::../execution.asciidoc[]
|
||||||
|
|
||||||
|
[id="{upid}-{api}-response"]
|
||||||
|
==== Put Privileges Response
|
||||||
|
|
||||||
|
The returned +{response}+ contains the information about the status
|
||||||
|
for each privilege present in the +{request}+. The status would be
|
||||||
|
`true` if the privilege was created, `false` if the privilege was updated.
|
||||||
|
|
||||||
|
["source","java",subs="attributes,callouts,macros"]
|
||||||
|
--------------------------------------------------
|
||||||
|
include-tagged::{doc-tests-file}[{api}-response]
|
||||||
|
--------------------------------------------------
|
||||||
|
<1> The response contains the status for given application name and
|
||||||
|
privilege name. The status would be `true` if the privilege was created,
|
||||||
|
`false` if the privilege was updated.
|
|
@ -398,6 +398,7 @@ The Java High Level REST Client supports the following Security APIs:
|
||||||
* <<java-rest-high-security-create-token>>
|
* <<java-rest-high-security-create-token>>
|
||||||
* <<{upid}-invalidate-token>>
|
* <<{upid}-invalidate-token>>
|
||||||
* <<{upid}-get-privileges>>
|
* <<{upid}-get-privileges>>
|
||||||
|
* <<{upid}-put-privileges>>
|
||||||
* <<{upid}-delete-privileges>>
|
* <<{upid}-delete-privileges>>
|
||||||
|
|
||||||
include::security/put-user.asciidoc[]
|
include::security/put-user.asciidoc[]
|
||||||
|
@ -419,6 +420,7 @@ include::security/get-role-mappings.asciidoc[]
|
||||||
include::security/delete-role-mapping.asciidoc[]
|
include::security/delete-role-mapping.asciidoc[]
|
||||||
include::security/create-token.asciidoc[]
|
include::security/create-token.asciidoc[]
|
||||||
include::security/invalidate-token.asciidoc[]
|
include::security/invalidate-token.asciidoc[]
|
||||||
|
include::security/put-privileges.asciidoc[]
|
||||||
|
|
||||||
== Watcher APIs
|
== Watcher APIs
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue