mirror of
https://github.com/honeymoose/OpenSearch.git
synced 2025-02-26 06:46:10 +00:00
Handle missing user in user privilege APIs (#34575)
For user/_has_privileges and user/_privileges, handle the case where there is no user in the security context. This is likely to indicate that the server is running with a basic license, in which case the action will be rejected with a non-compliance exception (provided we don't throw a NPE). The implementation here is based on the _authenticate API. Resolves: #34567
This commit is contained in:
parent
56d4f69718
commit
670ccfb853
@ -5,6 +5,7 @@
|
|||||||
*/
|
*/
|
||||||
package org.elasticsearch.xpack.security.rest.action.user;
|
package org.elasticsearch.xpack.security.rest.action.user;
|
||||||
|
|
||||||
|
import org.elasticsearch.ElasticsearchSecurityException;
|
||||||
import org.elasticsearch.client.node.NodeClient;
|
import org.elasticsearch.client.node.NodeClient;
|
||||||
import org.elasticsearch.common.settings.Settings;
|
import org.elasticsearch.common.settings.Settings;
|
||||||
import org.elasticsearch.common.xcontent.ToXContent;
|
import org.elasticsearch.common.xcontent.ToXContent;
|
||||||
@ -24,6 +25,7 @@ import org.elasticsearch.xpack.core.security.authz.RoleDescriptor;
|
|||||||
import org.elasticsearch.xpack.core.security.authz.privilege.ConditionalClusterPrivilege;
|
import org.elasticsearch.xpack.core.security.authz.privilege.ConditionalClusterPrivilege;
|
||||||
import org.elasticsearch.xpack.core.security.authz.privilege.ConditionalClusterPrivileges;
|
import org.elasticsearch.xpack.core.security.authz.privilege.ConditionalClusterPrivileges;
|
||||||
import org.elasticsearch.xpack.core.security.client.SecurityClient;
|
import org.elasticsearch.xpack.core.security.client.SecurityClient;
|
||||||
|
import org.elasticsearch.xpack.core.security.user.User;
|
||||||
import org.elasticsearch.xpack.security.rest.action.SecurityBaseRestHandler;
|
import org.elasticsearch.xpack.security.rest.action.SecurityBaseRestHandler;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
@ -52,7 +54,11 @@ public class RestGetUserPrivilegesAction extends SecurityBaseRestHandler {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public RestChannelConsumer innerPrepareRequest(RestRequest request, NodeClient client) throws IOException {
|
public RestChannelConsumer innerPrepareRequest(RestRequest request, NodeClient client) throws IOException {
|
||||||
final String username = securityContext.getUser().principal();
|
final User user = securityContext.getUser();
|
||||||
|
if (user == null) {
|
||||||
|
return restChannel -> { throw new ElasticsearchSecurityException("there is no authenticated user"); };
|
||||||
|
}
|
||||||
|
final String username = user.principal();
|
||||||
final GetUserPrivilegesRequestBuilder requestBuilder = new SecurityClient(client).prepareGetUserPrivileges(username);
|
final GetUserPrivilegesRequestBuilder requestBuilder = new SecurityClient(client).prepareGetUserPrivileges(username);
|
||||||
return channel -> requestBuilder.execute(new RestListener(channel));
|
return channel -> requestBuilder.execute(new RestListener(channel));
|
||||||
}
|
}
|
||||||
|
@ -5,6 +5,7 @@
|
|||||||
*/
|
*/
|
||||||
package org.elasticsearch.xpack.security.rest.action.user;
|
package org.elasticsearch.xpack.security.rest.action.user;
|
||||||
|
|
||||||
|
import org.elasticsearch.ElasticsearchSecurityException;
|
||||||
import org.elasticsearch.client.node.NodeClient;
|
import org.elasticsearch.client.node.NodeClient;
|
||||||
import org.elasticsearch.common.bytes.BytesReference;
|
import org.elasticsearch.common.bytes.BytesReference;
|
||||||
import org.elasticsearch.common.collect.Tuple;
|
import org.elasticsearch.common.collect.Tuple;
|
||||||
@ -24,6 +25,7 @@ import org.elasticsearch.xpack.core.security.action.user.HasPrivilegesRequestBui
|
|||||||
import org.elasticsearch.xpack.core.security.action.user.HasPrivilegesResponse;
|
import org.elasticsearch.xpack.core.security.action.user.HasPrivilegesResponse;
|
||||||
import org.elasticsearch.xpack.core.security.authz.RoleDescriptor;
|
import org.elasticsearch.xpack.core.security.authz.RoleDescriptor;
|
||||||
import org.elasticsearch.xpack.core.security.client.SecurityClient;
|
import org.elasticsearch.xpack.core.security.client.SecurityClient;
|
||||||
|
import org.elasticsearch.xpack.core.security.user.User;
|
||||||
import org.elasticsearch.xpack.security.rest.action.SecurityBaseRestHandler;
|
import org.elasticsearch.xpack.security.rest.action.SecurityBaseRestHandler;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
@ -59,6 +61,9 @@ public class RestHasPrivilegesAction extends SecurityBaseRestHandler {
|
|||||||
@Override
|
@Override
|
||||||
public RestChannelConsumer innerPrepareRequest(RestRequest request, NodeClient client) throws IOException {
|
public RestChannelConsumer innerPrepareRequest(RestRequest request, NodeClient client) throws IOException {
|
||||||
final String username = getUsername(request);
|
final String username = getUsername(request);
|
||||||
|
if (username == null) {
|
||||||
|
return restChannel -> { throw new ElasticsearchSecurityException("there is no authenticated user"); };
|
||||||
|
}
|
||||||
final Tuple<XContentType, BytesReference> content = request.contentOrSourceParam();
|
final Tuple<XContentType, BytesReference> content = request.contentOrSourceParam();
|
||||||
HasPrivilegesRequestBuilder requestBuilder = new SecurityClient(client).prepareHasPrivileges(username, content.v2(), content.v1());
|
HasPrivilegesRequestBuilder requestBuilder = new SecurityClient(client).prepareHasPrivileges(username, content.v2(), content.v1());
|
||||||
return channel -> requestBuilder.execute(new HasPrivilegesRestResponseBuilder(username, channel));
|
return channel -> requestBuilder.execute(new HasPrivilegesRestResponseBuilder(username, channel));
|
||||||
@ -69,7 +74,11 @@ public class RestHasPrivilegesAction extends SecurityBaseRestHandler {
|
|||||||
if (username != null) {
|
if (username != null) {
|
||||||
return username;
|
return username;
|
||||||
}
|
}
|
||||||
return securityContext.getUser().principal();
|
final User user = securityContext.getUser();
|
||||||
|
if (user == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return user.principal();
|
||||||
}
|
}
|
||||||
|
|
||||||
static class HasPrivilegesRestResponseBuilder extends RestBuilderListener<HasPrivilegesResponse> {
|
static class HasPrivilegesRestResponseBuilder extends RestBuilderListener<HasPrivilegesResponse> {
|
||||||
|
@ -6,17 +6,24 @@
|
|||||||
|
|
||||||
package org.elasticsearch.xpack.security.rest.action.user;
|
package org.elasticsearch.xpack.security.rest.action.user;
|
||||||
|
|
||||||
|
import org.elasticsearch.client.node.NodeClient;
|
||||||
import org.elasticsearch.common.Strings;
|
import org.elasticsearch.common.Strings;
|
||||||
import org.elasticsearch.common.bytes.BytesArray;
|
import org.elasticsearch.common.bytes.BytesArray;
|
||||||
|
import org.elasticsearch.common.settings.Settings;
|
||||||
import org.elasticsearch.common.util.set.Sets;
|
import org.elasticsearch.common.util.set.Sets;
|
||||||
import org.elasticsearch.common.xcontent.XContentBuilder;
|
import org.elasticsearch.common.xcontent.XContentBuilder;
|
||||||
|
import org.elasticsearch.license.XPackLicenseState;
|
||||||
|
import org.elasticsearch.rest.RestController;
|
||||||
|
import org.elasticsearch.rest.RestStatus;
|
||||||
import org.elasticsearch.test.ESTestCase;
|
import org.elasticsearch.test.ESTestCase;
|
||||||
|
import org.elasticsearch.test.rest.FakeRestChannel;
|
||||||
|
import org.elasticsearch.test.rest.FakeRestRequest;
|
||||||
|
import org.elasticsearch.xpack.core.security.SecurityContext;
|
||||||
import org.elasticsearch.xpack.core.security.action.user.GetUserPrivilegesResponse;
|
import org.elasticsearch.xpack.core.security.action.user.GetUserPrivilegesResponse;
|
||||||
import org.elasticsearch.xpack.core.security.authz.RoleDescriptor.ApplicationResourcePrivileges;
|
import org.elasticsearch.xpack.core.security.authz.RoleDescriptor.ApplicationResourcePrivileges;
|
||||||
import org.elasticsearch.xpack.core.security.authz.permission.FieldPermissionsDefinition;
|
import org.elasticsearch.xpack.core.security.authz.permission.FieldPermissionsDefinition;
|
||||||
import org.elasticsearch.xpack.core.security.authz.privilege.ConditionalClusterPrivilege;
|
import org.elasticsearch.xpack.core.security.authz.privilege.ConditionalClusterPrivilege;
|
||||||
import org.elasticsearch.xpack.core.security.authz.privilege.ConditionalClusterPrivileges;
|
import org.elasticsearch.xpack.core.security.authz.privilege.ConditionalClusterPrivileges;
|
||||||
import org.hamcrest.Matchers;
|
|
||||||
|
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
@ -24,9 +31,27 @@ import java.util.LinkedHashSet;
|
|||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
|
||||||
import static org.elasticsearch.common.xcontent.XContentFactory.jsonBuilder;
|
import static org.elasticsearch.common.xcontent.XContentFactory.jsonBuilder;
|
||||||
|
import static org.hamcrest.Matchers.containsString;
|
||||||
|
import static org.hamcrest.Matchers.equalTo;
|
||||||
|
import static org.hamcrest.Matchers.notNullValue;
|
||||||
|
import static org.mockito.Mockito.mock;
|
||||||
|
import static org.mockito.Mockito.when;
|
||||||
|
|
||||||
public class RestGetUserPrivilegesActionTests extends ESTestCase {
|
public class RestGetUserPrivilegesActionTests extends ESTestCase {
|
||||||
|
|
||||||
|
public void testBasicLicense() throws Exception {
|
||||||
|
final XPackLicenseState licenseState = mock(XPackLicenseState.class);
|
||||||
|
final RestGetUserPrivilegesAction action = new RestGetUserPrivilegesAction(Settings.EMPTY, mock(RestController.class),
|
||||||
|
mock(SecurityContext.class), licenseState);
|
||||||
|
when(licenseState.isSecurityAvailable()).thenReturn(false);
|
||||||
|
final FakeRestRequest request = new FakeRestRequest();
|
||||||
|
final FakeRestChannel channel = new FakeRestChannel(request, true, 1);
|
||||||
|
action.handleRequest(request, channel, mock(NodeClient.class));
|
||||||
|
assertThat(channel.capturedResponse(), notNullValue());
|
||||||
|
assertThat(channel.capturedResponse().status(), equalTo(RestStatus.FORBIDDEN));
|
||||||
|
assertThat(channel.capturedResponse().content().utf8ToString(), containsString("current license is non-compliant for [security]"));
|
||||||
|
}
|
||||||
|
|
||||||
public void testBuildResponse() throws Exception {
|
public void testBuildResponse() throws Exception {
|
||||||
final RestGetUserPrivilegesAction.RestListener listener = new RestGetUserPrivilegesAction.RestListener(null);
|
final RestGetUserPrivilegesAction.RestListener listener = new RestGetUserPrivilegesAction.RestListener(null);
|
||||||
|
|
||||||
@ -60,7 +85,7 @@ public class RestGetUserPrivilegesActionTests extends ESTestCase {
|
|||||||
listener.buildResponse(response, builder);
|
listener.buildResponse(response, builder);
|
||||||
|
|
||||||
String json = Strings.toString(builder);
|
String json = Strings.toString(builder);
|
||||||
assertThat(json, Matchers.equalTo("{" +
|
assertThat(json, equalTo("{" +
|
||||||
"\"cluster\":[\"monitor\",\"manage_ml\",\"manage_watcher\"]," +
|
"\"cluster\":[\"monitor\",\"manage_ml\",\"manage_watcher\"]," +
|
||||||
"\"global\":[" +
|
"\"global\":[" +
|
||||||
"{\"application\":{\"manage\":{\"applications\":[\"app01\",\"app02\"]}}}" +
|
"{\"application\":{\"manage\":{\"applications\":[\"app01\",\"app02\"]}}}" +
|
||||||
|
@ -0,0 +1,39 @@
|
|||||||
|
/*
|
||||||
|
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||||
|
* or more contributor license agreements. Licensed under the Elastic License;
|
||||||
|
* you may not use this file except in compliance with the Elastic License.
|
||||||
|
*/
|
||||||
|
package org.elasticsearch.xpack.security.rest.action.user;
|
||||||
|
|
||||||
|
import org.elasticsearch.client.node.NodeClient;
|
||||||
|
import org.elasticsearch.common.settings.Settings;
|
||||||
|
import org.elasticsearch.license.XPackLicenseState;
|
||||||
|
import org.elasticsearch.rest.RestController;
|
||||||
|
import org.elasticsearch.rest.RestStatus;
|
||||||
|
import org.elasticsearch.test.ESTestCase;
|
||||||
|
import org.elasticsearch.test.rest.FakeRestChannel;
|
||||||
|
import org.elasticsearch.test.rest.FakeRestRequest;
|
||||||
|
import org.elasticsearch.xpack.core.security.SecurityContext;
|
||||||
|
|
||||||
|
import static org.hamcrest.Matchers.containsString;
|
||||||
|
import static org.hamcrest.Matchers.equalTo;
|
||||||
|
import static org.hamcrest.Matchers.notNullValue;
|
||||||
|
import static org.mockito.Mockito.mock;
|
||||||
|
import static org.mockito.Mockito.when;
|
||||||
|
|
||||||
|
public class RestHasPrivilegesActionTests extends ESTestCase {
|
||||||
|
|
||||||
|
public void testBasicLicense() throws Exception {
|
||||||
|
final XPackLicenseState licenseState = mock(XPackLicenseState.class);
|
||||||
|
final RestHasPrivilegesAction action = new RestHasPrivilegesAction(Settings.EMPTY, mock(RestController.class),
|
||||||
|
mock(SecurityContext.class), licenseState);
|
||||||
|
when(licenseState.isSecurityAvailable()).thenReturn(false);
|
||||||
|
final FakeRestRequest request = new FakeRestRequest();
|
||||||
|
final FakeRestChannel channel = new FakeRestChannel(request, true, 1);
|
||||||
|
action.handleRequest(request, channel, mock(NodeClient.class));
|
||||||
|
assertThat(channel.capturedResponse(), notNullValue());
|
||||||
|
assertThat(channel.capturedResponse().status(), equalTo(RestStatus.FORBIDDEN));
|
||||||
|
assertThat(channel.capturedResponse().content().utf8ToString(), containsString("current license is non-compliant for [security]"));
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user