[PURIFY] Remove the AuthorizationEnginePlugin from examples. ()

Signed-off-by: Peter Nied <petern@amazon.com>
This commit is contained in:
Rabi Panda 2021-02-02 15:18:32 -08:00 committed by Peter Nied
parent 033f34cfdc
commit 38e9c9750a
7 changed files with 0 additions and 686 deletions

@ -1,31 +0,0 @@
// apply plugin: 'elasticsearch.esplugin'
// apply plugin: 'elasticsearch.java-rest-test'
// esplugin {
// name 'security-authorization-engine'
// description 'An example spi extension plugin for security that implements an Authorization Engine'
// classname 'org.elasticsearch.example.AuthorizationEnginePlugin'
// licenseFile rootProject.file('licenses/APACHE-LICENSE-2.0.txt')
// noticeFile rootProject.file('NOTICE.txt')
// }
// dependencies {
// // let the javaRestTest see the classpath of main
// javaRestTestImplementation project.sourceSets.main.runtimeClasspath
// }
// //no unit tests
// test.enabled = false
// javaRestTest {
// dependsOn buildZip
// systemProperty 'tests.security.manager', 'false'
// }
// testClusters.javaRestTest {
// // This is important, so that all the modules are available too.
// // There are index templates that use token filters that are in analysis-module and
// // processors are being used that are in ingest-common module.
// testDistribution = 'DEFAULT'
// user role: 'custom_superuser'
// }

