Add Delete Privileges API to HLRC (#35454)
This commit adds the Delete Privileges API to the high level REST client. Related to #29827
This commit is contained in:
parent
e7b7d52a6a
commit
5b7446bb5f
|
@ -29,6 +29,8 @@ import org.elasticsearch.client.security.ClearRolesCacheRequest;
|
|||
import org.elasticsearch.client.security.ClearRolesCacheResponse;
|
||||
import org.elasticsearch.client.security.CreateTokenRequest;
|
||||
import org.elasticsearch.client.security.CreateTokenResponse;
|
||||
import org.elasticsearch.client.security.DeletePrivilegesRequest;
|
||||
import org.elasticsearch.client.security.DeletePrivilegesResponse;
|
||||
import org.elasticsearch.client.security.DeleteRoleMappingRequest;
|
||||
import org.elasticsearch.client.security.DeleteRoleMappingResponse;
|
||||
import org.elasticsearch.client.security.DeleteRoleRequest;
|
||||
|
@ -221,7 +223,7 @@ public final class SecurityClient {
|
|||
* See <a href="https://www.elastic.co/guide/en/elasticsearch/reference/current/security-api-authenticate.html">
|
||||
* the docs</a> for more.
|
||||
*
|
||||
* @param options the request options (e.g. headers), use {@link RequestOptions#DEFAULT} if nothing needs to be customized
|
||||
* @param options the request options (e.g. headers), use {@link RequestOptions#DEFAULT} if nothing needs to be customized
|
||||
* @return the responsee from the authenticate user call
|
||||
*/
|
||||
public AuthenticateResponse authenticate(RequestOptions options) throws IOException {
|
||||
|
@ -234,8 +236,8 @@ public final class SecurityClient {
|
|||
* See <a href="https://www.elastic.co/guide/en/elasticsearch/reference/current/security-api-authenticate.html">
|
||||
* the docs</a> for more.
|
||||
*
|
||||
* @param options the request options (e.g. headers), use {@link RequestOptions#DEFAULT} if nothing needs to be customized
|
||||
* @param listener the listener to be notified upon request completion
|
||||
* @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 authenticateAsync(RequestOptions options, ActionListener<AuthenticateResponse> listener) {
|
||||
restHighLevelClient.performRequestAsyncAndParseEntity(AuthenticateRequest.INSTANCE, AuthenticateRequest::getRequest, options,
|
||||
|
@ -473,4 +475,32 @@ public final class SecurityClient {
|
|||
InvalidateTokenResponse::fromXContent, listener, emptySet());
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes application privilege(s)
|
||||
* See <a href="https://www.elastic.co/guide/en/elasticsearch/reference/current/security-api-delete-privilege.html">
|
||||
* the docs</a> for more.
|
||||
* @param request the request with the application privilege to delete
|
||||
* @param options the request options (e.g. headers), use {@link RequestOptions#DEFAULT} if nothing needs to be customized
|
||||
* @return the response from the delete application privilege call
|
||||
* @throws IOException in case there is a problem sending the request or parsing back the response
|
||||
*/
|
||||
public DeletePrivilegesResponse deletePrivileges(DeletePrivilegesRequest request, RequestOptions options) throws IOException {
|
||||
return restHighLevelClient.performRequestAndParseEntity(request, SecurityRequestConverters::deletePrivileges, options,
|
||||
DeletePrivilegesResponse::fromXContent, singleton(404));
|
||||
}
|
||||
|
||||
/**
|
||||
* Asynchronously removes an application privilege
|
||||
* See <a href="https://www.elastic.co/guide/en/elasticsearch/reference/current/security-api-delete-privilege.html">
|
||||
* the docs</a> for more.
|
||||
* @param request the request with the application privilege to delete
|
||||
* @param options the request options (e.g. headers), use {@link RequestOptions#DEFAULT} if nothing needs to be customized
|
||||
* @param listener the listener to be notified upon request completion
|
||||
*/
|
||||
public void deletePrivilegesAsync(DeletePrivilegesRequest request, RequestOptions options,
|
||||
ActionListener<DeletePrivilegesResponse> listener) {
|
||||
restHighLevelClient.performRequestAsyncAndParseEntity(request, SecurityRequestConverters::deletePrivileges, options,
|
||||
DeletePrivilegesResponse::fromXContent, listener, singleton(404));
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -19,21 +19,22 @@
|
|||
|
||||
package org.elasticsearch.client;
|
||||
|
||||
import org.apache.http.client.methods.HttpGet;
|
||||
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.HttpPut;
|
||||
import org.elasticsearch.client.security.ChangePasswordRequest;
|
||||
import org.elasticsearch.client.security.ClearRealmCacheRequest;
|
||||
import org.elasticsearch.client.security.ClearRolesCacheRequest;
|
||||
import org.elasticsearch.client.security.CreateTokenRequest;
|
||||
import org.elasticsearch.client.security.DeletePrivilegesRequest;
|
||||
import org.elasticsearch.client.security.DeleteRoleMappingRequest;
|
||||
import org.elasticsearch.client.security.DeleteRoleRequest;
|
||||
import org.elasticsearch.client.security.InvalidateTokenRequest;
|
||||
import org.elasticsearch.client.security.PutRoleMappingRequest;
|
||||
import org.elasticsearch.client.security.DisableUserRequest;
|
||||
import org.elasticsearch.client.security.EnableUserRequest;
|
||||
import org.elasticsearch.client.security.GetRoleMappingsRequest;
|
||||
import org.elasticsearch.client.security.ChangePasswordRequest;
|
||||
import org.elasticsearch.client.security.InvalidateTokenRequest;
|
||||
import org.elasticsearch.client.security.PutRoleMappingRequest;
|
||||
import org.elasticsearch.client.security.PutUserRequest;
|
||||
import org.elasticsearch.client.security.SetUserEnabledRequest;
|
||||
import org.elasticsearch.common.Strings;
|
||||
|
@ -172,4 +173,16 @@ final class SecurityRequestConverters {
|
|||
request.setEntity(createEntity(invalidateTokenRequest, REQUEST_BODY_CONTENT_TYPE));
|
||||
return request;
|
||||
}
|
||||
|
||||
static Request deletePrivileges(DeletePrivilegesRequest deletePrivilegeRequest) {
|
||||
String endpoint = new RequestConverters.EndpointBuilder()
|
||||
.addPathPartAsIs("_xpack/security/privilege")
|
||||
.addPathPart(deletePrivilegeRequest.getApplication())
|
||||
.addCommaSeparatedPathParts(deletePrivilegeRequest.getPrivileges())
|
||||
.build();
|
||||
Request request = new Request(HttpDelete.METHOD_NAME, endpoint);
|
||||
RequestConverters.Params params = new RequestConverters.Params(request);
|
||||
params.withRefreshPolicy(deletePrivilegeRequest.getRefreshPolicy());
|
||||
return request;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,76 @@
|
|||
/*
|
||||
* Licensed to Elasticsearch under one or more contributor
|
||||
* license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright
|
||||
* ownership. Elasticsearch licenses this file to you under
|
||||
* the Apache License, Version 2.0 (the "License"); you may
|
||||
* not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
package org.elasticsearch.client.security;
|
||||
|
||||
import org.elasticsearch.client.Validatable;
|
||||
import org.elasticsearch.common.Nullable;
|
||||
import org.elasticsearch.common.Strings;
|
||||
import org.elasticsearch.common.util.CollectionUtils;
|
||||
|
||||
/**
|
||||
* A request to delete application privileges
|
||||
*/
|
||||
public final class DeletePrivilegesRequest implements Validatable {
|
||||
|
||||
private final String application;
|
||||
private final String[] privileges;
|
||||
private final RefreshPolicy refreshPolicy;
|
||||
|
||||
/**
|
||||
* Creates a new {@link DeletePrivilegesRequest} using the default {@link RefreshPolicy#getDefault()} refresh policy.
|
||||
*
|
||||
* @param application the name of the application for which the privileges will be deleted
|
||||
* @param privileges the privileges to delete
|
||||
*/
|
||||
public DeletePrivilegesRequest(String application, String... privileges) {
|
||||
this(application, privileges, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new {@link DeletePrivilegesRequest}.
|
||||
*
|
||||
* @param application the name of the application for which the privileges will be deleted
|
||||
* @param privileges the privileges to delete
|
||||
* @param refreshPolicy the refresh policy {@link RefreshPolicy} for the request, defaults to {@link RefreshPolicy#getDefault()}
|
||||
*/
|
||||
public DeletePrivilegesRequest(String application, String[] privileges, @Nullable RefreshPolicy refreshPolicy) {
|
||||
if (Strings.hasText(application) == false) {
|
||||
throw new IllegalArgumentException("application name is required");
|
||||
}
|
||||
if (CollectionUtils.isEmpty(privileges)) {
|
||||
throw new IllegalArgumentException("privileges are required");
|
||||
}
|
||||
this.application = application;
|
||||
this.privileges = privileges;
|
||||
this.refreshPolicy = (refreshPolicy == null) ? RefreshPolicy.getDefault() : refreshPolicy;
|
||||
}
|
||||
|
||||
public String getApplication() {
|
||||
return application;
|
||||
}
|
||||
|
||||
public String[] getPrivileges() {
|
||||
return privileges;
|
||||
}
|
||||
|
||||
public RefreshPolicy getRefreshPolicy() {
|
||||
return refreshPolicy;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,91 @@
|
|||
/*
|
||||
* 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.XContentParser;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
|
||||
import static org.elasticsearch.common.xcontent.XContentParserUtils.ensureExpectedToken;
|
||||
|
||||
/**
|
||||
* Response for application privileges deletion
|
||||
*/
|
||||
public final class DeletePrivilegesResponse {
|
||||
|
||||
private final String application;
|
||||
private final List<String> privileges;
|
||||
|
||||
DeletePrivilegesResponse(String application, List<String> privileges) {
|
||||
this.application = Objects.requireNonNull(application, "application is required");
|
||||
this.privileges = Objects.requireNonNull(privileges, "privileges are required");
|
||||
}
|
||||
|
||||
public String getApplication() {
|
||||
return application;
|
||||
}
|
||||
|
||||
/**
|
||||
* Indicates if the given privilege was successfully found and deleted from the list of application privileges.
|
||||
*
|
||||
* @param privilege the privilege
|
||||
* @return true if the privilege was found and deleted, false otherwise.
|
||||
*/
|
||||
public boolean isFound(final String privilege) {
|
||||
return privileges.contains(privilege);
|
||||
}
|
||||
|
||||
public static DeletePrivilegesResponse fromXContent(XContentParser parser) throws IOException {
|
||||
XContentParser.Token token = parser.currentToken();
|
||||
if (token == null) {
|
||||
token = parser.nextToken();
|
||||
}
|
||||
ensureExpectedToken(XContentParser.Token.START_OBJECT, token, parser::getTokenLocation);
|
||||
token = parser.nextToken();
|
||||
ensureExpectedToken(XContentParser.Token.FIELD_NAME, token, parser::getTokenLocation);
|
||||
final String application = parser.currentName();
|
||||
final List<String> foundAndDeletedPrivileges = new ArrayList<>();
|
||||
token = parser.nextToken();
|
||||
if (token == XContentParser.Token.START_OBJECT) {
|
||||
while ((token = parser.nextToken()) != XContentParser.Token.END_OBJECT) {
|
||||
if (token == XContentParser.Token.FIELD_NAME) {
|
||||
String privilege = parser.currentName();
|
||||
token = parser.nextToken();
|
||||
if (token == XContentParser.Token.START_OBJECT) {
|
||||
String currentFieldName = null;
|
||||
while ((token = parser.nextToken()) != XContentParser.Token.END_OBJECT) {
|
||||
if (token == XContentParser.Token.FIELD_NAME) {
|
||||
currentFieldName = parser.currentName();
|
||||
} else if (token == XContentParser.Token.VALUE_BOOLEAN) {
|
||||
if ("found".equals(currentFieldName) && parser.booleanValue()) {
|
||||
foundAndDeletedPrivileges.add(privilege);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return new DeletePrivilegesResponse(application, foundAndDeletedPrivileges);
|
||||
}
|
||||
}
|
|
@ -24,6 +24,7 @@ import org.apache.http.client.methods.HttpDelete;
|
|||
import org.apache.http.client.methods.HttpPost;
|
||||
import org.apache.http.client.methods.HttpPut;
|
||||
import org.elasticsearch.client.security.CreateTokenRequest;
|
||||
import org.elasticsearch.client.security.DeletePrivilegesRequest;
|
||||
import org.elasticsearch.client.security.DeleteRoleMappingRequest;
|
||||
import org.elasticsearch.client.security.DeleteRoleRequest;
|
||||
import org.elasticsearch.client.security.DisableUserRequest;
|
||||
|
@ -241,4 +242,19 @@ public class SecurityRequestConvertersTests extends ESTestCase {
|
|||
assertEquals(0, request.getParameters().size());
|
||||
assertToXContentBody(createTokenRequest, request.getEntity());
|
||||
}
|
||||
|
||||
public void testDeletePrivileges() {
|
||||
final String application = randomAlphaOfLengthBetween(1, 12);
|
||||
final List<String> privileges = randomSubsetOf(randomIntBetween(1, 3), "read", "write", "all");
|
||||
final RefreshPolicy refreshPolicy = randomFrom(RefreshPolicy.values());
|
||||
final Map<String, String> expectedParams = getExpectedParamsFromRefreshPolicy(refreshPolicy);
|
||||
DeletePrivilegesRequest deletePrivilegesRequest =
|
||||
new DeletePrivilegesRequest(application, privileges.toArray(Strings.EMPTY_ARRAY), refreshPolicy);
|
||||
Request request = SecurityRequestConverters.deletePrivileges(deletePrivilegesRequest);
|
||||
assertEquals(HttpDelete.METHOD_NAME, request.getMethod());
|
||||
assertEquals("/_xpack/security/privilege/" + application + "/" + Strings.collectionToCommaDelimitedString(privileges),
|
||||
request.getEndpoint());
|
||||
assertEquals(expectedParams, request.getParameters());
|
||||
assertNull(request.getEntity());
|
||||
}
|
||||
}
|
||||
|
|
|
@ -28,6 +28,7 @@ import org.elasticsearch.action.support.PlainActionFuture;
|
|||
import org.elasticsearch.client.ESRestHighLevelClientTestCase;
|
||||
import org.elasticsearch.client.Request;
|
||||
import org.elasticsearch.client.RequestOptions;
|
||||
import org.elasticsearch.client.Response;
|
||||
import org.elasticsearch.client.RestHighLevelClient;
|
||||
import org.elasticsearch.client.security.AuthenticateResponse;
|
||||
import org.elasticsearch.client.security.ChangePasswordRequest;
|
||||
|
@ -37,6 +38,8 @@ import org.elasticsearch.client.security.ClearRolesCacheRequest;
|
|||
import org.elasticsearch.client.security.ClearRolesCacheResponse;
|
||||
import org.elasticsearch.client.security.CreateTokenRequest;
|
||||
import org.elasticsearch.client.security.CreateTokenResponse;
|
||||
import org.elasticsearch.client.security.DeletePrivilegesRequest;
|
||||
import org.elasticsearch.client.security.DeletePrivilegesResponse;
|
||||
import org.elasticsearch.client.security.DeleteRoleMappingRequest;
|
||||
import org.elasticsearch.client.security.DeleteRoleMappingResponse;
|
||||
import org.elasticsearch.client.security.DeleteRoleRequest;
|
||||
|
@ -55,13 +58,14 @@ import org.elasticsearch.client.security.PutRoleMappingResponse;
|
|||
import org.elasticsearch.client.security.PutUserRequest;
|
||||
import org.elasticsearch.client.security.PutUserResponse;
|
||||
import org.elasticsearch.client.security.RefreshPolicy;
|
||||
import org.elasticsearch.client.security.support.CertificateInfo;
|
||||
import org.elasticsearch.client.security.support.expressiondsl.RoleMapperExpression;
|
||||
import org.elasticsearch.client.security.support.expressiondsl.expressions.AnyRoleMapperExpression;
|
||||
import org.elasticsearch.client.security.support.expressiondsl.fields.FieldRoleMapperExpression;
|
||||
import org.elasticsearch.client.security.user.User;
|
||||
import org.elasticsearch.client.security.support.CertificateInfo;
|
||||
import org.elasticsearch.client.security.support.expressiondsl.expressions.AnyRoleMapperExpression;
|
||||
import org.elasticsearch.common.Strings;
|
||||
import org.elasticsearch.common.xcontent.XContentBuilder;
|
||||
import org.elasticsearch.rest.RestStatus;
|
||||
import org.hamcrest.Matchers;
|
||||
|
||||
import java.io.IOException;
|
||||
|
@ -916,4 +920,78 @@ public class SecurityDocumentationIT extends ESRestHighLevelClientTestCase {
|
|||
// See https://github.com/elastic/elasticsearch/issues/35115
|
||||
}
|
||||
}
|
||||
|
||||
public void testDeletePrivilege() throws Exception {
|
||||
RestHighLevelClient client = highLevelClient();
|
||||
{
|
||||
final Request createPrivilegeRequest = new Request("POST", "/_xpack/security/privilege");
|
||||
createPrivilegeRequest.setJsonEntity("{" +
|
||||
" \"testapp\": {" +
|
||||
" \"read\": {" +
|
||||
" \"actions\": [ \"action:login\", \"data:read/*\" ]" +
|
||||
" }," +
|
||||
" \"write\": {" +
|
||||
" \"actions\": [ \"action:login\", \"data:write/*\" ]" +
|
||||
" }," +
|
||||
" \"all\": {" +
|
||||
" \"actions\": [ \"action:login\", \"data:write/*\" ]" +
|
||||
" }" +
|
||||
" }" +
|
||||
"}");
|
||||
|
||||
final Response createPrivilegeResponse = client.getLowLevelClient().performRequest(createPrivilegeRequest);
|
||||
assertEquals(RestStatus.OK.getStatus(), createPrivilegeResponse.getStatusLine().getStatusCode());
|
||||
}
|
||||
{
|
||||
// tag::delete-privileges-request
|
||||
DeletePrivilegesRequest request = new DeletePrivilegesRequest(
|
||||
"testapp", // <1>
|
||||
"read", "write"); // <2>
|
||||
// end::delete-privileges-request
|
||||
|
||||
// tag::delete-privileges-execute
|
||||
DeletePrivilegesResponse response = client.security().deletePrivileges(request, RequestOptions.DEFAULT);
|
||||
// end::delete-privileges-execute
|
||||
|
||||
// tag::delete-privileges-response
|
||||
String application = response.getApplication(); // <1>
|
||||
boolean found = response.isFound("read"); // <2>
|
||||
// end::delete-privileges-response
|
||||
assertThat(application, equalTo("testapp"));
|
||||
assertTrue(response.isFound("write"));
|
||||
assertTrue(found);
|
||||
|
||||
// check if deleting the already deleted privileges again will give us a different response
|
||||
response = client.security().deletePrivileges(request, RequestOptions.DEFAULT);
|
||||
assertFalse(response.isFound("write"));
|
||||
}
|
||||
{
|
||||
DeletePrivilegesRequest deletePrivilegesRequest = new DeletePrivilegesRequest("testapp", "all");
|
||||
|
||||
ActionListener<DeletePrivilegesResponse> listener;
|
||||
//tag::delete-privileges-execute-listener
|
||||
listener = new ActionListener<DeletePrivilegesResponse>() {
|
||||
@Override
|
||||
public void onResponse(DeletePrivilegesResponse deletePrivilegesResponse) {
|
||||
// <1>
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onFailure(Exception e) {
|
||||
// <2>
|
||||
}
|
||||
};
|
||||
//end::delete-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::delete-privileges-execute-async
|
||||
client.security().deletePrivilegesAsync(deletePrivilegesRequest, RequestOptions.DEFAULT, listener); // <1>
|
||||
//end::delete-privileges-execute-async
|
||||
|
||||
assertTrue(latch.await(30L, TimeUnit.SECONDS));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,37 @@
|
|||
--
|
||||
:api: delete-privileges
|
||||
:request: DeletePrivilegesRequest
|
||||
:response: DeletePrivilegesResponse
|
||||
--
|
||||
|
||||
[id="{upid}-{api}"]
|
||||
=== Delete Privileges API
|
||||
|
||||
This API can be used to delete application privileges.
|
||||
|
||||
[id="{upid}-{api}-request"]
|
||||
==== Delete Application Privileges Request
|
||||
|
||||
A +{request}+ has two arguments
|
||||
|
||||
["source","java",subs="attributes,callouts,macros"]
|
||||
--------------------------------------------------
|
||||
include-tagged::{doc-tests-file}[{api}-request]
|
||||
--------------------------------------------------
|
||||
<1> the name of application
|
||||
<2> the name(s) of the privileges to delete that belong to the given application
|
||||
|
||||
include::../execution.asciidoc[]
|
||||
|
||||
[id="{upid}-{api}-response"]
|
||||
==== Delete Application Privileges Response
|
||||
|
||||
The returned +{response}+ allows to retrieve information about the executed
|
||||
operation as follows:
|
||||
|
||||
["source","java",subs="attributes,callouts,macros"]
|
||||
--------------------------------------------------
|
||||
include-tagged::{doc-tests-file}[{api}-response]
|
||||
--------------------------------------------------
|
||||
<1> the name of the application
|
||||
<2> whether the given privilege was found and deleted
|
|
@ -353,12 +353,14 @@ The Java High Level REST Client supports the following Security APIs:
|
|||
* <<java-rest-high-security-delete-role-mapping>>
|
||||
* <<java-rest-high-security-create-token>>
|
||||
* <<{upid}-invalidate-token>>
|
||||
* <<{upid}-delete-privileges>>
|
||||
|
||||
include::security/put-user.asciidoc[]
|
||||
include::security/enable-user.asciidoc[]
|
||||
include::security/disable-user.asciidoc[]
|
||||
include::security/change-password.asciidoc[]
|
||||
include::security/delete-role.asciidoc[]
|
||||
include::security/delete-privileges.asciidoc[]
|
||||
include::security/clear-roles-cache.asciidoc[]
|
||||
include::security/clear-realm-cache.asciidoc[]
|
||||
include::security/authenticate.asciidoc[]
|
||||
|
|
Loading…
Reference in New Issue