Skip to content

Commit

Permalink
support get user privileges
Browse files Browse the repository at this point in the history
  • Loading branch information
jakelandis committed Apr 9, 2024
1 parent df4e6a9 commit 435f79a
Show file tree
Hide file tree
Showing 10 changed files with 196 additions and 18 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
import org.elasticsearch.xcontent.XContentBuilder;
import org.elasticsearch.xpack.core.security.authz.RoleDescriptor;
import org.elasticsearch.xpack.core.security.authz.permission.FieldPermissionsDefinition;
import org.elasticsearch.xpack.core.security.authz.permission.RemoteClusterPermissions;
import org.elasticsearch.xpack.core.security.authz.privilege.ConfigurableClusterPrivilege;
import org.elasticsearch.xpack.core.security.authz.privilege.ConfigurableClusterPrivileges;

Expand All @@ -40,6 +41,7 @@ public final class GetUserPrivilegesResponse extends ActionResponse {
private final Set<RoleDescriptor.ApplicationResourcePrivileges> application;
private final Set<String> runAs;
private final Set<RemoteIndices> remoteIndex;
private final RemoteClusterPermissions remoteClusterPermissions;

public GetUserPrivilegesResponse(StreamInput in) throws IOException {
super(in);
Expand All @@ -53,6 +55,11 @@ public GetUserPrivilegesResponse(StreamInput in) throws IOException {
} else {
remoteIndex = Set.of();
}
if (in.getTransportVersion().onOrAfter(TransportVersions.ROLE_REMOTE_CLUSTER_PRIVS)) {
remoteClusterPermissions = new RemoteClusterPermissions(in);
} else {
remoteClusterPermissions = RemoteClusterPermissions.NONE;
}
}

public GetUserPrivilegesResponse(
Expand All @@ -61,14 +68,16 @@ public GetUserPrivilegesResponse(
Set<Indices> index,
Set<RoleDescriptor.ApplicationResourcePrivileges> application,
Set<String> runAs,
Set<RemoteIndices> remoteIndex
Set<RemoteIndices> remoteIndex,
RemoteClusterPermissions remoteClusterPermissions
) {
this.cluster = Collections.unmodifiableSet(cluster);
this.configurableClusterPrivileges = Collections.unmodifiableSet(conditionalCluster);
this.index = Collections.unmodifiableSet(index);
this.application = Collections.unmodifiableSet(application);
this.runAs = Collections.unmodifiableSet(runAs);
this.remoteIndex = Collections.unmodifiableSet(remoteIndex);
this.remoteClusterPermissions = remoteClusterPermissions;
}

public Set<String> getClusterPrivileges() {
Expand All @@ -87,6 +96,10 @@ public Set<RemoteIndices> getRemoteIndexPrivileges() {
return remoteIndex;
}

public RemoteClusterPermissions getRemoteClusterPermissions() {
return remoteClusterPermissions;
}

public Set<RoleDescriptor.ApplicationResourcePrivileges> getApplicationPrivileges() {
return application;
}
Expand All @@ -99,6 +112,10 @@ public boolean hasRemoteIndicesPrivileges() {
return false == remoteIndex.isEmpty();
}

public boolean hasRemoteClusterPrivileges() {
return remoteClusterPermissions.hasPrivileges();
}

@Override
public void writeTo(StreamOutput out) throws IOException {
out.writeStringCollection(cluster);
Expand All @@ -117,6 +134,17 @@ public void writeTo(StreamOutput out) throws IOException {
+ "]"
);
}
if (out.getTransportVersion().onOrAfter(TransportVersions.ROLE_REMOTE_CLUSTER_PRIVS)) {
remoteClusterPermissions.writeTo(out);
} else if(hasRemoteClusterPrivileges()){
throw new IllegalArgumentException(
"versions of Elasticsearch before ["
+ TransportVersions.ROLE_REMOTE_CLUSTER_PRIVS
+ "] can't handle remote cluster privileges and attempted to send to ["
+ out.getTransportVersion()
+ "]"
);
}
}

@Override
Expand All @@ -133,12 +161,13 @@ public boolean equals(Object other) {
&& Objects.equals(index, that.index)
&& Objects.equals(application, that.application)
&& Objects.equals(runAs, that.runAs)
&& Objects.equals(remoteIndex, that.remoteIndex);
&& Objects.equals(remoteIndex, that.remoteIndex)
&& Objects.equals(remoteClusterPermissions, that.remoteClusterPermissions);
}

@Override
public int hashCode() {
return Objects.hash(cluster, configurableClusterPrivileges, index, application, runAs, remoteIndex);
return Objects.hash(cluster, configurableClusterPrivileges, index, application, runAs, remoteIndex, remoteClusterPermissions);
}

public record RemoteIndices(Indices indices, Set<String> remoteClusters) implements ToXContentObject, Writeable {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@

import java.io.IOException;
import java.util.Arrays;
import java.util.Objects;

/**
* Represents a group of permissions for a remote cluster. For example:
Expand Down Expand Up @@ -84,4 +85,22 @@ public void writeTo(StreamOutput out) throws IOException {
out.writeStringArray(clusterPrivileges);
out.writeStringArray(remoteClusterAliases);
}

@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
RemoteClusterPermissionGroup that = (RemoteClusterPermissionGroup) o;
return Arrays.equals(clusterPrivileges, that.clusterPrivileges)
&& Arrays.equals(remoteClusterAliases, that.remoteClusterAliases)
&& Objects.equals(remoteClusterAliasMatcher, that.remoteClusterAliasMatcher);
}

@Override
public int hashCode() {
int result = Objects.hash(remoteClusterAliasMatcher);
result = 31 * result + Arrays.hashCode(clusterPrivileges);
result = 31 * result + Arrays.hashCode(remoteClusterAliases);
return result;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -25,8 +25,6 @@
import java.util.Objects;
import java.util.Set;

import static org.elasticsearch.action.ValidateActions.addValidationError;

/**
* Represents a group of permissions for a remote cluster. This is intended to be the model for both the {@link RoleDescriptor}
* and {@link Role}. This model is not intended to be sent to a remote cluster, but can be (wire) serialized within a single cluster
Expand Down Expand Up @@ -158,4 +156,17 @@ public XContentBuilder toXContent(XContentBuilder builder, Params params) throws
public void writeTo(StreamOutput out) throws IOException {
out.writeCollection(remoteClusterPermissionGroups);
}

@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
RemoteClusterPermissions that = (RemoteClusterPermissions) o;
return Objects.equals(remoteClusterPermissionGroups, that.remoteClusterPermissionGroups);
}

@Override
public int hashCode() {
return Objects.hash(remoteClusterPermissionGroups);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -96,7 +96,12 @@ public class ReservedRolesStore implements BiConsumer<Set<String>, ActionListene
.build(),
"*"
) },
new RemoteClusterPermissions().addGroup(new RemoteClusterPermissionGroup(new String[] { "monitor_enrich" }, new String[] { "*" })),
new RemoteClusterPermissions().addGroup(
new RemoteClusterPermissionGroup(
RemoteClusterPermissions.getSupportRemoteClusterPermissions().toArray(new String[0]),
new String[] { "*" }
)
),
null
);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,8 @@
import org.elasticsearch.xpack.core.XPackClientPlugin;
import org.elasticsearch.xpack.core.security.authz.RoleDescriptor.ApplicationResourcePrivileges;
import org.elasticsearch.xpack.core.security.authz.permission.FieldPermissionsDefinition.FieldGrantExcludeGroup;
import org.elasticsearch.xpack.core.security.authz.permission.RemoteClusterPermissionGroup;
import org.elasticsearch.xpack.core.security.authz.permission.RemoteClusterPermissions;
import org.elasticsearch.xpack.core.security.authz.privilege.ConfigurableClusterPrivilege;
import org.elasticsearch.xpack.core.security.authz.privilege.ConfigurableClusterPrivileges.ManageApplicationPrivileges;

Expand Down Expand Up @@ -67,8 +69,9 @@ public void testSerialization() throws IOException {
public void testSerializationForCurrentVersion() throws Exception {
final TransportVersion version = TransportVersionUtils.randomCompatibleVersion(random());
final boolean canIncludeRemoteIndices = version.onOrAfter(TransportVersions.V_8_8_0);
final boolean canIncludeRemoteCluster = version.onOrAfter(TransportVersions.ROLE_REMOTE_CLUSTER_PRIVS);

final GetUserPrivilegesResponse original = randomResponse(canIncludeRemoteIndices);
final GetUserPrivilegesResponse original = randomResponse(canIncludeRemoteIndices, canIncludeRemoteCluster);

final BytesStreamOutput out = new BytesStreamOutput();
out.setTransportVersion(version);
Expand Down Expand Up @@ -124,7 +127,8 @@ public void testEqualsAndHashCode() throws IOException {
original.getIndexPrivileges(),
original.getApplicationPrivileges(),
original.getRunAs(),
original.getRemoteIndexPrivileges()
original.getRemoteIndexPrivileges(),
original.getRemoteClusterPermissions()
);
final EqualsHashCodeTestUtils.MutateFunction<GetUserPrivilegesResponse> mutate = new EqualsHashCodeTestUtils.MutateFunction<>() {
@Override
Expand Down Expand Up @@ -175,7 +179,16 @@ public GetUserPrivilegesResponse mutate(GetUserPrivilegesResponse original) {
randomStringSet(1)
)
);
return new GetUserPrivilegesResponse(cluster, conditionalCluster, index, application, runAs, remoteIndex);

final RemoteClusterPermissions remoteCluster = new RemoteClusterPermissions();
remoteCluster.addGroup(
new RemoteClusterPermissionGroup(
RemoteClusterPermissions.getSupportRemoteClusterPermissions().toArray(new String[0]),
generateRandomStringArray(3, 5, false, false)
)
);

return new GetUserPrivilegesResponse(cluster, conditionalCluster, index, application, runAs, remoteIndex,remoteCluster);
}

private <T> Set<T> maybeMutate(int random, int index, Set<T> original, Supplier<T> supplier) {
Expand All @@ -193,10 +206,10 @@ private <T> Set<T> maybeMutate(int random, int index, Set<T> original, Supplier<
}

private GetUserPrivilegesResponse randomResponse() {
return randomResponse(true);
return randomResponse(true, true);
}

private GetUserPrivilegesResponse randomResponse(boolean allowRemoteIndices) {
private GetUserPrivilegesResponse randomResponse(boolean allowRemoteIndices, boolean allowRemoteClusters) {
final Set<String> cluster = randomStringSet(5);
final Set<ConfigurableClusterPrivilege> conditionalCluster = Sets.newHashSet(
randomArray(3, ConfigurableClusterPrivilege[]::new, () -> new ManageApplicationPrivileges(randomStringSet(3)))
Expand Down Expand Up @@ -226,7 +239,16 @@ private GetUserPrivilegesResponse randomResponse(boolean allowRemoteIndices) {
)
: Set.of();

return new GetUserPrivilegesResponse(cluster, conditionalCluster, index, application, runAs, remoteIndex);
RemoteClusterPermissions remoteCluster = allowRemoteClusters ? new RemoteClusterPermissions() : RemoteClusterPermissions.NONE;
if(allowRemoteClusters) {
remoteCluster.addGroup(
new RemoteClusterPermissionGroup(
RemoteClusterPermissions.getSupportRemoteClusterPermissions().toArray(new String[0]),
generateRandomStringArray(3, 5, false, false)
)
);
}
return new GetUserPrivilegesResponse(cluster, conditionalCluster, index, application, runAs, remoteIndex, remoteCluster);
}

private GetUserPrivilegesResponse.Indices randomIndices(boolean allowMultipleFlsDlsDefinitions) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -798,7 +798,15 @@ static GetUserPrivilegesResponse buildUserPrivilegesResponseObject(Role userRole
runAs = runAsPrivilege.name();
}

return new GetUserPrivilegesResponse(cluster, conditionalCluster, indices, application, runAs, remoteIndices);
return new GetUserPrivilegesResponse(
cluster,
conditionalCluster,
indices,
application,
runAs,
remoteIndices,
userRole.remoteCluster()
);
}

private static GetUserPrivilegesResponse.Indices toIndices(final IndicesPermission.Group group) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -96,7 +96,9 @@ public RestResponse buildResponse(GetUserPrivilegesResponse response, XContentBu
if (response.hasRemoteIndicesPrivileges()) {
builder.field(RoleDescriptor.Fields.REMOTE_INDICES.getPreferredName(), response.getRemoteIndexPrivileges());
}

if (response.hasRemoteClusterPrivileges()) {
builder.array(RoleDescriptor.Fields.REMOTE_CLUSTER.getPreferredName(), response.getRemoteClusterPermissions());
}
builder.endObject();
return new RestResponse(RestStatus.OK, builder);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,8 @@
import org.elasticsearch.xpack.core.security.authz.permission.FieldPermissionsCache;
import org.elasticsearch.xpack.core.security.authz.permission.FieldPermissionsDefinition;
import org.elasticsearch.xpack.core.security.authz.permission.IndicesPermission;
import org.elasticsearch.xpack.core.security.authz.permission.RemoteClusterPermissionGroup;
import org.elasticsearch.xpack.core.security.authz.permission.RemoteClusterPermissions;
import org.elasticsearch.xpack.core.security.authz.permission.RemoteIndicesPermission;
import org.elasticsearch.xpack.core.security.authz.permission.ResourcePrivileges;
import org.elasticsearch.xpack.core.security.authz.permission.Role;
Expand Down Expand Up @@ -133,6 +135,7 @@
import static org.hamcrest.Matchers.emptyArray;
import static org.hamcrest.Matchers.emptyIterable;
import static org.hamcrest.Matchers.equalTo;
import static org.hamcrest.Matchers.everyItem;
import static org.hamcrest.Matchers.hasItem;
import static org.hamcrest.Matchers.hasItems;
import static org.hamcrest.Matchers.instanceOf;
Expand Down Expand Up @@ -1301,6 +1304,20 @@ public void testBuildUserPrivilegeResponse() {
"remote-index-2",
"remote-index-3"
)
.addRemoteClusterPermissions(
new RemoteClusterPermissions().addGroup(
new RemoteClusterPermissionGroup(
RemoteClusterPermissions.getSupportRemoteClusterPermissions().toArray(new String[0]),
new String[] { "remote-1" }
)
)
.addGroup(
new RemoteClusterPermissionGroup(
RemoteClusterPermissions.getSupportRemoteClusterPermissions().toArray(new String[0]),
new String[] { "remote-2", "remote-3" }
)
)
)
.build();

final GetUserPrivilegesResponse response = RBACEngine.buildUserPrivilegesResponseObject(role);
Expand Down Expand Up @@ -1357,6 +1374,25 @@ public void testBuildUserPrivilegeResponse() {
containsInAnyOrder(new FieldPermissionsDefinition.FieldGrantExcludeGroup(new String[] { "public.*" }, new String[0]))
);
assertThat(remoteIndex2.indices().getQueries(), containsInAnyOrder(query));

RemoteClusterPermissions remoteClusterPermissions = response.getRemoteClusterPermissions();
String[] allRemoteClusterPermissions = RemoteClusterPermissions.getSupportRemoteClusterPermissions().toArray(new String[0]);
assert allRemoteClusterPermissions.length == 1
: "if more remote cluster permissions are added this test needs to be updated to ensure the correct remotes receive the "
+ "correct permissions. ";
//2 groups with 3 aliases
assertThat(response.getRemoteClusterPermissions().groups(), iterableWithSize(2));
assertEquals(
3,
response.getRemoteClusterPermissions().groups().stream()
.map(RemoteClusterPermissionGroup::remoteClusterAliases).flatMap(Arrays::stream).distinct().count()
);

for(String permission : RemoteClusterPermissions.getSupportRemoteClusterPermissions()){
assertThat(Arrays.asList(remoteClusterPermissions.privilegeNames("remote-1")), hasItem(permission));
assertThat(Arrays.asList(remoteClusterPermissions.privilegeNames("remote-2")), hasItem(permission));
assertThat(Arrays.asList(remoteClusterPermissions.privilegeNames("remote-3")), hasItem(permission));
}
}

public void testBackingIndicesAreIncludedForAuthorizedDataStreams() {
Expand Down Expand Up @@ -1677,7 +1713,7 @@ public void testGetRoleDescriptorsForRemoteClusterForReservedRoles() {
new RoleDescriptorsIntersection(
new RoleDescriptor(
Role.REMOTE_USER_ROLE_NAME,
null,
RemoteClusterPermissions.getSupportRemoteClusterPermissions().toArray(new String[0]),
new IndicesPrivileges[] {
IndicesPrivileges.builder().indices("*").privileges("all").allowRestrictedIndices(false).build(),
IndicesPrivileges.builder()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1482,6 +1482,7 @@ private static ApiKey createApiKeyForOwner(String apiKeyId, String username, Str
Map.of("_key", "value"),
null,
null,
null,
null
)
),
Expand Down
Loading

0 comments on commit 435f79a

Please sign in to comment.