@ -1,163 +0,0 @@
/*
* 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.example;
import org.apache.http.util.EntityUtils;
import org.elasticsearch.client.Request;
import org.elasticsearch.client.RequestOptions;
import org.elasticsearch.client.Response;
import org.elasticsearch.client.ResponseException;
import org.elasticsearch.common.network.NetworkModule;
import org.elasticsearch.common.settings.SecureString;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.common.util.concurrent.ThreadContext;
import org.elasticsearch.plugins.Plugin;
import org.elasticsearch.test.ESIntegTestCase;
import org.elasticsearch.xpack.core.XPackClientPlugin;
import org.elasticsearch.xpack.core.security.authc.support.Hasher;
import org.elasticsearch.xpack.core.security.authc.support.UsernamePasswordToken;
import org.elasticsearch.xpack.core.security.client.SecurityClient;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.util.Base64;
import java.util.Collection;
import java.util.Collections;
import static org.elasticsearch.xpack.core.security.authc.support.UsernamePasswordToken.basicAuthHeaderValue;
import static org.hamcrest.Matchers.containsString;
import static org.hamcrest.Matchers.is;
/**
* Integration tests for the custom authorization engine. These tests are meant to be run against
* an external cluster with the custom authorization plugin installed to validate the functionality
* when running as a plugin
*/
public class CustomAuthorizationEngineIT extends ESIntegTestCase {
@Override
protected Settings externalClusterClientSettings() {
final String token = "Basic " +
Base64.getEncoder().encodeToString(("test_user:x-pack-test-password").getBytes(StandardCharsets.UTF_8));
return Settings.builder()
.put(ThreadContext.PREFIX + ".Authorization", token)
.put(NetworkModule.TRANSPORT_TYPE_KEY, "security4")
.build();
}
@Override
protected Collection<Class<? extends Plugin>> transportClientPlugins() {
return Collections.singleton(XPackClientPlugin.class);
}
public void testClusterAction() throws IOException {
SecurityClient securityClient = new SecurityClient(client());
securityClient.preparePutUser("custom_user", "x-pack-test-password".toCharArray(), Hasher.BCRYPT, "custom_superuser").get();
{
RequestOptions.Builder options = RequestOptions.DEFAULT.toBuilder();
options.addHeader(UsernamePasswordToken.BASIC_AUTH_HEADER,
basicAuthHeaderValue("custom_user", new SecureString("x-pack-test-password".toCharArray())));
Request request = new Request("GET", "_cluster/health");
request.setOptions(options);
Response response = getRestClient().performRequest(request);
assertThat(response.getStatusLine().getStatusCode(), is(200));
}
{
securityClient.preparePutUser("custom_user2", "x-pack-test-password".toCharArray(), Hasher.BCRYPT, "not_superuser").get();
RequestOptions.Builder options = RequestOptions.DEFAULT.toBuilder();
options.addHeader(UsernamePasswordToken.BASIC_AUTH_HEADER,
basicAuthHeaderValue("custom_user2", new SecureString("x-pack-test-password".toCharArray())));
Request request = new Request("GET", "_cluster/health");
request.setOptions(options);
ResponseException e = expectThrows(ResponseException.class, () -> getRestClient().performRequest(request));
assertThat(e.getResponse().getStatusLine().getStatusCode(), is(403));
}
}
public void testIndexAction() throws IOException {
SecurityClient securityClient = new SecurityClient(client());
securityClient.preparePutUser("custom_user", "x-pack-test-password".toCharArray(), Hasher.BCRYPT, "custom_superuser").get();
{
RequestOptions.Builder options = RequestOptions.DEFAULT.toBuilder();
options.addHeader(UsernamePasswordToken.BASIC_AUTH_HEADER,
basicAuthHeaderValue("custom_user", new SecureString("x-pack-test-password".toCharArray())));
Request request = new Request("PUT", "/index");
request.setOptions(options);
Response response = getRestClient().performRequest(request);
assertThat(response.getStatusLine().getStatusCode(), is(200));
}
{
securityClient.preparePutUser("custom_user2", "x-pack-test-password".toCharArray(), Hasher.BCRYPT, "not_superuser").get();
RequestOptions.Builder options = RequestOptions.DEFAULT.toBuilder();
options.addHeader(UsernamePasswordToken.BASIC_AUTH_HEADER,
basicAuthHeaderValue("custom_user2", new SecureString("x-pack-test-password".toCharArray())));
Request request = new Request("PUT", "/index");
request.setOptions(options);
ResponseException e = expectThrows(ResponseException.class, () -> getRestClient().performRequest(request));
assertThat(e.getResponse().getStatusLine().getStatusCode(), is(403));
}
}
public void testRunAs() throws IOException {
SecurityClient securityClient = new SecurityClient(client());
securityClient.preparePutUser("custom_user", "x-pack-test-password".toCharArray(), Hasher.BCRYPT, "custom_superuser").get();
securityClient.preparePutUser("custom_user2", "x-pack-test-password".toCharArray(), Hasher.BCRYPT, "custom_superuser").get();
securityClient.preparePutUser("custom_user3", "x-pack-test-password".toCharArray(), Hasher.BCRYPT, "not_superuser").get();
{
RequestOptions.Builder options = RequestOptions.DEFAULT.toBuilder();
options.addHeader(UsernamePasswordToken.BASIC_AUTH_HEADER,
basicAuthHeaderValue("custom_user", new SecureString("x-pack-test-password".toCharArray())));
options.addHeader("es-security-runas-user", "custom_user2");
Request request = new Request("GET", "/_security/_authenticate");
request.setOptions(options);
Response response = getRestClient().performRequest(request);
assertThat(response.getStatusLine().getStatusCode(), is(200));
String responseStr = EntityUtils.toString(response.getEntity());
assertThat(responseStr, containsString("custom_user2"));
}
{
RequestOptions.Builder options = RequestOptions.DEFAULT.toBuilder();
options.addHeader(UsernamePasswordToken.BASIC_AUTH_HEADER,
basicAuthHeaderValue("custom_user", new SecureString("x-pack-test-password".toCharArray())));
options.addHeader("es-security-runas-user", "custom_user3");
Request request = new Request("PUT", "/index");
request.setOptions(options);
ResponseException e = expectThrows(ResponseException.class, () -> getRestClient().performRequest(request));
assertThat(e.getResponse().getStatusLine().getStatusCode(), is(403));
}
{
RequestOptions.Builder options = RequestOptions.DEFAULT.toBuilder();
options.addHeader(UsernamePasswordToken.BASIC_AUTH_HEADER,
basicAuthHeaderValue("custom_user3", new SecureString("x-pack-test-password".toCharArray())));
options.addHeader("es-security-runas-user", "custom_user2");
Request request = new Request("PUT", "/index");
request.setOptions(options);
ResponseException e = expectThrows(ResponseException.class, () -> getRestClient().performRequest(request));
assertThat(e.getResponse().getStatusLine().getStatusCode(), is(403));
}
}
}

