Skip to content

Add granular privileges for API keys #42020

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 32 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
32 commits
Select commit Hold shift + click to select a range
f58d5e0
Add granular privileges for API keys
May 8, 2019
167b98e
add check for realm name in conditional predicate
May 9, 2019
08e1163
fix test
May 9, 2019
5be1187
Merge branch 'master' into api-key-privileges
May 9, 2019
25e97ab
style fix
May 10, 2019
7cbb19e
add action instead of flags for conditional privilege
May 17, 2019
a125018
fix line length
May 17, 2019
eecbdbe
Merge branch 'master' into api-key-privileges
May 17, 2019
cccdb96
fix parser
May 17, 2019
9062acb
fix integ test
May 18, 2019
06c3c66
remove unwanted check and add check that realms and users contain onl…
May 29, 2019
68109f9
Merge branch 'master' into api-key-privileges
May 29, 2019
be7a093
provide default conditional cluster privileges for API keys
Jun 3, 2019
13a86f3
Merge branch 'master' into api-key-privileges
Jun 3, 2019
9958b81
fix error message and compilation issue
Jun 3, 2019
d69224e
keep the conditional cluster privileges same and introduce plain cond…
Jun 3, 2019
8f6caad
revert unwanted change
Jun 3, 2019
04fe24d
fix checkstyle errors
Jun 3, 2019
8952ffd
add test, javadocs, cleanup
Jun 4, 2019
3d977ec
Merge branch 'master' into api-key-privileges
Jun 11, 2019
108278c
address review comments - remove unwanted api conditional cluster pri…
Jun 11, 2019
07bb117
change ConditionalClusterPrivilege to GlobalClusterPrivilege and Plai…
Jun 11, 2019
aa07ee3
refactor cluster privilege and extract enum for default cluster privi…
Jun 11, 2019
8aeeafa
add docs
Jun 11, 2019
b20f4c3
address review comments
Jun 18, 2019
598f3de
Merge branch 'master' into api-key-privileges
Jun 18, 2019
3a1c361
remove unwanted code
Jun 18, 2019
e39e263
fix code and tests
Jun 18, 2019
9826c81
resolve precommit errors
Jun 18, 2019
d69db4e
address intermittent failure
Jun 18, 2019
fa8386b
Merge branch 'master' into api-key-privileges
Jun 18, 2019
aa14195
refactor - to address review comments
Jun 19, 2019
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -313,14 +313,16 @@ public static class ClusterPrivilegeName {
public static final String MANAGE_SAML = "manage_saml";
public static final String MANAGE_OIDC = "manage_oidc";
public static final String MANAGE_TOKEN = "manage_token";
public static final String MANAGE_API_KEY = "manage_api_key";
public static final String MANAGE_PIPELINE = "manage_pipeline";
public static final String MANAGE_CCR = "manage_ccr";
public static final String READ_CCR = "read_ccr";
public static final String MANAGE_ILM = "manage_ilm";
public static final String READ_ILM = "read_ilm";
public static final String[] ALL_ARRAY = new String[] { NONE, ALL, MONITOR, MONITOR_ML, MONITOR_WATCHER, MONITOR_ROLLUP, MANAGE,
MANAGE_ML, MANAGE_WATCHER, MANAGE_ROLLUP, MANAGE_INDEX_TEMPLATES, MANAGE_INGEST_PIPELINES, TRANSPORT_CLIENT,
MANAGE_SECURITY, MANAGE_SAML, MANAGE_OIDC, MANAGE_TOKEN, MANAGE_PIPELINE, MANAGE_CCR, READ_CCR, MANAGE_ILM, READ_ILM};
MANAGE_SECURITY, MANAGE_SAML, MANAGE_OIDC, MANAGE_TOKEN, MANAGE_API_KEY, MANAGE_PIPELINE, MANAGE_CCR, READ_CCR, MANAGE_ILM,
READ_ILM };
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@
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.ConditionalClusterPrivilege;
import org.elasticsearch.xpack.core.security.authz.privilege.GlobalClusterPrivilege;
import org.elasticsearch.xpack.core.security.user.User;

