-
Notifications
You must be signed in to change notification settings - Fork 24.3k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Cluster-state based Security role mapper (#107410)
This implements a new UserRoleMapper that sources the role mapping rules from the cluster state. The role mapping rules are stored under a new custom cluster state that is persisted (both disk and snapshots). The role mapper refreshes realm caches when role mapping changes are published. The role mapper is disabled by default, and it can only be enabled from code, by other plugins. When enabled, the cluster state role mappings rules, if any, are additive to the rules from the index-based native role mapping store and the file-based DN one.
- Loading branch information
1 parent
03651dc
commit 768a001
Showing
25 changed files
with
1,328 additions
and
100 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
pr: 107410 | ||
summary: Cluster-state based Security role mapper | ||
area: Authorization | ||
type: enhancement | ||
issues: [] |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
129 changes: 129 additions & 0 deletions
129
...n/core/src/main/java/org/elasticsearch/xpack/core/security/authz/RoleMappingMetadata.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,129 @@ | ||
/* | ||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one | ||
* or more contributor license agreements. Licensed under the Elastic License | ||
* 2.0; you may not use this file except in compliance with the Elastic License | ||
* 2.0. | ||
*/ | ||
|
||
package org.elasticsearch.xpack.core.security.authz; | ||
|
||
import org.elasticsearch.TransportVersion; | ||
import org.elasticsearch.TransportVersions; | ||
import org.elasticsearch.cluster.AbstractNamedDiffable; | ||
import org.elasticsearch.cluster.ClusterState; | ||
import org.elasticsearch.cluster.NamedDiff; | ||
import org.elasticsearch.cluster.metadata.Metadata; | ||
import org.elasticsearch.common.collect.Iterators; | ||
import org.elasticsearch.common.io.stream.StreamInput; | ||
import org.elasticsearch.common.io.stream.StreamOutput; | ||
import org.elasticsearch.common.xcontent.ChunkedToXContentHelper; | ||
import org.elasticsearch.xcontent.ToXContent; | ||
import org.elasticsearch.xpack.core.security.authc.support.mapper.ExpressionRoleMapping; | ||
|
||
import java.io.IOException; | ||
import java.util.EnumSet; | ||
import java.util.Iterator; | ||
import java.util.Objects; | ||
import java.util.Set; | ||
|
||
import static org.elasticsearch.cluster.metadata.Metadata.ALL_CONTEXTS; | ||
|
||
public final class RoleMappingMetadata extends AbstractNamedDiffable<Metadata.Custom> implements Metadata.Custom { | ||
|
||
public static final String TYPE = "role_mappings"; | ||
|
||
private static final RoleMappingMetadata EMPTY = new RoleMappingMetadata(Set.of()); | ||
|
||
public static RoleMappingMetadata getFromClusterState(ClusterState clusterState) { | ||
return clusterState.metadata().custom(RoleMappingMetadata.TYPE, RoleMappingMetadata.EMPTY); | ||
} | ||
|
||
private final Set<ExpressionRoleMapping> roleMappings; | ||
|
||
public RoleMappingMetadata(Set<ExpressionRoleMapping> roleMappings) { | ||
this.roleMappings = roleMappings; | ||
} | ||
|
||
public RoleMappingMetadata(StreamInput input) throws IOException { | ||
this.roleMappings = input.readCollectionAsSet(ExpressionRoleMapping::new); | ||
} | ||
|
||
public Set<ExpressionRoleMapping> getRoleMappings() { | ||
return this.roleMappings; | ||
} | ||
|
||
public boolean isEmpty() { | ||
return roleMappings.isEmpty(); | ||
} | ||
|
||
public ClusterState updateClusterState(ClusterState clusterState) { | ||
if (isEmpty()) { | ||
// prefer no role mapping custom metadata to the empty role mapping metadata | ||
return clusterState.copyAndUpdateMetadata(b -> b.removeCustom(RoleMappingMetadata.TYPE)); | ||
} else { | ||
return clusterState.copyAndUpdateMetadata(b -> b.putCustom(RoleMappingMetadata.TYPE, this)); | ||
} | ||
} | ||
|
||
public static NamedDiff<Metadata.Custom> readDiffFrom(StreamInput streamInput) throws IOException { | ||
return readDiffFrom(Metadata.Custom.class, TYPE, streamInput); | ||
} | ||
|
||
@Override | ||
public Iterator<? extends ToXContent> toXContentChunked(ToXContent.Params params) { | ||
return Iterators.concat(ChunkedToXContentHelper.startArray(TYPE), roleMappings.iterator(), ChunkedToXContentHelper.endArray()); | ||
} | ||
|
||
@Override | ||
public String getWriteableName() { | ||
return TYPE; | ||
} | ||
|
||
@Override | ||
public TransportVersion getMinimalSupportedVersion() { | ||
return TransportVersions.SECURITY_ROLE_MAPPINGS_IN_CLUSTER_STATE; | ||
} | ||
|
||
@Override | ||
public void writeTo(StreamOutput out) throws IOException { | ||
out.writeCollection(roleMappings); | ||
} | ||
|
||
@Override | ||
public boolean equals(Object o) { | ||
if (this == o) return true; | ||
if (o == null || getClass() != o.getClass()) return false; | ||
final var other = (RoleMappingMetadata) o; | ||
return Objects.equals(roleMappings, other.roleMappings); | ||
} | ||
|
||
@Override | ||
public int hashCode() { | ||
return Objects.hash(roleMappings); | ||
} | ||
|
||
@Override | ||
public String toString() { | ||
StringBuilder builder = new StringBuilder("RoleMapping[entries=["); | ||
final Iterator<ExpressionRoleMapping> entryList = roleMappings.iterator(); | ||
boolean firstEntry = true; | ||
while (entryList.hasNext()) { | ||
if (firstEntry == false) { | ||
builder.append(","); | ||
} | ||
builder.append(entryList.next().toString()); | ||
firstEntry = false; | ||
} | ||
return builder.append("]]").toString(); | ||
} | ||
|
||
@Override | ||
public EnumSet<Metadata.XContentContext> context() { | ||
// It is safest to have this persisted to gateway and snapshots, although maybe redundant. | ||
// The persistence can become an issue in cases where {@link ReservedStateMetadata} | ||
// (which records the names of the role mappings last applied) is persisted, | ||
// but the role mappings themselves (stored here by the {@link RoleMappingMetadata}) | ||
// are not persisted. | ||
return ALL_CONTEXTS; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.