@ -1,188 +0,0 @@
/*
* 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.example;
import org.elasticsearch.Version;
import org.elasticsearch.action.search.SearchRequest;
import org.elasticsearch.action.support.PlainActionFuture;
import org.elasticsearch.cluster.metadata.IndexAbstraction;
import org.elasticsearch.cluster.metadata.IndexAbstraction.Index;
import org.elasticsearch.cluster.metadata.IndexMetadata;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.test.ESTestCase;
import org.elasticsearch.transport.TransportRequest;
import org.elasticsearch.xpack.core.security.authc.Authentication;
import org.elasticsearch.xpack.core.security.authc.Authentication.RealmRef;
import org.elasticsearch.xpack.core.security.authz.AuthorizationEngine.AuthorizationInfo;
import org.elasticsearch.xpack.core.security.authz.AuthorizationEngine.AuthorizationResult;
import org.elasticsearch.xpack.core.security.authz.AuthorizationEngine.IndexAuthorizationResult;
import org.elasticsearch.xpack.core.security.authz.AuthorizationEngine.RequestInfo;
import org.elasticsearch.xpack.core.security.authz.ResolvedIndices;
import org.elasticsearch.xpack.core.security.authz.accesscontrol.IndicesAccessControl;
import org.elasticsearch.xpack.core.security.user.User;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import static org.hamcrest.Matchers.is;
/**
* Unit tests for the custom authorization engine. These are basic tests that validate the
* engine's functionality outside of being used by the AuthorizationService
*/
public class CustomAuthorizationEngineTests extends ESTestCase {
public void testGetAuthorizationInfo() {
PlainActionFuture<AuthorizationInfo> future = new PlainActionFuture<>();
CustomAuthorizationEngine engine = new CustomAuthorizationEngine();
engine.resolveAuthorizationInfo(getRequestInfo(), future);
assertNotNull(future.actionGet());
}
public void testAuthorizeRunAs() {
final String action = "cluster:monitor/foo";
final TransportRequest request = new TransportRequest() {};
CustomAuthorizationEngine engine = new CustomAuthorizationEngine();
// unauthorized
{
Authentication authentication =
new Authentication(new User("joe", new String[]{"custom_superuser"}, new User("bar", "not_superuser")),
new RealmRef("test", "test", "node"), new RealmRef("test", "test", "node"));
RequestInfo info = new RequestInfo(authentication, request, action);
PlainActionFuture<AuthorizationInfo> future = new PlainActionFuture<>();
engine.resolveAuthorizationInfo(info, future);
AuthorizationInfo authzInfo = future.actionGet();
PlainActionFuture<AuthorizationResult> resultFuture = new PlainActionFuture<>();
engine.authorizeRunAs(info, authzInfo, resultFuture);
AuthorizationResult result = resultFuture.actionGet();
assertThat(result.isGranted(), is(false));
assertThat(result.isAuditable(), is(true));
}
// authorized
{
Authentication authentication =
new Authentication(new User("joe", new String[]{"not_superuser"}, new User("bar", "custom_superuser")),
new RealmRef("test", "test", "node"), new RealmRef("test", "test", "node"));
RequestInfo info = new RequestInfo(authentication, request, action);
PlainActionFuture<AuthorizationInfo> future = new PlainActionFuture<>();
engine.resolveAuthorizationInfo(info, future);
AuthorizationInfo authzInfo = future.actionGet();
PlainActionFuture<AuthorizationResult> resultFuture = new PlainActionFuture<>();
engine.authorizeRunAs(info, authzInfo, resultFuture);
AuthorizationResult result = resultFuture.actionGet();
assertThat(result.isGranted(), is(true));
assertThat(result.isAuditable(), is(true));
}
}
public void testAuthorizeClusterAction() {
CustomAuthorizationEngine engine = new CustomAuthorizationEngine();
RequestInfo requestInfo = getRequestInfo();
// authorized
{
PlainActionFuture<AuthorizationInfo> future = new PlainActionFuture<>();
engine.resolveAuthorizationInfo(requestInfo, future);
AuthorizationInfo authzInfo = future.actionGet();
PlainActionFuture<AuthorizationResult> resultFuture = new PlainActionFuture<>();
engine.authorizeClusterAction(requestInfo, authzInfo, resultFuture);
AuthorizationResult result = resultFuture.actionGet();
assertThat(result.isGranted(), is(true));
assertThat(result.isAuditable(), is(true));
}
// unauthorized
{
RequestInfo unauthReqInfo =
new RequestInfo(new Authentication(new User("joe", "not_superuser"), new RealmRef("test", "test", "node"), null),
requestInfo.getRequest(), requestInfo.getAction());
PlainActionFuture<AuthorizationInfo> future = new PlainActionFuture<>();
engine.resolveAuthorizationInfo(unauthReqInfo, future);
AuthorizationInfo authzInfo = future.actionGet();
PlainActionFuture<AuthorizationResult> resultFuture = new PlainActionFuture<>();
engine.authorizeClusterAction(unauthReqInfo, authzInfo, resultFuture);
AuthorizationResult result = resultFuture.actionGet();
assertThat(result.isGranted(), is(false));
assertThat(result.isAuditable(), is(true));
}
}
public void testAuthorizeIndexAction() {
CustomAuthorizationEngine engine = new CustomAuthorizationEngine();
Map<String, IndexAbstraction> indicesMap = new HashMap<>();
indicesMap.put("index", new Index(IndexMetadata.builder("index")
.settings(Settings.builder().put("index.version.created", Version.CURRENT))
.numberOfShards(1)
.numberOfReplicas(0)
.build()));
// authorized
{
RequestInfo requestInfo =
new RequestInfo(new Authentication(new User("joe", "custom_superuser"), new RealmRef("test", "test", "node"), null),
new SearchRequest(), "indices:data/read/search");
PlainActionFuture<AuthorizationInfo> future = new PlainActionFuture<>();
engine.resolveAuthorizationInfo(requestInfo, future);
AuthorizationInfo authzInfo = future.actionGet();
PlainActionFuture<IndexAuthorizationResult> resultFuture = new PlainActionFuture<>();
engine.authorizeIndexAction(requestInfo, authzInfo,
listener -> listener.onResponse(new ResolvedIndices(Collections.singletonList("index"), Collections.emptyList())),
indicesMap, resultFuture);
IndexAuthorizationResult result = resultFuture.actionGet();
assertThat(result.isGranted(), is(true));
assertThat(result.isAuditable(), is(true));
IndicesAccessControl indicesAccessControl = result.getIndicesAccessControl();
assertNotNull(indicesAccessControl.getIndexPermissions("index"));
assertThat(indicesAccessControl.getIndexPermissions("index").isGranted(), is(true));
}
// unauthorized
{
RequestInfo requestInfo =
new RequestInfo(new Authentication(new User("joe", "not_superuser"), new RealmRef("test", "test", "node"), null),
new SearchRequest(), "indices:data/read/search");
PlainActionFuture<AuthorizationInfo> future = new PlainActionFuture<>();
engine.resolveAuthorizationInfo(requestInfo, future);
AuthorizationInfo authzInfo = future.actionGet();
PlainActionFuture<IndexAuthorizationResult> resultFuture = new PlainActionFuture<>();
engine.authorizeIndexAction(requestInfo, authzInfo,
listener -> listener.onResponse(new ResolvedIndices(Collections.singletonList("index"), Collections.emptyList())),
indicesMap, resultFuture);
IndexAuthorizationResult result = resultFuture.actionGet();
assertThat(result.isGranted(), is(false));
assertThat(result.isAuditable(), is(true));
IndicesAccessControl indicesAccessControl = result.getIndicesAccessControl();
assertNull(indicesAccessControl.getIndexPermissions("index"));
}
}
private RequestInfo getRequestInfo() {
final String action = "cluster:monitor/foo";
final TransportRequest request = new TransportRequest() {};
final Authentication authentication =
new Authentication(new User("joe", "custom_superuser"), new RealmRef("test", "test", "node"), null);
return new RequestInfo(authentication, request, action);
}
}