import java.util.ArrayList;
Expand Down Expand Up @@ -199,7 +199,7 @@ private HasPrivilegesResponse getHasPrivilegesResponse(Authentication authentica

private GetUserPrivilegesResponse getUserPrivilegesResponse(boolean isSuperuser) {
final Set<String> cluster = isSuperuser ? Collections.singleton("ALL") : Collections.emptySet();
final Set<ConditionalClusterPrivilege> conditionalCluster = Collections.emptySet();
final Set<GlobalClusterPrivilege> conditionalCluster = Collections.emptySet();
final Set<GetUserPrivilegesResponse.Indices> indices = isSuperuser ? Collections.singleton(new Indices(Collections.singleton("*"),
Collections.singleton("*"), Collections.emptySet(), Collections.emptySet(), true)) : Collections.emptySet();

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -168,8 +168,8 @@
import org.elasticsearch.xpack.core.security.authc.support.mapper.expressiondsl.ExceptExpression;
import org.elasticsearch.xpack.core.security.authc.support.mapper.expressiondsl.FieldExpression;
import org.elasticsearch.xpack.core.security.authc.support.mapper.expressiondsl.RoleMapperExpression;
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.ManageApplicationPrivileges;
import org.elasticsearch.xpack.core.security.authz.privilege.GlobalClusterPrivilege;
import org.elasticsearch.xpack.core.sql.SqlFeatureSetUsage;
import org.elasticsearch.xpack.core.ssl.action.GetCertificateInfoAction;
import org.elasticsearch.xpack.core.upgrade.actions.IndexUpgradeAction;
Expand Down Expand Up @@ -386,9 +386,9 @@ public List<NamedWriteableRegistry.Entry> getNamedWriteables() {
new NamedWriteableRegistry.Entry(NamedDiff.class, TokenMetaData.TYPE, TokenMetaData::readDiffFrom),
new NamedWriteableRegistry.Entry(XPackFeatureSet.Usage.class, XPackField.SECURITY, SecurityFeatureSetUsage::new),
// security : conditional privileges
new NamedWriteableRegistry.Entry(ConditionalClusterPrivilege.class,
ConditionalClusterPrivileges.ManageApplicationPrivileges.WRITEABLE_NAME,
ConditionalClusterPrivileges.ManageApplicationPrivileges::createFrom),
new NamedWriteableRegistry.Entry(GlobalClusterPrivilege.class,
ManageApplicationPrivileges.WRITEABLE_NAME,
ManageApplicationPrivileges::createFrom),
// security : role-mappings
new NamedWriteableRegistry.Entry(RoleMapperExpression.class, AllExpression.NAME, AllExpression::new),
new NamedWriteableRegistry.Entry(RoleMapperExpression.class, AnyExpression.NAME, AnyExpression::new),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -117,16 +117,6 @@ public ActionRequestValidationException validate() {
validationException = addValidationError("One of [api key id, api key name, username, realm name] must be specified",
validationException);
}
if (Strings.hasText(apiKeyId) || Strings.hasText(apiKeyName)) {
if (Strings.hasText(realmName) || Strings.hasText(userName)) {
validationException = addValidationError(
"username or realm name must not be specified when the api key id or api key name is specified",
validationException);
}
}
if (Strings.hasText(apiKeyId) && Strings.hasText(apiKeyName)) {
validationException = addValidationError("only one of [api key id, api key name] can be specified", validationException);
}
return validationException;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -117,16 +117,6 @@ public ActionRequestValidationException validate() {
validationException = addValidationError("One of [api key id, api key name, username, realm name] must be specified",
validationException);
}
if (Strings.hasText(id) || Strings.hasText(name)) {
if (Strings.hasText(realmName) || Strings.hasText(userName)) {
validationException = addValidationError(
"username or realm name must not be specified when the api key id or api key name is specified",
validationException);
}
}
if (Strings.hasText(id) && Strings.hasText(name)) {
validationException = addValidationError("only one of [api key id, api key name] can be specified", validationException);
}
return validationException;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,8 @@
import org.elasticsearch.common.io.stream.StreamOutput;
import org.elasticsearch.xpack.core.security.authz.RoleDescriptor;
import org.elasticsearch.xpack.core.security.authz.privilege.ApplicationPrivilege;
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.GlobalClusterPrivilege;
import org.elasticsearch.xpack.core.security.authz.privilege.GlobalClusterPrivileges;
import org.elasticsearch.xpack.core.security.support.MetadataUtils;

import java.io.IOException;
Expand All @@ -35,7 +35,7 @@ public class PutRoleRequest extends ActionRequest implements WriteRequest<PutRol

private String name;
private String[] clusterPrivileges = Strings.EMPTY_ARRAY;
private ConditionalClusterPrivilege[] conditionalClusterPrivileges = ConditionalClusterPrivileges.EMPTY_ARRAY;
private GlobalClusterPrivilege[] conditionalClusterPrivileges = GlobalClusterPrivileges.EMPTY_ARRAY;
private List<RoleDescriptor.IndicesPrivileges> indicesPrivileges = new ArrayList<>();
private List<RoleDescriptor.ApplicationResourcePrivileges> applicationPrivileges = new ArrayList<>();
private String[] runAs = Strings.EMPTY_ARRAY;
Expand Down Expand Up @@ -82,7 +82,7 @@ public void cluster(String... clusterPrivileges) {
this.clusterPrivileges = clusterPrivileges;
}

void conditionalCluster(ConditionalClusterPrivilege... conditionalClusterPrivileges) {
void conditionalCluster(GlobalClusterPrivilege... conditionalClusterPrivileges) {
this.conditionalClusterPrivileges = conditionalClusterPrivileges;
}

Expand Down Expand Up @@ -145,7 +145,7 @@ public List<RoleDescriptor.ApplicationResourcePrivileges> applicationPrivileges(
return Collections.unmodifiableList(applicationPrivileges);
}

public ConditionalClusterPrivilege[] conditionalClusterPrivileges() {
public GlobalClusterPrivilege[] conditionalClusterPrivileges() {
return conditionalClusterPrivileges;
}

Expand All @@ -168,7 +168,7 @@ public void readFrom(StreamInput in) throws IOException {
indicesPrivileges.add(new RoleDescriptor.IndicesPrivileges(in));
}
applicationPrivileges = in.readList(RoleDescriptor.ApplicationResourcePrivileges::new);
conditionalClusterPrivileges = ConditionalClusterPrivileges.readArray(in);
conditionalClusterPrivileges = GlobalClusterPrivileges.readArray(in);
runAs = in.readStringArray();
refreshPolicy = RefreshPolicy.readFrom(in);
metadata = in.readMap();
Expand All @@ -184,7 +184,7 @@ public void writeTo(StreamOutput out) throws IOException {
index.writeTo(out);
}
out.writeList(applicationPrivileges);
ConditionalClusterPrivileges.writeArray(out, this.conditionalClusterPrivileges);
GlobalClusterPrivileges.writeArray(out, this.conditionalClusterPrivileges);
out.writeStringArray(runAs);
refreshPolicy.writeTo(out);
out.writeMap(metadata);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,8 @@
import org.elasticsearch.common.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.privilege.ConditionalClusterPrivilege;
import org.elasticsearch.xpack.core.security.authz.privilege.ConditionalClusterPrivileges;
import org.elasticsearch.xpack.core.security.authz.privilege.GlobalClusterPrivilege;
import org.elasticsearch.xpack.core.security.authz.privilege.GlobalClusterPrivileges;

import java.io.IOException;
import java.util.Collection;
Expand All @@ -32,7 +32,7 @@
public final class GetUserPrivilegesResponse extends ActionResponse {

private Set<String> cluster;
private Set<ConditionalClusterPrivilege> conditionalCluster;
private Set<GlobalClusterPrivilege> conditionalCluster;
private Set<Indices> index;
private Set<RoleDescriptor.ApplicationResourcePrivileges> application;
private Set<String> runAs;
Expand All @@ -41,7 +41,7 @@ public GetUserPrivilegesResponse() {
this(Collections.emptySet(), Collections.emptySet(), Collections.emptySet(), Collections.emptySet(), Collections.emptySet());
}

public GetUserPrivilegesResponse(Set<String> cluster, Set<ConditionalClusterPrivilege> conditionalCluster,
public GetUserPrivilegesResponse(Set<String> cluster, Set<GlobalClusterPrivilege> conditionalCluster,
Set<Indices> index,
Set<RoleDescriptor.ApplicationResourcePrivileges> application,
Set<String> runAs) {
Expand All @@ -56,7 +56,7 @@ public Set<String> getClusterPrivileges() {
return cluster;
}

public Set<ConditionalClusterPrivilege> getConditionalClusterPrivileges() {
public Set<GlobalClusterPrivilege> getConditionalClusterPrivileges() {
return conditionalCluster;
}

Expand All @@ -75,7 +75,7 @@ public Set<String> getRunAs() {
public void readFrom(StreamInput in) throws IOException {
super.readFrom(in);
cluster = Collections.unmodifiableSet(in.readSet(StreamInput::readString));
conditionalCluster = Collections.unmodifiableSet(in.readSet(ConditionalClusterPrivileges.READER));
conditionalCluster = Collections.unmodifiableSet(in.readSet(GlobalClusterPrivileges.READER));
index = Collections.unmodifiableSet(in.readSet(Indices::new));
application = Collections.unmodifiableSet(in.readSet(RoleDescriptor.ApplicationResourcePrivileges::new));
runAs = Collections.unmodifiableSet(in.readSet(StreamInput::readString));
Expand All @@ -85,7 +85,7 @@ public void readFrom(StreamInput in) throws IOException {
public void writeTo(StreamOutput out) throws IOException {
super.writeTo(out);
out.writeCollection(cluster, StreamOutput::writeString);
out.writeCollection(conditionalCluster, ConditionalClusterPrivileges.WRITER);
out.writeCollection(conditionalCluster, GlobalClusterPrivileges.WRITER);
out.writeCollection(index);
out.writeCollection(application);
out.writeCollection(runAs, StreamOutput::writeString);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,8 @@
import org.elasticsearch.common.xcontent.XContentParser;
import org.elasticsearch.common.xcontent.XContentType;
import org.elasticsearch.common.xcontent.json.JsonXContent;
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.GlobalClusterPrivilege;
import org.elasticsearch.xpack.core.security.authz.privilege.GlobalClusterPrivileges;
import org.elasticsearch.xpack.core.security.support.Validation;
import org.elasticsearch.xpack.core.security.xcontent.XContentUtils;

Expand All @@ -48,7 +48,7 @@ public class RoleDescriptor implements ToXContentObject, Writeable {

private final String name;
private final String[] clusterPrivileges;
private final ConditionalClusterPrivilege[] conditionalClusterPrivileges;
private final GlobalClusterPrivilege[] conditionalClusterPrivileges;
private final IndicesPrivileges[] indicesPrivileges;
private final ApplicationResourcePrivileges[] applicationPrivileges;
private final String[] runAs;
Expand All @@ -64,7 +64,7 @@ public RoleDescriptor(String name,

/**
* @deprecated Use {@link #RoleDescriptor(String, String[], IndicesPrivileges[], ApplicationResourcePrivileges[],
* ConditionalClusterPrivilege[], String[], Map, Map)}
* GlobalClusterPrivilege[], String[], Map, Map)}
*/
@Deprecated
public RoleDescriptor(String name,
Expand All @@ -77,7 +77,7 @@ public RoleDescriptor(String name,

/**
* @deprecated Use {@link #RoleDescriptor(String, String[], IndicesPrivileges[], ApplicationResourcePrivileges[],
* ConditionalClusterPrivilege[], String[], Map, Map)}
* GlobalClusterPrivilege[], String[], Map, Map)}
*/
@Deprecated
public RoleDescriptor(String name,
Expand All @@ -93,14 +93,14 @@ public RoleDescriptor(String name,
@Nullable String[] clusterPrivileges,
@Nullable IndicesPrivileges[] indicesPrivileges,
@Nullable ApplicationResourcePrivileges[] applicationPrivileges,
@Nullable ConditionalClusterPrivilege[] conditionalClusterPrivileges,
@Nullable GlobalClusterPrivilege[] conditionalClusterPrivileges,
@Nullable String[] runAs,
@Nullable Map<String, Object> metadata,
@Nullable Map<String, Object> transientMetadata) {
this.name = name;
this.clusterPrivileges = clusterPrivileges != null ? clusterPrivileges : Strings.EMPTY_ARRAY;
this.conditionalClusterPrivileges = conditionalClusterPrivileges != null
? conditionalClusterPrivileges : ConditionalClusterPrivileges.EMPTY_ARRAY;
? conditionalClusterPrivileges : GlobalClusterPrivileges.EMPTY_ARRAY;
this.indicesPrivileges = indicesPrivileges != null ? indicesPrivileges : IndicesPrivileges.NONE;
this.applicationPrivileges = applicationPrivileges != null ? applicationPrivileges : ApplicationResourcePrivileges.NONE;
this.runAs = runAs != null ? runAs : Strings.EMPTY_ARRAY;
Expand All @@ -122,7 +122,7 @@ public RoleDescriptor(StreamInput in) throws IOException {
this.transientMetadata = in.readMap();

this.applicationPrivileges = in.readArray(ApplicationResourcePrivileges::new, ApplicationResourcePrivileges[]::new);
this.conditionalClusterPrivileges = ConditionalClusterPrivileges.readArray(in);
this.conditionalClusterPrivileges = GlobalClusterPrivileges.readArray(in);
}

public String getName() {
Expand All @@ -133,7 +133,7 @@ public String[] getClusterPrivileges() {
return this.clusterPrivileges;
}

public ConditionalClusterPrivilege[] getConditionalClusterPrivileges() {
public GlobalClusterPrivilege[] getConditionalClusterPrivileges() {
return this.conditionalClusterPrivileges;
}

Expand Down Expand Up @@ -231,7 +231,7 @@ public XContentBuilder toXContent(XContentBuilder builder, Params params, boolea
builder.array(Fields.CLUSTER.getPreferredName(), clusterPrivileges);
if (conditionalClusterPrivileges.length != 0) {
builder.field(Fields.GLOBAL.getPreferredName());
ConditionalClusterPrivileges.toXContent(builder, params, Arrays.asList(conditionalClusterPrivileges));
GlobalClusterPrivileges.toXContent(builder, params, Arrays.asList(conditionalClusterPrivileges));
}
builder.array(Fields.INDICES.getPreferredName(), (Object[]) indicesPrivileges);
builder.array(Fields.APPLICATIONS.getPreferredName(), (Object[]) applicationPrivileges);
Expand Down Expand Up @@ -259,7 +259,7 @@ public void writeTo(StreamOutput out) throws IOException {
out.writeMap(metadata);
out.writeMap(transientMetadata);
out.writeArray(ApplicationResourcePrivileges::write, applicationPrivileges);
ConditionalClusterPrivileges.writeArray(out, getConditionalClusterPrivileges());
GlobalClusterPrivileges.writeArray(out, getConditionalClusterPrivileges());
}

public static RoleDescriptor parse(String name, BytesReference source, boolean allow2xFormat, XContentType xContentType)
Expand Down Expand Up @@ -290,7 +290,7 @@ public static RoleDescriptor parse(String name, XContentParser parser, boolean a
String currentFieldName = null;
IndicesPrivileges[] indicesPrivileges = null;
String[] clusterPrivileges = null;
List<ConditionalClusterPrivilege> conditionalClusterPrivileges = Collections.emptyList();
List<GlobalClusterPrivilege> conditionalClusterPrivileges = Collections.emptyList();
ApplicationResourcePrivileges[] applicationPrivileges = null;
String[] runAsUsers = null;
Map<String, Object> metadata = null;
Expand All @@ -308,7 +308,7 @@ public static RoleDescriptor parse(String name, XContentParser parser, boolean a
|| Fields.APPLICATION.match(currentFieldName, parser.getDeprecationHandler())) {
applicationPrivileges = parseApplicationPrivileges(name, parser);
} else if (Fields.GLOBAL.match(currentFieldName, parser.getDeprecationHandler())) {
conditionalClusterPrivileges = ConditionalClusterPrivileges.parse(parser);
conditionalClusterPrivileges = GlobalClusterPrivileges.parse(parser);
} else if (Fields.METADATA.match(currentFieldName, parser.getDeprecationHandler())) {
if (token != XContentParser.Token.START_OBJECT) {
throw new ElasticsearchParseException(
Expand All @@ -329,7 +329,7 @@ public static RoleDescriptor parse(String name, XContentParser parser, boolean a
}
}
return new RoleDescriptor(name, clusterPrivileges, indicesPrivileges, applicationPrivileges,
conditionalClusterPrivileges.toArray(new ConditionalClusterPrivilege[conditionalClusterPrivileges.size()]), runAsUsers,
conditionalClusterPrivileges.toArray(new GlobalClusterPrivilege[conditionalClusterPrivileges.size()]), runAsUsers,
metadata, null);
}

Expand Down
Loading