HLRC: Implement get-user-privileges API (#36292)
This adds the _security/user/_privileges API to the High Level Rest Client. This also makes some changes to the Java model for the Role APIs in order to better accommodate the GetPrivileges API
This commit is contained in:
parent
03daad9812
commit
143f151185
|
@ -48,6 +48,8 @@ import org.elasticsearch.client.security.GetRolesRequest;
|
|||
import org.elasticsearch.client.security.GetRolesResponse;
|
||||
import org.elasticsearch.client.security.GetSslCertificatesRequest;
|
||||
import org.elasticsearch.client.security.GetSslCertificatesResponse;
|
||||
import org.elasticsearch.client.security.GetUserPrivilegesRequest;
|
||||
import org.elasticsearch.client.security.GetUserPrivilegesResponse;
|
||||
import org.elasticsearch.client.security.HasPrivilegesRequest;
|
||||
import org.elasticsearch.client.security.HasPrivilegesResponse;
|
||||
import org.elasticsearch.client.security.InvalidateTokenRequest;
|
||||
|
@ -311,6 +313,25 @@ public final class SecurityClient {
|
|||
HasPrivilegesResponse::fromXContent, listener, emptySet());
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve the set of effective privileges held by the current user.
|
||||
* @param options the request options (e.g. headers), use {@link RequestOptions#DEFAULT} if nothing needs to be customized
|
||||
*/
|
||||
public GetUserPrivilegesResponse getUserPrivileges(RequestOptions options) throws IOException {
|
||||
return restHighLevelClient.performRequestAndParseEntity(GetUserPrivilegesRequest.INSTANCE, GetUserPrivilegesRequest::getRequest,
|
||||
options, GetUserPrivilegesResponse::fromXContent, emptySet());
|
||||
}
|
||||
|
||||
/**
|
||||
* Asynchronously retrieve the set of effective privileges held by the current user.
|
||||
* @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 getUserPrivilegesAsync(RequestOptions options, ActionListener<GetUserPrivilegesResponse> listener) {
|
||||
restHighLevelClient.performRequestAsyncAndParseEntity(GetUserPrivilegesRequest.INSTANCE, GetUserPrivilegesRequest::getRequest,
|
||||
options, GetUserPrivilegesResponse::fromXContent, listener, emptySet());
|
||||
}
|
||||
|
||||
/**
|
||||
* Clears the cache in one or more realms.
|
||||
* See <a href="https://www.elastic.co/guide/en/elasticsearch/reference/current/security-api-clear-cache.html">
|
||||
|
@ -697,5 +718,4 @@ public final class SecurityClient {
|
|||
restHighLevelClient.performRequestAsyncAndParseEntity(request, SecurityRequestConverters::deletePrivileges, options,
|
||||
DeletePrivilegesResponse::fromXContent, listener, singleton(404));
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -0,0 +1,41 @@
|
|||
/*
|
||||
* Licensed to Elasticsearch under one or more contributor
|
||||
* license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright
|
||||
* ownership. Elasticsearch licenses this file to you under
|
||||
* the Apache License, Version 2.0 (the "License"); you may
|
||||
* not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
package org.elasticsearch.client.security;
|
||||
|
||||
import org.apache.http.client.methods.HttpGet;
|
||||
import org.elasticsearch.client.Request;
|
||||
import org.elasticsearch.client.RequestOptions;
|
||||
import org.elasticsearch.client.Validatable;
|
||||
|
||||
/**
|
||||
* A request object for the {@link org.elasticsearch.client.SecurityClient#getUserPrivileges(RequestOptions)} API.
|
||||
* This request takes no parameters, and has a singleton {@link #INSTANCE}.
|
||||
*/
|
||||
public class GetUserPrivilegesRequest implements Validatable {
|
||||
|
||||
public static final GetUserPrivilegesRequest INSTANCE = new GetUserPrivilegesRequest();
|
||||
|
||||
private GetUserPrivilegesRequest() {
|
||||
}
|
||||
|
||||
public Request getRequest() {
|
||||
return new Request(HttpGet.METHOD_NAME, "/_security/user/_privileges");
|
||||
}
|
||||
}
|
|
@ -0,0 +1,141 @@
|
|||
/*
|
||||
* 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.RequestOptions;
|
||||
import org.elasticsearch.client.security.user.privileges.ApplicationResourcePrivileges;
|
||||
import org.elasticsearch.client.security.user.privileges.GlobalPrivileges;
|
||||
import org.elasticsearch.client.security.user.privileges.UserIndicesPrivileges;
|
||||
import org.elasticsearch.common.ParseField;
|
||||
import org.elasticsearch.common.xcontent.ConstructingObjectParser;
|
||||
import org.elasticsearch.common.xcontent.XContentParser;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.LinkedHashSet;
|
||||
import java.util.Objects;
|
||||
import java.util.Set;
|
||||
|
||||
import static org.elasticsearch.common.xcontent.ConstructingObjectParser.constructorArg;
|
||||
|
||||
/**
|
||||
* The response for the {@link org.elasticsearch.client.SecurityClient#getUserPrivileges(RequestOptions)} API.
|
||||
* See <a href="https://www.elastic.co/guide/en/elasticsearch/reference/current/security-api-get-user-privileges.html">the API docs</a>
|
||||
*/
|
||||
public class GetUserPrivilegesResponse {
|
||||
|
||||
private static final ConstructingObjectParser<GetUserPrivilegesResponse, Void> PARSER = new ConstructingObjectParser<>(
|
||||
"get_user_privileges_response", true, GetUserPrivilegesResponse::buildResponseFromParserArgs);
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private static GetUserPrivilegesResponse buildResponseFromParserArgs(Object[] args) {
|
||||
return new GetUserPrivilegesResponse(
|
||||
(Collection<String>) args[0],
|
||||
(Collection<GlobalPrivileges>) args[1],
|
||||
(Collection<UserIndicesPrivileges>) args[2],
|
||||
(Collection<ApplicationResourcePrivileges>) args[3],
|
||||
(Collection<String>) args[4]
|
||||
);
|
||||
}
|
||||
|
||||
static {
|
||||
PARSER.declareStringArray(constructorArg(), new ParseField("cluster"));
|
||||
PARSER.declareObjectArray(constructorArg(), (parser, ignore) -> GlobalPrivileges.fromXContent(parser),
|
||||
new ParseField("global"));
|
||||
PARSER.declareObjectArray(constructorArg(), (parser, ignore) -> UserIndicesPrivileges.fromXContent(parser),
|
||||
new ParseField("indices"));
|
||||
PARSER.declareObjectArray(constructorArg(), (parser, ignore) -> ApplicationResourcePrivileges.fromXContent(parser),
|
||||
new ParseField("applications"));
|
||||
PARSER.declareStringArray(constructorArg(), new ParseField("run_as"));
|
||||
}
|
||||
|
||||
public static GetUserPrivilegesResponse fromXContent(XContentParser parser) throws IOException {
|
||||
return PARSER.parse(parser, null);
|
||||
}
|
||||
|
||||
private Set<String> clusterPrivileges;
|
||||
private Set<GlobalPrivileges> globalPrivileges;
|
||||
private Set<UserIndicesPrivileges> indicesPrivileges;
|
||||
private Set<ApplicationResourcePrivileges> applicationPrivileges;
|
||||
private Set<String> runAsPrivilege;
|
||||
|
||||
public GetUserPrivilegesResponse(Collection<String> clusterPrivileges, Collection<GlobalPrivileges> globalPrivileges,
|
||||
Collection<UserIndicesPrivileges> indicesPrivileges,
|
||||
Collection<ApplicationResourcePrivileges> applicationPrivileges, Collection<String> runAsPrivilege) {
|
||||
this.clusterPrivileges = Collections.unmodifiableSet(new LinkedHashSet<>(clusterPrivileges));
|
||||
this.globalPrivileges = Collections.unmodifiableSet(new LinkedHashSet<>(globalPrivileges));
|
||||
this.indicesPrivileges = Collections.unmodifiableSet(new LinkedHashSet<>(indicesPrivileges));
|
||||
this.applicationPrivileges = Collections.unmodifiableSet(new LinkedHashSet<>(applicationPrivileges));
|
||||
this.runAsPrivilege = Collections.unmodifiableSet(new LinkedHashSet<>(runAsPrivilege));
|
||||
}
|
||||
|
||||
public Set<String> getClusterPrivileges() {
|
||||
return clusterPrivileges;
|
||||
}
|
||||
|
||||
public Set<GlobalPrivileges> getGlobalPrivileges() {
|
||||
return globalPrivileges;
|
||||
}
|
||||
|
||||
public Set<UserIndicesPrivileges> getIndicesPrivileges() {
|
||||
return indicesPrivileges;
|
||||
}
|
||||
|
||||
public Set<ApplicationResourcePrivileges> getApplicationPrivileges() {
|
||||
return applicationPrivileges;
|
||||
}
|
||||
|
||||
public Set<String> getRunAsPrivilege() {
|
||||
return runAsPrivilege;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "GetUserPrivilegesResponse{" +
|
||||
"clusterPrivileges=" + clusterPrivileges +
|
||||
", globalPrivileges=" + globalPrivileges +
|
||||
", indicesPrivileges=" + indicesPrivileges +
|
||||
", applicationPrivileges=" + applicationPrivileges +
|
||||
", runAsPrivilege=" + runAsPrivilege +
|
||||
'}';
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) {
|
||||
return true;
|
||||
}
|
||||
if (o == null || getClass() != o.getClass()) {
|
||||
return false;
|
||||
}
|
||||
final GetUserPrivilegesResponse that = (GetUserPrivilegesResponse) o;
|
||||
return Objects.equals(this.clusterPrivileges, that.clusterPrivileges) &&
|
||||
Objects.equals(this.globalPrivileges, that.globalPrivileges) &&
|
||||
Objects.equals(this.indicesPrivileges, that.indicesPrivileges) &&
|
||||
Objects.equals(this.applicationPrivileges, that.applicationPrivileges) &&
|
||||
Objects.equals(this.runAsPrivilege, that.runAsPrivilege);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(clusterPrivileges, globalPrivileges, indicesPrivileges, applicationPrivileges, runAsPrivilege);
|
||||
}
|
||||
}
|
|
@ -74,14 +74,14 @@ public final class PutRoleRequest implements Validatable, ToXContentObject {
|
|||
@Override
|
||||
public XContentBuilder toXContent(XContentBuilder builder, Params params) throws IOException {
|
||||
builder.startObject();
|
||||
if (role.getApplicationResourcePrivileges() != null) {
|
||||
builder.field(Role.APPLICATIONS.getPreferredName(), role.getApplicationResourcePrivileges());
|
||||
if (role.getApplicationPrivileges() != null) {
|
||||
builder.field(Role.APPLICATIONS.getPreferredName(), role.getApplicationPrivileges());
|
||||
}
|
||||
if (role.getClusterPrivileges() != null) {
|
||||
builder.field(Role.CLUSTER.getPreferredName(), role.getClusterPrivileges());
|
||||
}
|
||||
if (role.getGlobalApplicationPrivileges() != null) {
|
||||
builder.field(Role.GLOBAL.getPreferredName(), role.getGlobalApplicationPrivileges());
|
||||
if (role.getGlobalPrivileges() != null) {
|
||||
builder.field(Role.GLOBAL.getPreferredName(), role.getGlobalPrivileges());
|
||||
}
|
||||
if (role.getIndicesPrivileges() != null) {
|
||||
builder.field(Role.INDICES.getPreferredName(), role.getIndicesPrivileges());
|
||||
|
|
|
@ -0,0 +1,199 @@
|
|||
/*
|
||||
* 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.ParseField;
|
||||
import org.elasticsearch.common.xcontent.ConstructingObjectParser;
|
||||
import org.elasticsearch.common.xcontent.ToXContentObject;
|
||||
import org.elasticsearch.common.xcontent.XContentBuilder;
|
||||
import org.elasticsearch.common.xcontent.XContentHelper;
|
||||
import org.elasticsearch.common.xcontent.XContentParser;
|
||||
import org.elasticsearch.common.xcontent.XContentType;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.UncheckedIOException;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.HashSet;
|
||||
import java.util.Objects;
|
||||
import java.util.Set;
|
||||
|
||||
import static org.elasticsearch.common.xcontent.ConstructingObjectParser.optionalConstructorArg;
|
||||
|
||||
public abstract class AbstractIndicesPrivileges {
|
||||
static final ParseField NAMES = new ParseField("names");
|
||||
static final ParseField PRIVILEGES = new ParseField("privileges");
|
||||
static final ParseField FIELD_PERMISSIONS = new ParseField("field_security");
|
||||
static final ParseField QUERY = new ParseField("query");
|
||||
|
||||
protected final Set<String> indices;
|
||||
protected final Set<String> privileges;
|
||||
|
||||
AbstractIndicesPrivileges(Collection<String> indices, Collection<String> privileges) {
|
||||
if (null == indices || indices.isEmpty()) {
|
||||
throw new IllegalArgumentException("indices privileges must refer to at least one index name or index name pattern");
|
||||
}
|
||||
if (null == privileges || privileges.isEmpty()) {
|
||||
throw new IllegalArgumentException("indices privileges must define at least one privilege");
|
||||
}
|
||||
this.indices = Collections.unmodifiableSet(new HashSet<>(indices));
|
||||
this.privileges = Collections.unmodifiableSet(new HashSet<>(privileges));
|
||||
}
|
||||
|
||||
/**
|
||||
* The indices names covered by the privileges.
|
||||
*/
|
||||
public Set<String> getIndices() {
|
||||
return this.indices;
|
||||
}
|
||||
|
||||
/**
|
||||
* The privileges acting over indices. There is a canonical predefined set of
|
||||
* such privileges, but the {@code String} datatype allows for flexibility in defining
|
||||
* finer grained privileges.
|
||||
*/
|
||||
public Set<String> getPrivileges() {
|
||||
return this.privileges;
|
||||
}
|
||||
|
||||
/**
|
||||
* If {@code true} some documents might not be visible. Only the documents
|
||||
* matching {@code query} will be readable.
|
||||
*/
|
||||
public abstract boolean isUsingDocumentLevelSecurity();
|
||||
|
||||
/**
|
||||
* If {@code true} some document fields might not be visible.
|
||||
*/
|
||||
public abstract boolean isUsingFieldLevelSecurity();
|
||||
|
||||
public static class FieldSecurity implements ToXContentObject {
|
||||
static final ParseField GRANT_FIELDS = new ParseField("grant");
|
||||
static final ParseField EXCEPT_FIELDS = new ParseField("except");
|
||||
|
||||
private static final ConstructingObjectParser<IndicesPrivileges.FieldSecurity, Void> PARSER = new ConstructingObjectParser<>(
|
||||
FIELD_PERMISSIONS.getPreferredName(), true, FieldSecurity::buildObjectFromParserArgs);
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private static FieldSecurity buildObjectFromParserArgs(Object[] args) {
|
||||
return new FieldSecurity(
|
||||
(Collection<String>) args[0],
|
||||
(Collection<String>) args[1]
|
||||
);
|
||||
}
|
||||
|
||||
static {
|
||||
PARSER.declareStringArray(optionalConstructorArg(), GRANT_FIELDS);
|
||||
PARSER.declareStringArray(optionalConstructorArg(), EXCEPT_FIELDS);
|
||||
}
|
||||
|
||||
static FieldSecurity parse(XContentParser parser, Void context) throws IOException {
|
||||
return PARSER.parse(parser, context);
|
||||
}
|
||||
|
||||
// null or singleton '*' means all fields are granted, empty means no fields are granted
|
||||
private final Set<String> grantedFields;
|
||||
// null or empty means no fields are denied
|
||||
private final Set<String> deniedFields;
|
||||
|
||||
FieldSecurity(Collection<String> grantedFields, Collection<String> deniedFields) {
|
||||
// unspecified granted fields means no restriction
|
||||
this.grantedFields = grantedFields == null ? null : Collections.unmodifiableSet(new HashSet<>(grantedFields));
|
||||
// unspecified denied fields means no restriction
|
||||
this.deniedFields = deniedFields == null ? null : Collections.unmodifiableSet(new HashSet<>(deniedFields));
|
||||
}
|
||||
|
||||
/**
|
||||
* The document fields that can be read or queried. Can be null, in this case
|
||||
* all the document's fields are granted access to. Can also be empty, in which
|
||||
* case no fields are granted access to.
|
||||
*/
|
||||
public Set<String> getGrantedFields() {
|
||||
return grantedFields;
|
||||
}
|
||||
|
||||
/**
|
||||
* The document fields that cannot be accessed or queried. Can be null or empty,
|
||||
* in which case no fields are denied.
|
||||
*/
|
||||
public Set<String> getDeniedFields() {
|
||||
return deniedFields;
|
||||
}
|
||||
|
||||
public boolean isUsingFieldLevelSecurity() {
|
||||
return limitsGrantedFields() || hasDeniedFields();
|
||||
}
|
||||
|
||||
private boolean hasDeniedFields() {
|
||||
return deniedFields != null && false == deniedFields.isEmpty();
|
||||
}
|
||||
|
||||
private boolean limitsGrantedFields() {
|
||||
// we treat just '*' as no FLS since that's what the UI defaults to
|
||||
if (grantedFields == null || (grantedFields.size() == 1 && grantedFields.iterator().next().equals("*"))) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public XContentBuilder toXContent(XContentBuilder builder, Params params) throws IOException {
|
||||
builder.startObject();
|
||||
if (grantedFields == null) {
|
||||
// The role parser will reject a field_security object that doesn't have a "granted" field
|
||||
builder.field(GRANT_FIELDS.getPreferredName(), Collections.singletonList("*"));
|
||||
} else {
|
||||
builder.field(GRANT_FIELDS.getPreferredName(), grantedFields);
|
||||
}
|
||||
if (deniedFields != null) {
|
||||
builder.field(EXCEPT_FIELDS.getPreferredName(), deniedFields);
|
||||
}
|
||||
return builder.endObject();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
try {
|
||||
return XContentHelper.toXContent(this, XContentType.JSON, true).utf8ToString();
|
||||
} catch (IOException e) {
|
||||
throw new UncheckedIOException("Unexpected", e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) {
|
||||
return true;
|
||||
}
|
||||
if (o == null || getClass() != o.getClass()) {
|
||||
return false;
|
||||
}
|
||||
final FieldSecurity that = (FieldSecurity) o;
|
||||
return Objects.equals(this.grantedFields, that.grantedFields) &&
|
||||
Objects.equals(this.deniedFields, that.deniedFields);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(grantedFields, deniedFields);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -20,22 +20,17 @@
|
|||
package org.elasticsearch.client.security.user.privileges;
|
||||
|
||||
import org.elasticsearch.common.Nullable;
|
||||
import org.elasticsearch.common.ParseField;
|
||||
import org.elasticsearch.common.collect.Tuple;
|
||||
import org.elasticsearch.common.xcontent.ConstructingObjectParser;
|
||||
import org.elasticsearch.common.xcontent.ToXContentObject;
|
||||
import org.elasticsearch.common.xcontent.XContentBuilder;
|
||||
import org.elasticsearch.common.xcontent.XContentHelper;
|
||||
import org.elasticsearch.common.xcontent.XContentParser;
|
||||
import org.elasticsearch.common.xcontent.XContentType;
|
||||
import org.elasticsearch.common.xcontent.ConstructingObjectParser;
|
||||
import org.elasticsearch.common.xcontent.ToXContentObject;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.HashSet;
|
||||
import java.util.Objects;
|
||||
import java.util.Set;
|
||||
|
||||
import static org.elasticsearch.common.xcontent.ConstructingObjectParser.constructorArg;
|
||||
import static org.elasticsearch.common.xcontent.ConstructingObjectParser.optionalConstructorArg;
|
||||
|
@ -47,104 +42,44 @@ import static org.elasticsearch.common.xcontent.ConstructingObjectParser.optiona
|
|||
* This also encapsulates field and document level security privileges. These
|
||||
* allow to control what fields or documents are readable or queryable.
|
||||
*/
|
||||
public final class IndicesPrivileges implements ToXContentObject {
|
||||
|
||||
public static final ParseField NAMES = new ParseField("names");
|
||||
public static final ParseField PRIVILEGES = new ParseField("privileges");
|
||||
public static final ParseField FIELD_PERMISSIONS = new ParseField("field_security");
|
||||
public static final ParseField GRANT_FIELDS = new ParseField("grant");
|
||||
public static final ParseField EXCEPT_FIELDS = new ParseField("except");
|
||||
public static final ParseField QUERY = new ParseField("query");
|
||||
public final class IndicesPrivileges extends AbstractIndicesPrivileges implements ToXContentObject {
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
static final ConstructingObjectParser<IndicesPrivileges, Void> PARSER =
|
||||
new ConstructingObjectParser<>("indices_privileges", false, constructorObjects -> {
|
||||
int i = 0;
|
||||
final Collection<String> indices = (Collection<String>) constructorObjects[i++];
|
||||
final Collection<String> privileges = (Collection<String>) constructorObjects[i++];
|
||||
final Tuple<Collection<String>, Collection<String>> fields =
|
||||
(Tuple<Collection<String>, Collection<String>>) constructorObjects[i++];
|
||||
final Collection<String> grantFields = fields != null ? fields.v1() : null;
|
||||
final Collection<String> exceptFields = fields != null ? fields.v2() : null;
|
||||
final String query = (String) constructorObjects[i];
|
||||
return new IndicesPrivileges(indices, privileges, grantFields, exceptFields, query);
|
||||
});
|
||||
int i = 0;
|
||||
final Collection<String> indices = (Collection<String>) constructorObjects[i++];
|
||||
final Collection<String> privileges = (Collection<String>) constructorObjects[i++];
|
||||
final FieldSecurity fields = (FieldSecurity) constructorObjects[i++];
|
||||
final String query = (String) constructorObjects[i];
|
||||
return new IndicesPrivileges(indices, privileges, fields, query);
|
||||
});
|
||||
|
||||
static {
|
||||
@SuppressWarnings("unchecked")
|
||||
final ConstructingObjectParser<Tuple<Collection<String>, Collection<String>>, Void> fls_parser =
|
||||
new ConstructingObjectParser<>( "field_level_parser", false, constructorObjects -> {
|
||||
int i = 0;
|
||||
final Collection<String> grantFields = (Collection<String>) constructorObjects[i++];
|
||||
final Collection<String> exceptFields = (Collection<String>) constructorObjects[i];
|
||||
return new Tuple<>(grantFields, exceptFields);
|
||||
});
|
||||
fls_parser.declareStringArray(optionalConstructorArg(), GRANT_FIELDS);
|
||||
fls_parser.declareStringArray(optionalConstructorArg(), EXCEPT_FIELDS);
|
||||
|
||||
PARSER.declareStringArray(constructorArg(), NAMES);
|
||||
PARSER.declareStringArray(constructorArg(), PRIVILEGES);
|
||||
PARSER.declareObject(optionalConstructorArg(), fls_parser, FIELD_PERMISSIONS);
|
||||
PARSER.declareObject(optionalConstructorArg(), FieldSecurity::parse, FIELD_PERMISSIONS);
|
||||
PARSER.declareStringOrNull(optionalConstructorArg(), QUERY);
|
||||
}
|
||||
|
||||
private final Set<String> indices;
|
||||
private final Set<String> privileges;
|
||||
// null or singleton '*' means all fields are granted, empty means no fields are granted
|
||||
private final @Nullable Set<String> grantedFields;
|
||||
// null or empty means no fields are denied
|
||||
private final @Nullable Set<String> deniedFields;
|
||||
private final FieldSecurity fieldSecurity;
|
||||
// missing query means all documents, i.e. no restrictions
|
||||
private final @Nullable String query;
|
||||
|
||||
private IndicesPrivileges(Collection<String> indices, Collection<String> privileges, @Nullable Collection<String> grantedFields,
|
||||
@Nullable Collection<String> deniedFields, @Nullable String query) {
|
||||
if (null == indices || indices.isEmpty()) {
|
||||
throw new IllegalArgumentException("indices privileges must refer to at least one index name or index name pattern");
|
||||
}
|
||||
if (null == privileges || privileges.isEmpty()) {
|
||||
throw new IllegalArgumentException("indices privileges must define at least one privilege");
|
||||
}
|
||||
this.indices = Collections.unmodifiableSet(new HashSet<>(indices));
|
||||
this.privileges = Collections.unmodifiableSet(new HashSet<>(privileges));
|
||||
// unspecified granted fields means no restriction
|
||||
this.grantedFields = grantedFields == null ? null : Collections.unmodifiableSet(new HashSet<>(grantedFields));
|
||||
// unspecified denied fields means no restriction
|
||||
this.deniedFields = deniedFields == null ? null : Collections.unmodifiableSet(new HashSet<>(deniedFields));
|
||||
private IndicesPrivileges(Collection<String> indices, Collection<String> privileges, @Nullable FieldSecurity fieldSecurity,
|
||||
@Nullable String query) {
|
||||
super(indices, privileges);
|
||||
this.fieldSecurity = fieldSecurity;
|
||||
this.query = query;
|
||||
}
|
||||
|
||||
/**
|
||||
* The indices names covered by the privileges.
|
||||
* The combination of the {@link FieldSecurity#getGrantedFields() granted} and
|
||||
* {@link FieldSecurity#getDeniedFields() denied} document fields.
|
||||
* May be null, in which case no field level security is applicable, and all the document's fields are granted access to.
|
||||
*/
|
||||
public Set<String> getIndices() {
|
||||
return this.indices;
|
||||
}
|
||||
|
||||
/**
|
||||
* The privileges acting over indices. There is a canonical predefined set of
|
||||
* such privileges, but the {@code String} datatype allows for flexibility in defining
|
||||
* finer grained privileges.
|
||||
*/
|
||||
public Set<String> getPrivileges() {
|
||||
return this.privileges;
|
||||
}
|
||||
|
||||
/**
|
||||
* The document fields that can be read or queried. Can be null, in this case
|
||||
* all the document's fields are granted access to. Can also be empty, in which
|
||||
* case no fields are granted access to.
|
||||
*/
|
||||
public @Nullable Set<String> getGrantedFields() {
|
||||
return this.grantedFields;
|
||||
}
|
||||
|
||||
/**
|
||||
* The document fields that cannot be accessed or queried. Can be null or empty,
|
||||
* in which case no fields are denied.
|
||||
*/
|
||||
public @Nullable Set<String> getDeniedFields() {
|
||||
return this.deniedFields;
|
||||
public FieldSecurity getFieldSecurity() {
|
||||
return fieldSecurity;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -159,6 +94,7 @@ public final class IndicesPrivileges implements ToXContentObject {
|
|||
* If {@code true} some documents might not be visible. Only the documents
|
||||
* matching {@code query} will be readable.
|
||||
*/
|
||||
@Override
|
||||
public boolean isUsingDocumentLevelSecurity() {
|
||||
return query != null;
|
||||
}
|
||||
|
@ -166,20 +102,9 @@ public final class IndicesPrivileges implements ToXContentObject {
|
|||
/**
|
||||
* If {@code true} some document fields might not be visible.
|
||||
*/
|
||||
@Override
|
||||
public boolean isUsingFieldLevelSecurity() {
|
||||
return limitsGrantedFields() || hasDeniedFields();
|
||||
}
|
||||
|
||||
private boolean hasDeniedFields() {
|
||||
return deniedFields != null && false == deniedFields.isEmpty();
|
||||
}
|
||||
|
||||
private boolean limitsGrantedFields() {
|
||||
// we treat just '*' as no FLS since that's what the UI defaults to
|
||||
if (grantedFields == null || (grantedFields.size() == 1 && grantedFields.iterator().next().equals("*"))) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
return fieldSecurity != null && fieldSecurity.isUsingFieldLevelSecurity();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -192,15 +117,14 @@ public final class IndicesPrivileges implements ToXContentObject {
|
|||
}
|
||||
IndicesPrivileges that = (IndicesPrivileges) o;
|
||||
return indices.equals(that.indices)
|
||||
&& privileges.equals(that.privileges)
|
||||
&& Objects.equals(grantedFields, that.grantedFields)
|
||||
&& Objects.equals(deniedFields, that.deniedFields)
|
||||
&& Objects.equals(query, that.query);
|
||||
&& privileges.equals(that.privileges)
|
||||
&& Objects.equals(this.fieldSecurity, that.fieldSecurity)
|
||||
&& Objects.equals(query, that.query);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(indices, privileges, grantedFields, deniedFields, query);
|
||||
return Objects.hash(indices, privileges, fieldSecurity, query);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -217,15 +141,8 @@ public final class IndicesPrivileges implements ToXContentObject {
|
|||
builder.startObject();
|
||||
builder.field(NAMES.getPreferredName(), indices);
|
||||
builder.field(PRIVILEGES.getPreferredName(), privileges);
|
||||
if (grantedFields != null || deniedFields != null) {
|
||||
builder.startObject(FIELD_PERMISSIONS.getPreferredName());
|
||||
if (grantedFields != null) {
|
||||
builder.field(GRANT_FIELDS.getPreferredName(), grantedFields);
|
||||
}
|
||||
if (deniedFields != null) {
|
||||
builder.field(EXCEPT_FIELDS.getPreferredName(), deniedFields);
|
||||
}
|
||||
builder.endObject();
|
||||
if (fieldSecurity != null) {
|
||||
builder.field(FIELD_PERMISSIONS.getPreferredName(), fieldSecurity, params);
|
||||
}
|
||||
if (isUsingDocumentLevelSecurity()) {
|
||||
builder.field("query", query);
|
||||
|
@ -243,11 +160,16 @@ public final class IndicesPrivileges implements ToXContentObject {
|
|||
|
||||
public static final class Builder {
|
||||
|
||||
private @Nullable Collection<String> indices = null;
|
||||
private @Nullable Collection<String> privileges = null;
|
||||
private @Nullable Collection<String> grantedFields = null;
|
||||
private @Nullable Collection<String> deniedFields = null;
|
||||
private @Nullable String query = null;
|
||||
private @Nullable
|
||||
Collection<String> indices = null;
|
||||
private @Nullable
|
||||
Collection<String> privileges = null;
|
||||
private @Nullable
|
||||
Collection<String> grantedFields = null;
|
||||
private @Nullable
|
||||
Collection<String> deniedFields = null;
|
||||
private @Nullable
|
||||
String query = null;
|
||||
|
||||
public Builder() {
|
||||
}
|
||||
|
@ -255,7 +177,7 @@ public final class IndicesPrivileges implements ToXContentObject {
|
|||
public Builder indices(String... indices) {
|
||||
return indices(Arrays.asList(Objects.requireNonNull(indices, "indices required")));
|
||||
}
|
||||
|
||||
|
||||
public Builder indices(Collection<String> indices) {
|
||||
this.indices = Objects.requireNonNull(indices, "indices required");
|
||||
return this;
|
||||
|
@ -302,7 +224,13 @@ public final class IndicesPrivileges implements ToXContentObject {
|
|||
}
|
||||
|
||||
public IndicesPrivileges build() {
|
||||
return new IndicesPrivileges(indices, privileges, grantedFields, deniedFields, query);
|
||||
final FieldSecurity fieldSecurity;
|
||||
if (grantedFields == null && deniedFields == null) {
|
||||
fieldSecurity = null;
|
||||
} else {
|
||||
fieldSecurity = new FieldSecurity(grantedFields, deniedFields);
|
||||
}
|
||||
return new IndicesPrivileges(indices, privileges, fieldSecurity, query);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -85,16 +85,16 @@ public final class Role {
|
|||
|
||||
private final String name;
|
||||
private final Set<String> clusterPrivileges;
|
||||
private final @Nullable GlobalPrivileges globalApplicationPrivileges;
|
||||
private final @Nullable GlobalPrivileges globalPrivileges;
|
||||
private final Set<IndicesPrivileges> indicesPrivileges;
|
||||
private final Set<ApplicationResourcePrivileges> applicationResourcePrivileges;
|
||||
private final Set<ApplicationResourcePrivileges> applicationPrivileges;
|
||||
private final Set<String> runAsPrivilege;
|
||||
private final Map<String, Object> metadata;
|
||||
|
||||
private Role(String name, @Nullable Collection<String> clusterPrivileges,
|
||||
@Nullable GlobalPrivileges globalApplicationPrivileges,
|
||||
@Nullable GlobalPrivileges globalPrivileges,
|
||||
@Nullable Collection<IndicesPrivileges> indicesPrivileges,
|
||||
@Nullable Collection<ApplicationResourcePrivileges> applicationResourcePrivileges,
|
||||
@Nullable Collection<ApplicationResourcePrivileges> applicationPrivileges,
|
||||
@Nullable Collection<String> runAsPrivilege, @Nullable Map<String, Object> metadata) {
|
||||
if (Strings.hasText(name) == false){
|
||||
throw new IllegalArgumentException("role name must be provided");
|
||||
|
@ -104,13 +104,13 @@ public final class Role {
|
|||
// no cluster privileges are granted unless otherwise specified
|
||||
this.clusterPrivileges = Collections
|
||||
.unmodifiableSet(clusterPrivileges != null ? new HashSet<>(clusterPrivileges) : Collections.emptySet());
|
||||
this.globalApplicationPrivileges = globalApplicationPrivileges;
|
||||
this.globalPrivileges = globalPrivileges;
|
||||
// no indices privileges are granted unless otherwise specified
|
||||
this.indicesPrivileges = Collections
|
||||
.unmodifiableSet(indicesPrivileges != null ? new HashSet<>(indicesPrivileges) : Collections.emptySet());
|
||||
// no application resource privileges are granted unless otherwise specified
|
||||
this.applicationResourcePrivileges = Collections.unmodifiableSet(
|
||||
applicationResourcePrivileges != null ? new HashSet<>(applicationResourcePrivileges) : Collections.emptySet());
|
||||
this.applicationPrivileges = Collections.unmodifiableSet(
|
||||
applicationPrivileges != null ? new HashSet<>(applicationPrivileges) : Collections.emptySet());
|
||||
// no run as privileges are granted unless otherwise specified
|
||||
this.runAsPrivilege = Collections.unmodifiableSet(runAsPrivilege != null ? new HashSet<>(runAsPrivilege) : Collections.emptySet());
|
||||
this.metadata = metadata != null ? Collections.unmodifiableMap(metadata) : Collections.emptyMap();
|
||||
|
@ -124,16 +124,16 @@ public final class Role {
|
|||
return clusterPrivileges;
|
||||
}
|
||||
|
||||
public GlobalPrivileges getGlobalApplicationPrivileges() {
|
||||
return globalApplicationPrivileges;
|
||||
public GlobalPrivileges getGlobalPrivileges() {
|
||||
return globalPrivileges;
|
||||
}
|
||||
|
||||
public Set<IndicesPrivileges> getIndicesPrivileges() {
|
||||
return indicesPrivileges;
|
||||
}
|
||||
|
||||
public Set<ApplicationResourcePrivileges> getApplicationResourcePrivileges() {
|
||||
return applicationResourcePrivileges;
|
||||
public Set<ApplicationResourcePrivileges> getApplicationPrivileges() {
|
||||
return applicationPrivileges;
|
||||
}
|
||||
|
||||
public Set<String> getRunAsPrivilege() {
|
||||
|
@ -151,16 +151,16 @@ public final class Role {
|
|||
Role that = (Role) o;
|
||||
return name.equals(that.name)
|
||||
&& clusterPrivileges.equals(that.clusterPrivileges)
|
||||
&& Objects.equals(globalApplicationPrivileges, that.globalApplicationPrivileges)
|
||||
&& Objects.equals(globalPrivileges, that.globalPrivileges)
|
||||
&& indicesPrivileges.equals(that.indicesPrivileges)
|
||||
&& applicationResourcePrivileges.equals(that.applicationResourcePrivileges)
|
||||
&& applicationPrivileges.equals(that.applicationPrivileges)
|
||||
&& runAsPrivilege.equals(that.runAsPrivilege)
|
||||
&& metadata.equals(that.metadata);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(name, clusterPrivileges, globalApplicationPrivileges, indicesPrivileges, applicationResourcePrivileges,
|
||||
return Objects.hash(name, clusterPrivileges, globalPrivileges, indicesPrivileges, applicationPrivileges,
|
||||
runAsPrivilege, metadata);
|
||||
}
|
||||
|
||||
|
@ -173,9 +173,9 @@ public final class Role {
|
|||
sb.append(clusterPrivileges.toString());
|
||||
sb.append(", ");
|
||||
}
|
||||
if (globalApplicationPrivileges != null) {
|
||||
sb.append("GlobalApplcationPrivileges=");
|
||||
sb.append(globalApplicationPrivileges.toString());
|
||||
if (globalPrivileges != null) {
|
||||
sb.append("GlobalPrivileges=");
|
||||
sb.append(globalPrivileges.toString());
|
||||
sb.append(", ");
|
||||
}
|
||||
if (false == indicesPrivileges.isEmpty()) {
|
||||
|
@ -183,9 +183,9 @@ public final class Role {
|
|||
sb.append(indicesPrivileges.toString());
|
||||
sb.append(", ");
|
||||
}
|
||||
if (false == applicationResourcePrivileges.isEmpty()) {
|
||||
if (false == applicationPrivileges.isEmpty()) {
|
||||
sb.append("ApplicationPrivileges=");
|
||||
sb.append(applicationResourcePrivileges.toString());
|
||||
sb.append(applicationPrivileges.toString());
|
||||
sb.append(", ");
|
||||
}
|
||||
if (false == runAsPrivilege.isEmpty()) {
|
||||
|
|
|
@ -0,0 +1,135 @@
|
|||
/*
|
||||
* 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.client.security.GetUserPrivilegesResponse;
|
||||
import org.elasticsearch.common.xcontent.ConstructingObjectParser;
|
||||
import org.elasticsearch.common.xcontent.XContentParser;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
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 "index" privilege in the {@link GetUserPrivilegesResponse}. This differs from the
|
||||
* {@link org.elasticsearch.client.security.user.privileges.IndicesPrivileges}" object in a
|
||||
* {@link org.elasticsearch.client.security.user.privileges.Role}
|
||||
* as it supports an array value for {@link #getFieldSecurity() field_security} and {@link #getQueries() query}.
|
||||
* See <a href="https://www.elastic.co/guide/en/elasticsearch/reference/current/security-api-get-user-privileges.html">the API docs</a>
|
||||
*/
|
||||
public class UserIndicesPrivileges extends AbstractIndicesPrivileges {
|
||||
|
||||
private final Set<IndicesPrivileges.FieldSecurity> fieldSecurity;
|
||||
private final Set<String> query;
|
||||
|
||||
private static final ConstructingObjectParser<UserIndicesPrivileges, Void> PARSER = new ConstructingObjectParser<>(
|
||||
"user_indices_privilege", true, UserIndicesPrivileges::buildObjectFromParserArgs);
|
||||
|
||||
static {
|
||||
PARSER.declareStringArray(constructorArg(), IndicesPrivileges.NAMES);
|
||||
PARSER.declareStringArray(constructorArg(), IndicesPrivileges.PRIVILEGES);
|
||||
PARSER.declareObjectArray(optionalConstructorArg(), IndicesPrivileges.FieldSecurity::parse, IndicesPrivileges.FIELD_PERMISSIONS);
|
||||
PARSER.declareStringArray(optionalConstructorArg(), IndicesPrivileges.QUERY);
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private static UserIndicesPrivileges buildObjectFromParserArgs(Object[] args) {
|
||||
return new UserIndicesPrivileges(
|
||||
(List<String>) args[0],
|
||||
(List<String>) args[1],
|
||||
(List<IndicesPrivileges.FieldSecurity>) args[2],
|
||||
(List<String>) args[3]
|
||||
);
|
||||
}
|
||||
|
||||
public static UserIndicesPrivileges fromXContent(XContentParser parser) throws IOException {
|
||||
return PARSER.parse(parser, null);
|
||||
}
|
||||
|
||||
public UserIndicesPrivileges(Collection<String> indices, Collection<String> privileges,
|
||||
Collection<IndicesPrivileges.FieldSecurity> fieldSecurity, Collection<String> query) {
|
||||
super(indices, privileges);
|
||||
this.fieldSecurity = fieldSecurity == null ? Collections.emptySet() : Collections.unmodifiableSet(new HashSet<>(fieldSecurity));
|
||||
this.query = query == null ? Collections.emptySet() : Collections.unmodifiableSet(new HashSet<>(query));
|
||||
}
|
||||
|
||||
public Set<String> getIndices() {
|
||||
return indices;
|
||||
}
|
||||
|
||||
public Set<String> getPrivileges() {
|
||||
return privileges;
|
||||
}
|
||||
|
||||
public Set<IndicesPrivileges.FieldSecurity> getFieldSecurity() {
|
||||
return fieldSecurity;
|
||||
}
|
||||
|
||||
public Set<String> getQueries() {
|
||||
return query;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isUsingDocumentLevelSecurity() {
|
||||
return query.isEmpty() == false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isUsingFieldLevelSecurity() {
|
||||
return fieldSecurity.stream().anyMatch(FieldSecurity::isUsingFieldLevelSecurity);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) {
|
||||
return true;
|
||||
}
|
||||
if (o == null || getClass() != o.getClass()) {
|
||||
return false;
|
||||
}
|
||||
final UserIndicesPrivileges that = (UserIndicesPrivileges) o;
|
||||
return Objects.equals(indices, that.indices) &&
|
||||
Objects.equals(privileges, that.privileges) &&
|
||||
Objects.equals(fieldSecurity, that.fieldSecurity) &&
|
||||
Objects.equals(query, that.query);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(indices, privileges, fieldSecurity, query);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "UserIndexPrivilege{" +
|
||||
"indices=" + indices +
|
||||
", privileges=" + privileges +
|
||||
", fieldSecurity=" + fieldSecurity +
|
||||
", query=" + query +
|
||||
'}';
|
||||
}
|
||||
}
|
|
@ -20,7 +20,6 @@
|
|||
package org.elasticsearch.client;
|
||||
|
||||
import com.fasterxml.jackson.core.JsonParseException;
|
||||
|
||||
import org.apache.http.HttpEntity;
|
||||
import org.apache.http.HttpHost;
|
||||
import org.apache.http.HttpResponse;
|
||||
|
@ -60,6 +59,7 @@ import org.elasticsearch.cluster.ClusterName;
|
|||
import org.elasticsearch.common.CheckedFunction;
|
||||
import org.elasticsearch.common.bytes.BytesReference;
|
||||
import org.elasticsearch.common.collect.Tuple;
|
||||
import org.elasticsearch.common.util.set.Sets;
|
||||
import org.elasticsearch.common.xcontent.NamedXContentRegistry;
|
||||
import org.elasticsearch.common.xcontent.ToXContent;
|
||||
import org.elasticsearch.common.xcontent.XContentBuilder;
|
||||
|
@ -121,6 +121,21 @@ public class RestHighLevelClientTests extends ESTestCase {
|
|||
private static final ProtocolVersion HTTP_PROTOCOL = new ProtocolVersion("http", 1, 1);
|
||||
private static final RequestLine REQUEST_LINE = new BasicRequestLine(HttpGet.METHOD_NAME, "/", HTTP_PROTOCOL);
|
||||
|
||||
/**
|
||||
* These APIs do not use a Request object (because they don't have a body, or any request parameters).
|
||||
* The method naming/parameter assertions use this {@code Set} to determine which rules to apply.
|
||||
* (This is also used for async variants of these APIs when they exist)
|
||||
*/
|
||||
private static final Set<String> APIS_WITHOUT_REQUEST_OBJECT = Sets.newHashSet(
|
||||
// core
|
||||
"ping", "info",
|
||||
// security
|
||||
"security.get_ssl_certificates", "security.authenticate", "security.get_user_privileges",
|
||||
// license
|
||||
"license.get_trial_status", "license.get_basic_status"
|
||||
|
||||
);
|
||||
|
||||
private RestClient restClient;
|
||||
private RestHighLevelClient restHighLevelClient;
|
||||
|
||||
|
@ -783,9 +798,7 @@ public class RestHighLevelClientTests extends ESTestCase {
|
|||
|
||||
assertEquals("incorrect number of exceptions for method [" + method + "]", 1, method.getExceptionTypes().length);
|
||||
//a few methods don't accept a request object as argument
|
||||
if (apiName.equals("ping") || apiName.equals("info") || apiName.equals("security.get_ssl_certificates")
|
||||
|| apiName.equals("security.authenticate") || apiName.equals("license.get_trial_status")
|
||||
|| apiName.equals("license.get_basic_status")) {
|
||||
if (APIS_WITHOUT_REQUEST_OBJECT.contains(apiName)) {
|
||||
assertEquals("incorrect number of arguments for method [" + method + "]", 1, method.getParameterTypes().length);
|
||||
assertThat("the parameter to method [" + method + "] is the wrong type",
|
||||
method.getParameterTypes()[0], equalTo(RequestOptions.class));
|
||||
|
@ -803,7 +816,7 @@ public class RestHighLevelClientTests extends ESTestCase {
|
|||
methods.containsKey(apiName.substring(0, apiName.length() - 6)));
|
||||
assertThat("async method [" + method + "] should return void", method.getReturnType(), equalTo(Void.TYPE));
|
||||
assertEquals("async method [" + method + "] should not throw any exceptions", 0, method.getExceptionTypes().length);
|
||||
if (apiName.equals("security.authenticate_async") || apiName.equals("security.get_ssl_certificates_async")) {
|
||||
if (APIS_WITHOUT_REQUEST_OBJECT.contains(apiName.replaceAll("_async$", ""))) {
|
||||
assertEquals(2, method.getParameterTypes().length);
|
||||
assertThat(method.getParameterTypes()[0], equalTo(RequestOptions.class));
|
||||
assertThat(method.getParameterTypes()[1], equalTo(ActionListener.class));
|
||||
|
|
|
@ -53,8 +53,11 @@ import org.elasticsearch.client.security.GetRoleMappingsResponse;
|
|||
import org.elasticsearch.client.security.GetRolesRequest;
|
||||
import org.elasticsearch.client.security.GetRolesResponse;
|
||||
import org.elasticsearch.client.security.GetSslCertificatesResponse;
|
||||
import org.elasticsearch.client.security.GetUserPrivilegesResponse;
|
||||
import org.elasticsearch.client.security.HasPrivilegesRequest;
|
||||
import org.elasticsearch.client.security.HasPrivilegesResponse;
|
||||
import org.elasticsearch.client.security.user.privileges.ApplicationResourcePrivileges;
|
||||
import org.elasticsearch.client.security.user.privileges.UserIndicesPrivileges;
|
||||
import org.elasticsearch.client.security.InvalidateTokenRequest;
|
||||
import org.elasticsearch.client.security.InvalidateTokenResponse;
|
||||
import org.elasticsearch.client.security.PutPrivilegesRequest;
|
||||
|
@ -697,6 +700,66 @@ public class SecurityDocumentationIT extends ESRestHighLevelClientTestCase {
|
|||
}
|
||||
}
|
||||
|
||||
public void testGetUserPrivileges() throws Exception {
|
||||
RestHighLevelClient client = highLevelClient();
|
||||
{
|
||||
//tag::get-user-privileges-execute
|
||||
GetUserPrivilegesResponse response = client.security().getUserPrivileges(RequestOptions.DEFAULT);
|
||||
//end::get-user-privileges-execute
|
||||
|
||||
assertNotNull(response);
|
||||
//tag::get-user-privileges-response
|
||||
final Set<String> cluster = response.getClusterPrivileges();
|
||||
final Set<UserIndicesPrivileges> index = response.getIndicesPrivileges();
|
||||
final Set<ApplicationResourcePrivileges> application = response.getApplicationPrivileges();
|
||||
final Set<String> runAs = response.getRunAsPrivilege();
|
||||
//end::get-user-privileges-response
|
||||
|
||||
assertNotNull(cluster);
|
||||
assertThat(cluster, contains("all"));
|
||||
|
||||
assertNotNull(index);
|
||||
assertThat(index.size(), is(1));
|
||||
final UserIndicesPrivileges indexPrivilege = index.iterator().next();
|
||||
assertThat(indexPrivilege.getIndices(), contains("*"));
|
||||
assertThat(indexPrivilege.getPrivileges(), contains("all"));
|
||||
assertThat(indexPrivilege.getFieldSecurity().size(), is(0));
|
||||
assertThat(indexPrivilege.getQueries().size(), is(0));
|
||||
|
||||
assertNotNull(application);
|
||||
assertThat(application.size(), is(1));
|
||||
|
||||
assertNotNull(runAs);
|
||||
assertThat(runAs, contains("*"));
|
||||
}
|
||||
|
||||
{
|
||||
//tag::get-user-privileges-execute-listener
|
||||
ActionListener<GetUserPrivilegesResponse> listener = new ActionListener<GetUserPrivilegesResponse>() {
|
||||
@Override
|
||||
public void onResponse(GetUserPrivilegesResponse getUserPrivilegesResponse) {
|
||||
// <1>
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onFailure(Exception e) {
|
||||
// <2>
|
||||
}
|
||||
};
|
||||
//end::get-user-privileges-execute-listener
|
||||
|
||||
// Replace the empty listener by a blocking listener in test
|
||||
final CountDownLatch latch = new CountDownLatch(1);
|
||||
listener = new LatchedActionListener<>(listener, latch);
|
||||
|
||||
// tag::get-user-privileges-execute-async
|
||||
client.security().getUserPrivilegesAsync(RequestOptions.DEFAULT, listener); // <1>
|
||||
// end::get-user-privileges-execute-async
|
||||
|
||||
assertTrue(latch.await(30L, TimeUnit.SECONDS));
|
||||
}
|
||||
}
|
||||
|
||||
public void testClearRealmCache() throws Exception {
|
||||
RestHighLevelClient client = highLevelClient();
|
||||
{
|
||||
|
@ -1513,5 +1576,5 @@ public class SecurityDocumentationIT extends ESRestHighLevelClientTestCase {
|
|||
assertTrue(latch.await(30L, TimeUnit.SECONDS));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -0,0 +1,131 @@
|
|||
/*
|
||||
* 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.GlobalOperationPrivilege;
|
||||
import org.elasticsearch.client.security.user.privileges.IndicesPrivileges;
|
||||
import org.elasticsearch.client.security.user.privileges.UserIndicesPrivileges;
|
||||
import org.elasticsearch.common.util.iterable.Iterables;
|
||||
import org.elasticsearch.common.xcontent.XContentParser;
|
||||
import org.elasticsearch.common.xcontent.XContentType;
|
||||
import org.elasticsearch.test.ESTestCase;
|
||||
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
|
||||
import static org.hamcrest.Matchers.contains;
|
||||
import static org.hamcrest.Matchers.containsInAnyOrder;
|
||||
import static org.hamcrest.Matchers.emptyIterable;
|
||||
import static org.hamcrest.Matchers.equalTo;
|
||||
import static org.hamcrest.Matchers.instanceOf;
|
||||
import static org.hamcrest.Matchers.iterableWithSize;
|
||||
import static org.hamcrest.Matchers.nullValue;
|
||||
|
||||
public class GetUserPrivilegesResponseTests extends ESTestCase {
|
||||
|
||||
public void testParse() throws Exception {
|
||||
String json = "{" +
|
||||
"\"cluster\":[\"manage\",\"manage_security\",\"monitor\"]," +
|
||||
"\"global\":[" +
|
||||
" {\"application\":{\"manage\":{\"applications\":[\"test-*\"]}}}," +
|
||||
" {\"application\":{\"manage\":{\"applications\":[\"apps-*\"]}}}" +
|
||||
"]," +
|
||||
"\"indices\":[" +
|
||||
" {\"names\":[\"test-1-*\"],\"privileges\":[\"read\"]}," +
|
||||
" {\"names\":[\"test-4-*\"],\"privileges\":[\"read\"],\"field_security\":[{\"grant\":[\"*\"],\"except\":[\"private-*\"]}]}," +
|
||||
" {\"names\":[\"test-6-*\",\"test-7-*\"],\"privileges\":[\"read\"]," +
|
||||
" \"query\":[\"{\\\"term\\\":{\\\"test\\\":true}}\"]}," +
|
||||
" {\"names\":[\"test-2-*\"],\"privileges\":[\"read\"]," +
|
||||
" \"field_security\":[{\"grant\":[\"*\"],\"except\":[\"secret-*\",\"private-*\"]},{\"grant\":[\"apps-*\"]}]," +
|
||||
" \"query\":[\"{\\\"term\\\":{\\\"test\\\":true}}\",\"{\\\"term\\\":{\\\"apps\\\":true}}\"]}," +
|
||||
" {\"names\":[\"test-3-*\",\"test-6-*\"],\"privileges\":[\"read\",\"write\"]}," +
|
||||
" {\"names\":[\"test-3-*\",\"test-4-*\",\"test-5-*\"],\"privileges\":[\"read\"]," +
|
||||
" \"field_security\":[{\"grant\":[\"test-*\"]}]}," +
|
||||
" {\"names\":[\"test-1-*\",\"test-9-*\"],\"privileges\":[\"all\"]}" +
|
||||
"]," +
|
||||
"\"applications\":[" +
|
||||
" {\"application\":\"app-dne\",\"privileges\":[\"all\"],\"resources\":[\"*\"]}," +
|
||||
" {\"application\":\"test-app\",\"privileges\":[\"read\"],\"resources\":[\"object/1\",\"object/2\"]}," +
|
||||
" {\"application\":\"test-app\",\"privileges\":[\"user\",\"dne\"],\"resources\":[\"*\"]}" +
|
||||
"]," +
|
||||
"\"run_as\":[\"app-*\",\"test-*\"]}";
|
||||
final XContentParser parser = createParser(XContentType.JSON.xContent(), json);
|
||||
final GetUserPrivilegesResponse response = GetUserPrivilegesResponse.fromXContent(parser);
|
||||
|
||||
assertThat(response.getClusterPrivileges(), contains("manage", "manage_security", "monitor"));
|
||||
|
||||
assertThat(response.getGlobalPrivileges().size(), equalTo(2));
|
||||
assertThat(Iterables.get(response.getGlobalPrivileges(), 0).getPrivileges().size(), equalTo(1));
|
||||
assertManageApplicationsPrivilege(Iterables.get(response.getGlobalPrivileges(), 0).getPrivileges().iterator().next(), "test-*");
|
||||
assertThat(Iterables.get(response.getGlobalPrivileges(), 1).getPrivileges().size(), equalTo(1));
|
||||
assertManageApplicationsPrivilege(Iterables.get(response.getGlobalPrivileges(), 1).getPrivileges().iterator().next(), "apps-*");
|
||||
|
||||
assertThat(response.getIndicesPrivileges().size(), equalTo(7));
|
||||
assertThat(Iterables.get(response.getIndicesPrivileges(), 0).getIndices(), contains("test-1-*"));
|
||||
assertThat(Iterables.get(response.getIndicesPrivileges(), 0).getPrivileges(), contains("read"));
|
||||
assertThat(Iterables.get(response.getIndicesPrivileges(), 0).getFieldSecurity(), emptyIterable());
|
||||
assertThat(Iterables.get(response.getIndicesPrivileges(), 0).getQueries(), emptyIterable());
|
||||
|
||||
final UserIndicesPrivileges test4Privilege = Iterables.get(response.getIndicesPrivileges(), 1);
|
||||
assertThat(test4Privilege.getIndices(), contains("test-4-*"));
|
||||
assertThat(test4Privilege.getPrivileges(), contains("read"));
|
||||
assertThat(test4Privilege.getFieldSecurity(), iterableWithSize(1));
|
||||
final IndicesPrivileges.FieldSecurity test4FLS = test4Privilege.getFieldSecurity().iterator().next();
|
||||
assertThat(test4FLS.getGrantedFields(), contains("*"));
|
||||
assertThat(test4FLS.getDeniedFields(), contains("private-*"));
|
||||
assertThat(test4Privilege.getQueries(), emptyIterable());
|
||||
|
||||
final UserIndicesPrivileges test2Privilege = Iterables.get(response.getIndicesPrivileges(), 3);
|
||||
assertThat(test2Privilege.getIndices(), contains("test-2-*"));
|
||||
assertThat(test2Privilege.getPrivileges(), contains("read"));
|
||||
assertThat(test2Privilege.getFieldSecurity(), iterableWithSize(2));
|
||||
final Iterator<IndicesPrivileges.FieldSecurity> test2FLSIter = test2Privilege.getFieldSecurity().iterator();
|
||||
final IndicesPrivileges.FieldSecurity test2FLS1 = test2FLSIter.next();
|
||||
final IndicesPrivileges.FieldSecurity test2FLS2 = test2FLSIter.next();
|
||||
assertThat(test2FLS1.getGrantedFields(), contains("*"));
|
||||
assertThat(test2FLS1.getDeniedFields(), containsInAnyOrder("secret-*", "private-*"));
|
||||
assertThat(test2FLS2.getGrantedFields(), contains("apps-*"));
|
||||
assertThat(test2FLS2.getDeniedFields(), nullValue());
|
||||
assertThat(test2Privilege.getQueries(), iterableWithSize(2));
|
||||
final Iterator<String> test2QueryIter = test2Privilege.getQueries().iterator();
|
||||
assertThat(test2QueryIter.next(), equalTo("{\"term\":{\"test\":true}}"));
|
||||
assertThat(test2QueryIter.next(), equalTo("{\"term\":{\"apps\":true}}"));
|
||||
|
||||
assertThat(Iterables.get(response.getIndicesPrivileges(), 6).getIndices(), contains("test-1-*", "test-9-*"));
|
||||
assertThat(Iterables.get(response.getIndicesPrivileges(), 6).getPrivileges(), contains("all"));
|
||||
assertThat(Iterables.get(response.getIndicesPrivileges(), 6).getFieldSecurity(), emptyIterable());
|
||||
assertThat(Iterables.get(response.getIndicesPrivileges(), 6).getQueries(), emptyIterable());
|
||||
|
||||
assertThat(response.getApplicationPrivileges().size(), equalTo(3));
|
||||
assertThat(Iterables.get(response.getApplicationPrivileges(), 1).getApplication(), equalTo("test-app"));
|
||||
assertThat(Iterables.get(response.getApplicationPrivileges(), 1).getPrivileges(), contains("read"));
|
||||
assertThat(Iterables.get(response.getApplicationPrivileges(), 1).getResources(), containsInAnyOrder("object/1", "object/2"));
|
||||
|
||||
assertThat(response.getRunAsPrivilege(), contains("app-*", "test-*"));
|
||||
}
|
||||
|
||||
private void assertManageApplicationsPrivilege(GlobalOperationPrivilege privilege, String... applications) {
|
||||
assertThat(privilege.getCategory(), equalTo("application"));
|
||||
assertThat(privilege.getOperation(), equalTo("manage"));
|
||||
assertThat(privilege.getRaw().keySet(), contains("applications"));
|
||||
assertThat(privilege.getRaw().get("applications"), instanceOf(List.class));
|
||||
assertThat((List<?>) privilege.getRaw().get("applications"), contains((Object[]) applications));
|
||||
}
|
||||
}
|
|
@ -19,13 +19,18 @@
|
|||
|
||||
package org.elasticsearch.client.security.user.privileges;
|
||||
|
||||
import org.elasticsearch.common.Strings;
|
||||
import org.elasticsearch.common.xcontent.XContentParser;
|
||||
import org.elasticsearch.test.AbstractXContentTestCase;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
import static org.hamcrest.Matchers.containsString;
|
||||
import static org.hamcrest.Matchers.not;
|
||||
|
||||
public class IndicesPrivilegesTests extends AbstractXContentTestCase<IndicesPrivileges> {
|
||||
|
||||
public static IndicesPrivileges createNewRandom(String query) {
|
||||
|
@ -43,6 +48,35 @@ public class IndicesPrivilegesTests extends AbstractXContentTestCase<IndicesPriv
|
|||
return indicesPrivilegesBuilder.build();
|
||||
}
|
||||
|
||||
public void testToXContentWithNullFieldSecurity() {
|
||||
final IndicesPrivileges privileges = IndicesPrivileges.builder().indices("abc").privileges("all").build();
|
||||
final String json = Strings.toString(privileges);
|
||||
assertThat(json, not(containsString("field_security")));
|
||||
}
|
||||
|
||||
public void testToXContentWithEmptyFieldSecurity() {
|
||||
final IndicesPrivileges privileges = IndicesPrivileges.builder()
|
||||
.indices("abc")
|
||||
.privileges("all")
|
||||
.grantedFields(Collections.emptyList())
|
||||
.deniedFields(Collections.emptyList())
|
||||
.build();
|
||||
final String json = Strings.toString(privileges);
|
||||
assertThat(json, containsString("field_security"));
|
||||
assertThat(json, containsString("\"field_security\":{\"grant\":[],\"except\":[]}"));
|
||||
}
|
||||
|
||||
public void testToXContentWithDeniedFieldsOnly() {
|
||||
final IndicesPrivileges privileges = IndicesPrivileges.builder()
|
||||
.indices("abc")
|
||||
.privileges("all")
|
||||
.deniedFields("secret.*")
|
||||
.build();
|
||||
final String json = Strings.toString(privileges);
|
||||
assertThat(json, containsString("field_security"));
|
||||
assertThat(json, containsString("\"field_security\":{\"grant\":[\"*\"],\"except\":[\"secret.*\"]}"));
|
||||
}
|
||||
|
||||
@Override
|
||||
protected IndicesPrivileges createTestInstance() {
|
||||
return createNewRandom(
|
||||
|
|
|
@ -0,0 +1,55 @@
|
|||
////
|
||||
This file is included by high level rest client API documentation pages
|
||||
where the client method does not use a request object.
|
||||
For methods with requests, see execution.asciidoc
|
||||
////
|
||||
|
||||
[id="{upid}-{api}-sync"]
|
||||
==== Synchronous Execution
|
||||
|
||||
When executing the +{api}+ API in the following manner, the client waits
|
||||
for the +{response}+ to be returned before continuing with code execution:
|
||||
|
||||
["source","java",subs="attributes,callouts,macros"]
|
||||
--------------------------------------------------
|
||||
include-tagged::{doc-tests-file}[{api}-execute]
|
||||
--------------------------------------------------
|
||||
|
||||
Synchronous calls may throw an `IOException` in case of either failing to
|
||||
parse the REST response in the high-level REST client, the request times out
|
||||
or similar cases where there is no response coming back from the server.
|
||||
|
||||
In cases where the server returns a `4xx` or `5xx` error code, the high-level
|
||||
client tries to parse the response body error details instead and then throws
|
||||
a generic `ElasticsearchException` and adds the original `ResponseException` as a
|
||||
suppressed exception to it.
|
||||
|
||||
[id="{upid}-{api}-async"]
|
||||
==== Asynchronous Execution
|
||||
|
||||
The +{api}+ API can also be called in an asynchronous fashion so that
|
||||
the client can return directly. Users need to specify how the response or
|
||||
potential failures will be handled by passing a listener to the
|
||||
asynchronous {api} method:
|
||||
|
||||
["source","java",subs="attributes,callouts,macros"]
|
||||
--------------------------------------------------
|
||||
include-tagged::{doc-tests-file}[{api}-execute-async]
|
||||
--------------------------------------------------
|
||||
<1> The `RequestOptions` and `ActionListener` to use when the execution
|
||||
completes
|
||||
|
||||
The asynchronous method does not block and returns immediately. Once it is
|
||||
completed the `ActionListener` is called back using the `onResponse` method
|
||||
if the execution successfully completed or using the `onFailure` method if
|
||||
it failed. Failure scenarios and expected exceptions are the same as in the
|
||||
synchronous execution case.
|
||||
|
||||
A typical listener for +{api}+ looks like:
|
||||
|
||||
["source","java",subs="attributes,callouts,macros"]
|
||||
--------------------------------------------------
|
||||
include-tagged::{doc-tests-file}[{api}-execute-listener]
|
||||
--------------------------------------------------
|
||||
<1> Called when the execution is successfully completed.
|
||||
<2> Called when the +{api}+ call fails.
|
|
@ -0,0 +1,46 @@
|
|||
--
|
||||
:api: get-user-privileges
|
||||
:request: GetUserPrivilegesRequest
|
||||
:response: GetUserPrivilegesResponse
|
||||
--
|
||||
|
||||
[id="{upid}-{api}"]
|
||||
=== Get User Privileges API
|
||||
|
||||
include::../execution-no-req.asciidoc[]
|
||||
|
||||
[id="{upid}-{api}-response"]
|
||||
==== Get User Privileges Response
|
||||
|
||||
The returned +{response}+ contains the following properties
|
||||
|
||||
`clusterPrivileges`::
|
||||
A `Set` of all _cluster_ privileges that are held by the user.
|
||||
This will be the union of all the _cluster_ privileges from the user's roles.
|
||||
|
||||
`globalPrivileges`::
|
||||
A `Set` of all _global_ privileges that are held by the user.
|
||||
This will be the union of all the _global_ privileges from the user's roles.
|
||||
Because this a union of multiple roles, it may contain multiple privileges for
|
||||
the same `category` and `operation` (which is why is is represented as a `Set`
|
||||
rather than a single object).
|
||||
|
||||
`indicesPrivileges`::
|
||||
A `Set` of all _index_ privileges that are held by the user.
|
||||
This will be the union of all the _index_ privileges from the user's roles.
|
||||
Because this a union of multiple roles, it may contain multiple privileges for
|
||||
the same `index`, and those privileges may have independent field level security
|
||||
access grants and/or multiple document level security queries.
|
||||
|
||||
`applicationPrivileges`::
|
||||
A `Set` of all _application_ privileges that are held by the user.
|
||||
This will be the union of all the _application_ privileges from the user's roles.
|
||||
|
||||
`runAsPrivilege`::
|
||||
A `Set` representation of the _run-as_ privilege that is held by the user.
|
||||
This will be the union of the _run-as_ privilege from each of the user's roles.
|
||||
|
||||
["source","java",subs="attributes,callouts,macros"]
|
||||
--------------------------------------------------
|
||||
include-tagged::{doc-tests-file}[{api}-response]
|
||||
--------------------------------------------------
|
|
@ -398,6 +398,7 @@ The Java High Level REST Client supports the following Security APIs:
|
|||
* <<{upid}-clear-realm-cache>>
|
||||
* <<{upid}-authenticate>>
|
||||
* <<{upid}-has-privileges>>
|
||||
* <<{upid}-get-user-privileges>>
|
||||
* <<java-rest-high-security-get-certificates>>
|
||||
* <<java-rest-high-security-put-role-mapping>>
|
||||
* <<java-rest-high-security-get-role-mappings>>
|
||||
|
@ -422,6 +423,7 @@ include::security/clear-roles-cache.asciidoc[]
|
|||
include::security/clear-realm-cache.asciidoc[]
|
||||
include::security/authenticate.asciidoc[]
|
||||
include::security/has-privileges.asciidoc[]
|
||||
include::security/get-user-privileges.asciidoc[]
|
||||
include::security/get-certificates.asciidoc[]
|
||||
include::security/put-role-mapping.asciidoc[]
|
||||
include::security/get-role-mappings.asciidoc[]
|
||||
|
|
Loading…
Reference in New Issue