@ -1,30 +0,0 @@
/*
* 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.example;
import org.elasticsearch.plugins.ActionPlugin;
import org.elasticsearch.plugins.Plugin;
/**
* Plugin class that is required so that the code contained here may be loaded as a plugin.
* Additional items such as settings and actions can be registered using this plugin class.
*/
public class AuthorizationEnginePlugin extends Plugin implements ActionPlugin {
}

@ -1,238 +0,0 @@
/*
* 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.example;
import org.elasticsearch.action.ActionListener;
import org.elasticsearch.cluster.metadata.IndexAbstraction;
import org.elasticsearch.xpack.core.security.action.user.GetUserPrivilegesRequest;
import org.elasticsearch.xpack.core.security.action.user.GetUserPrivilegesResponse;
import org.elasticsearch.xpack.core.security.action.user.GetUserPrivilegesResponse.Indices;
import org.elasticsearch.xpack.core.security.action.user.HasPrivilegesRequest;
import org.elasticsearch.xpack.core.security.action.user.HasPrivilegesResponse;
import org.elasticsearch.xpack.core.security.authc.Authentication;
import org.elasticsearch.xpack.core.security.authz.AuthorizationEngine;
import org.elasticsearch.xpack.core.security.authz.ResolvedIndices;
import org.elasticsearch.xpack.core.security.authz.RoleDescriptor;
import org.elasticsearch.xpack.core.security.authz.RoleDescriptor.IndicesPrivileges;
import org.elasticsearch.xpack.core.security.authz.accesscontrol.IndicesAccessControl;
import org.elasticsearch.xpack.core.security.authz.accesscontrol.IndicesAccessControl.IndexAccessControl;
import org.elasticsearch.xpack.core.security.authz.permission.FieldPermissions;
import org.elasticsearch.xpack.core.security.authz.permission.ResourcePrivileges;
import org.elasticsearch.xpack.core.security.authz.privilege.ApplicationPrivilegeDescriptor;
import org.elasticsearch.xpack.core.security.authz.privilege.ConfigurableClusterPrivilege;
import org.elasticsearch.xpack.core.security.user.User;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;
/**
* A custom implementation of an authorization engine. This engine is extremely basic in that it
* authorizes based upon the name of a single role. If users have this role they are granted access.
*/
public class CustomAuthorizationEngine implements AuthorizationEngine {
@Override
public void resolveAuthorizationInfo(RequestInfo requestInfo, ActionListener<AuthorizationInfo> listener) {
final Authentication authentication = requestInfo.getAuthentication();
if (authentication.getUser().isRunAs()) {
final CustomAuthorizationInfo authenticatedUserAuthzInfo =
new CustomAuthorizationInfo(authentication.getUser().authenticatedUser().roles(), null);
listener.onResponse(new CustomAuthorizationInfo(authentication.getUser().roles(), authenticatedUserAuthzInfo));
} else {
listener.onResponse(new CustomAuthorizationInfo(authentication.getUser().roles(), null));
}
}
@Override
public void authorizeRunAs(RequestInfo requestInfo, AuthorizationInfo authorizationInfo, ActionListener<AuthorizationResult> listener) {
if (isSuperuser(requestInfo.getAuthentication().getUser().authenticatedUser())) {
listener.onResponse(AuthorizationResult.granted());
} else {
listener.onResponse(AuthorizationResult.deny());
}
}
@Override
public void authorizeClusterAction(RequestInfo requestInfo, AuthorizationInfo authorizationInfo,
ActionListener<AuthorizationResult> listener) {
if (isSuperuser(requestInfo.getAuthentication().getUser())) {
listener.onResponse(AuthorizationResult.granted());
} else {
listener.onResponse(AuthorizationResult.deny());
}
}
@Override
public void authorizeIndexAction(RequestInfo requestInfo, AuthorizationInfo authorizationInfo,
AsyncSupplier<ResolvedIndices> indicesAsyncSupplier,
Map<String, IndexAbstraction> aliasOrIndexLookup,
ActionListener<IndexAuthorizationResult> listener) {
if (isSuperuser(requestInfo.getAuthentication().getUser())) {
indicesAsyncSupplier.getAsync(ActionListener.wrap(resolvedIndices -> {
Map<String, IndexAccessControl> indexAccessControlMap = new HashMap<>();
for (String name : resolvedIndices.getLocal()) {
indexAccessControlMap.put(name, new IndexAccessControl(true, FieldPermissions.DEFAULT, null));
}
IndicesAccessControl indicesAccessControl =
new IndicesAccessControl(true, Collections.unmodifiableMap(indexAccessControlMap));
listener.onResponse(new IndexAuthorizationResult(true, indicesAccessControl));
}, listener::onFailure));
} else {
listener.onResponse(new IndexAuthorizationResult(true, IndicesAccessControl.DENIED));
}
}
@Override
public void loadAuthorizedIndices(RequestInfo requestInfo, AuthorizationInfo authorizationInfo,
Map<String, IndexAbstraction> indicesLookup, ActionListener<List<String>> listener) {
if (isSuperuser(requestInfo.getAuthentication().getUser())) {
listener.onResponse(new ArrayList<>(indicesLookup.keySet()));
} else {
listener.onResponse(Collections.emptyList());
}
}
@Override
public void validateIndexPermissionsAreSubset(RequestInfo requestInfo, AuthorizationInfo authorizationInfo,
Map<String, List<String>> indexNameToNewNames,
ActionListener<AuthorizationResult> listener) {
if (isSuperuser(requestInfo.getAuthentication().getUser())) {
listener.onResponse(AuthorizationResult.granted());
} else {
listener.onResponse(AuthorizationResult.deny());
}
}
@Override
public void checkPrivileges(Authentication authentication, AuthorizationInfo authorizationInfo,
HasPrivilegesRequest hasPrivilegesRequest,
Collection<ApplicationPrivilegeDescriptor> applicationPrivilegeDescriptors,
ActionListener<HasPrivilegesResponse> listener) {
if (isSuperuser(authentication.getUser())) {
listener.onResponse(getHasPrivilegesResponse(authentication, hasPrivilegesRequest, true));
} else {
listener.onResponse(getHasPrivilegesResponse(authentication, hasPrivilegesRequest, false));
}
}
@Override
public void getUserPrivileges(Authentication authentication, AuthorizationInfo authorizationInfo, GetUserPrivilegesRequest request,
ActionListener<GetUserPrivilegesResponse> listener) {
if (isSuperuser(authentication.getUser())) {
listener.onResponse(getUserPrivilegesResponse(true));
} else {
listener.onResponse(getUserPrivilegesResponse(false));
}
}
private HasPrivilegesResponse getHasPrivilegesResponse(Authentication authentication, HasPrivilegesRequest hasPrivilegesRequest,
boolean authorized) {
Map<String, Boolean> clusterPrivMap = new HashMap<>();
for (String clusterPriv : hasPrivilegesRequest.clusterPrivileges()) {
clusterPrivMap.put(clusterPriv, authorized);
}
final Map<String, ResourcePrivileges> indices = new LinkedHashMap<>();
for (IndicesPrivileges check : hasPrivilegesRequest.indexPrivileges()) {
for (String index : check.getIndices()) {
final Map<String, Boolean> privileges = new HashMap<>();
final ResourcePrivileges existing = indices.get(index);
if (existing != null) {
privileges.putAll(existing.getPrivileges());
}
for (String privilege : check.getPrivileges()) {
privileges.put(privilege, authorized);
}
indices.put(index, ResourcePrivileges.builder(index).addPrivileges(privileges).build());
}
}
final Map<String, Collection<ResourcePrivileges>> privilegesByApplication = new HashMap<>();
Set<String> applicationNames = Arrays.stream(hasPrivilegesRequest.applicationPrivileges())
.map(RoleDescriptor.ApplicationResourcePrivileges::getApplication)
.collect(Collectors.toSet());
for (String applicationName : applicationNames) {
final Map<String, ResourcePrivileges> appPrivilegesByResource = new LinkedHashMap<>();
for (RoleDescriptor.ApplicationResourcePrivileges p : hasPrivilegesRequest.applicationPrivileges()) {
if (applicationName.equals(p.getApplication())) {
for (String resource : p.getResources()) {
final Map<String, Boolean> privileges = new HashMap<>();
final ResourcePrivileges existing = appPrivilegesByResource.get(resource);
if (existing != null) {
privileges.putAll(existing.getPrivileges());
}
for (String privilege : p.getPrivileges()) {
privileges.put(privilege, authorized);
}
appPrivilegesByResource.put(resource, ResourcePrivileges.builder(resource).addPrivileges(privileges).build());
}
}
}
privilegesByApplication.put(applicationName, appPrivilegesByResource.values());
}
return new HasPrivilegesResponse(authentication.getUser().principal(), authorized, clusterPrivMap, indices.values(),
privilegesByApplication);
}
private GetUserPrivilegesResponse getUserPrivilegesResponse(boolean isSuperuser) {
final Set<String> cluster = isSuperuser ? Collections.singleton("ALL") : Collections.emptySet();
final Set<ConfigurableClusterPrivilege> conditionalCluster = Collections.emptySet();
final Set<GetUserPrivilegesResponse.Indices> indices = isSuperuser ? Collections.singleton(new Indices(Collections.singleton("*"),
Collections.singleton("*"), Collections.emptySet(), Collections.emptySet(), true)) : Collections.emptySet();
final Set<RoleDescriptor.ApplicationResourcePrivileges> application = isSuperuser ?
Collections.singleton(
RoleDescriptor.ApplicationResourcePrivileges.builder().application("*").privileges("*").resources("*").build()) :
Collections.emptySet();
final Set<String> runAs = isSuperuser ? Collections.singleton("*") : Collections.emptySet();
return new GetUserPrivilegesResponse(cluster, conditionalCluster, indices, application, runAs);
}
public static class CustomAuthorizationInfo implements AuthorizationInfo {
private final String[] roles;
private final CustomAuthorizationInfo authenticatedAuthzInfo;
CustomAuthorizationInfo(String[] roles, CustomAuthorizationInfo authenticatedAuthzInfo) {
this.roles = roles;
this.authenticatedAuthzInfo = authenticatedAuthzInfo;
}
@Override
public Map<String, Object> asMap() {
return Collections.singletonMap("roles", roles);
}
@Override
public CustomAuthorizationInfo getAuthenticatedUserAuthorizationInfo() {
return authenticatedAuthzInfo;
}
}
private boolean isSuperuser(User user) {
return Arrays.asList(user.roles()).contains("custom_superuser");
}
}

@ -1,35 +0,0 @@
/*
* 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.example;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.xpack.core.security.SecurityExtension;
import org.elasticsearch.xpack.core.security.authz.AuthorizationEngine;
/**
* Security extension class that registers the custom authorization engine to be used
*/
public class ExampleAuthorizationEngineExtension implements SecurityExtension {
@Override
public AuthorizationEngine getAuthorizationEngine(Settings settings) {
return new CustomAuthorizationEngine();
}
}