From 36a3e5c0d2f36d5d130192d7d431c05d6f2a915f Mon Sep 17 00:00:00 2001 From: Slobodan Adamovic Date: Fri, 12 Apr 2024 17:03:02 +0200 Subject: [PATCH 1/3] Refactor role descriptor parsing The method for `RoleDescriptor` parsing is becoming more complex due to its usage being shared between API keys, file-based and native roles. In some cases we allow 2.X format, in others we disallow restrictions. Having a single method with multiple boolean flags that control inclusion/exclusion of fields is becoming hard to extend. This refactoring aims to allow easier introduction of new fields that should be conditionally supported in some cases but not others. One of such cases is introduction of `description` field that should only be supported for file-based and native roles but not for roles embedded in API keys. --- .../core/security/action/apikey/ApiKey.java | 2 +- .../BulkUpdateApiKeyRequestTranslator.java | 2 +- .../apikey/CreateApiKeyRequestBuilder.java | 2 +- .../apikey/UpdateApiKeyRequestTranslator.java | 4 +- .../action/role/PutRoleRequestBuilder.java | 5 +- .../authc/CrossClusterAccessSubjectInfo.java | 2 +- .../core/security/authz/RoleDescriptor.java | 195 ++++++++++-------- .../authz/RoleDescriptorsIntersection.java | 2 +- .../GetServiceAccountResponseTests.java | 8 +- .../security/authz/RoleDescriptorTests.java | 82 ++++---- ...RoleWithRemoteIndicesPrivilegesRestIT.java | 2 +- .../security/authc/ApiKeyIntegTests.java | 13 +- .../authc/apikey/ApiKeySingleNodeTests.java | 20 +- .../xpack/security/authc/ApiKeyService.java | 4 +- .../security/authz/store/FileRolesStore.java | 5 +- .../authz/store/NativeRolesStore.java | 5 +- .../test/TestSecurityClient.java | 2 +- .../security/authc/ApiKeyServiceTests.java | 2 +- .../permission/FieldPermissionsTests.java | 34 +-- 19 files changed, 202 insertions(+), 189 deletions(-) diff --git a/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/security/action/apikey/ApiKey.java b/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/security/action/apikey/ApiKey.java index 0120ed09e8fe4..f358df6c39cfe 100644 --- a/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/security/action/apikey/ApiKey.java +++ b/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/security/action/apikey/ApiKey.java @@ -419,7 +419,7 @@ static int initializeParser(AbstractObjectParser parser) { parser.declareObject(optionalConstructorArg(), (p, c) -> p.map(), new ParseField("metadata")); parser.declareNamedObjects(optionalConstructorArg(), (p, c, n) -> { p.nextToken(); - return RoleDescriptor.parse(n, p, false); + return RoleDescriptor.parser().allowRestriction(true).parse(n, p); }, new ParseField("role_descriptors")); parser.declareField( optionalConstructorArg(), diff --git a/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/security/action/apikey/BulkUpdateApiKeyRequestTranslator.java b/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/security/action/apikey/BulkUpdateApiKeyRequestTranslator.java index 57a5848970b2e..52039a6f11c93 100644 --- a/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/security/action/apikey/BulkUpdateApiKeyRequestTranslator.java +++ b/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/security/action/apikey/BulkUpdateApiKeyRequestTranslator.java @@ -27,7 +27,7 @@ public interface BulkUpdateApiKeyRequestTranslator { class Default implements BulkUpdateApiKeyRequestTranslator { private static final ConstructingObjectParser PARSER = createParser( - (n, p) -> RoleDescriptor.parse(n, p, false) + (n, p) -> RoleDescriptor.parser().allowRestriction(true).parse(n, p) ); @SuppressWarnings("unchecked") diff --git a/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/security/action/apikey/CreateApiKeyRequestBuilder.java b/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/security/action/apikey/CreateApiKeyRequestBuilder.java index 5c156ab4e6166..5d07bdf44ecaa 100644 --- a/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/security/action/apikey/CreateApiKeyRequestBuilder.java +++ b/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/security/action/apikey/CreateApiKeyRequestBuilder.java @@ -32,7 +32,7 @@ */ public class CreateApiKeyRequestBuilder extends ActionRequestBuilder { private static final ConstructingObjectParser PARSER = createParser( - (n, p) -> RoleDescriptor.parse(n, p, false) + (n, p) -> RoleDescriptor.parser().allowRestriction(true).parse(n, p) ); @SuppressWarnings("unchecked") diff --git a/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/security/action/apikey/UpdateApiKeyRequestTranslator.java b/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/security/action/apikey/UpdateApiKeyRequestTranslator.java index f70732dd50990..e39c8449ddbf2 100644 --- a/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/security/action/apikey/UpdateApiKeyRequestTranslator.java +++ b/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/security/action/apikey/UpdateApiKeyRequestTranslator.java @@ -25,7 +25,9 @@ public interface UpdateApiKeyRequestTranslator { UpdateApiKeyRequest translate(RestRequest request) throws IOException; class Default implements UpdateApiKeyRequestTranslator { - private static final ConstructingObjectParser PARSER = createParser((n, p) -> RoleDescriptor.parse(n, p, false)); + private static final ConstructingObjectParser PARSER = createParser( + (n, p) -> RoleDescriptor.parser().allowRestriction(true).parse(n, p) + ); @SuppressWarnings("unchecked") protected static ConstructingObjectParser createParser( diff --git a/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/security/action/role/PutRoleRequestBuilder.java b/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/security/action/role/PutRoleRequestBuilder.java index f389a39df7979..3d6f30803c6c1 100644 --- a/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/security/action/role/PutRoleRequestBuilder.java +++ b/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/security/action/role/PutRoleRequestBuilder.java @@ -29,9 +29,8 @@ public PutRoleRequestBuilder(ElasticsearchClient client) { * Populate the put role request from the source and the role's name */ public PutRoleRequestBuilder source(String name, BytesReference source, XContentType xContentType) throws IOException { - // we pass false as last parameter because we want to reject the request if field permissions - // are given in 2.x syntax - RoleDescriptor descriptor = RoleDescriptor.parse(name, source, false, xContentType, false); + // we want to reject the request if field permissions are given in 2.x syntax, hence we do not allow2xFormat + RoleDescriptor descriptor = RoleDescriptor.parser().parse(name, source, xContentType); assert name.equals(descriptor.getName()); request.name(name); request.cluster(descriptor.getClusterPrivileges()); diff --git a/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/security/authc/CrossClusterAccessSubjectInfo.java b/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/security/authc/CrossClusterAccessSubjectInfo.java index b6b54846fc7c4..efb452667402d 100644 --- a/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/security/authc/CrossClusterAccessSubjectInfo.java +++ b/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/security/authc/CrossClusterAccessSubjectInfo.java @@ -263,7 +263,7 @@ public Set toRoleDescriptors() { while (parser.nextToken() != XContentParser.Token.END_OBJECT) { parser.nextToken(); final String roleName = parser.currentName(); - roleDescriptors.add(RoleDescriptor.parse(roleName, parser, false)); + roleDescriptors.add(RoleDescriptor.parser().parse(roleName, parser)); } return Set.copyOf(roleDescriptors); } catch (IOException e) { diff --git a/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/security/authz/RoleDescriptor.java b/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/security/authz/RoleDescriptor.java index ecbd12a7f4643..1e41223d287b7 100644 --- a/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/security/authz/RoleDescriptor.java +++ b/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/security/authz/RoleDescriptor.java @@ -420,80 +420,105 @@ public void writeTo(StreamOutput out) throws IOException { } } - public static RoleDescriptor parse(String name, BytesReference source, boolean allow2xFormat, XContentType xContentType) - throws IOException { - return parse(name, source, allow2xFormat, xContentType, true); + public static Parser parser() { + return new Parser(); } - public static RoleDescriptor parse( - String name, - BytesReference source, - boolean allow2xFormat, - XContentType xContentType, - boolean allowRestriction - ) throws IOException { - assert name != null; - try (XContentParser parser = createParser(source, xContentType)) { - return parse(name, parser, allow2xFormat, allowRestriction); - } - } + public static final class Parser { - public static RoleDescriptor parse(String name, XContentParser parser, boolean allow2xFormat) throws IOException { - return parse(name, parser, allow2xFormat, true); - } + private boolean allow2xFormat = false; + private boolean allowRestriction = false; - public static RoleDescriptor parse(String name, XContentParser parser, boolean allow2xFormat, boolean allowRestriction) - throws IOException { - // validate name - Validation.Error validationError = Validation.Roles.validateRoleName(name, true); - if (validationError != null) { - ValidationException ve = new ValidationException(); - ve.addValidationError(validationError.toString()); - throw ve; + private Parser() {} + + public Parser allow2xFormat(boolean allow2xFormat) { + this.allow2xFormat = allow2xFormat; + return this; } - // advance to the START_OBJECT token if needed - XContentParser.Token token = parser.currentToken() == null ? parser.nextToken() : parser.currentToken(); - if (token != XContentParser.Token.START_OBJECT) { - throw new ElasticsearchParseException("failed to parse role [{}]. expected an object but found [{}] instead", name, token); + public Parser allowRestriction(boolean allowRestriction) { + this.allowRestriction = allowRestriction; + return this; } - String currentFieldName = null; - IndicesPrivileges[] indicesPrivileges = null; - RemoteIndicesPrivileges[] remoteIndicesPrivileges = null; - String[] clusterPrivileges = null; - List configurableClusterPrivileges = Collections.emptyList(); - ApplicationResourcePrivileges[] applicationPrivileges = null; - String[] runAsUsers = null; - Restriction restriction = null; - Map metadata = null; - while ((token = parser.nextToken()) != XContentParser.Token.END_OBJECT) { - if (token == XContentParser.Token.FIELD_NAME) { - currentFieldName = parser.currentName(); - } else if (Fields.INDEX.match(currentFieldName, parser.getDeprecationHandler()) - || Fields.INDICES.match(currentFieldName, parser.getDeprecationHandler())) { - indicesPrivileges = parseIndices(name, parser, allow2xFormat); - } else if (Fields.RUN_AS.match(currentFieldName, parser.getDeprecationHandler())) { - runAsUsers = readStringArray(name, parser, true); - } else if (Fields.CLUSTER.match(currentFieldName, parser.getDeprecationHandler())) { - clusterPrivileges = readStringArray(name, parser, true); - } else if (Fields.APPLICATIONS.match(currentFieldName, parser.getDeprecationHandler()) - || Fields.APPLICATION.match(currentFieldName, parser.getDeprecationHandler())) { - applicationPrivileges = parseApplicationPrivileges(name, parser); - } else if (Fields.GLOBAL.match(currentFieldName, parser.getDeprecationHandler())) { - configurableClusterPrivileges = ConfigurableClusterPrivileges.parse(parser); - } else if (Fields.METADATA.match(currentFieldName, parser.getDeprecationHandler())) { - if (token != XContentParser.Token.START_OBJECT) { - throw new ElasticsearchParseException( - "expected field [{}] to be of type object, but found [{}] instead", - currentFieldName, - token - ); - } - metadata = parser.map(); - } else if (Fields.TRANSIENT_METADATA.match(currentFieldName, parser.getDeprecationHandler())) { - if (token == XContentParser.Token.START_OBJECT) { - // consume object but just drop - parser.map(); + + public RoleDescriptor parse(String name, BytesReference source, XContentType xContentType) throws IOException { + assert name != null; + try ( + XContentParser parser = XContentHelper.createParserNotCompressed( + LoggingDeprecationHandler.XCONTENT_PARSER_CONFIG, + source, + xContentType + ) + ) { + return parse(name, parser); + } + } + + public RoleDescriptor parse(String name, XContentParser parser) throws IOException { + // validate name + Validation.Error validationError = Validation.Roles.validateRoleName(name, true); + if (validationError != null) { + ValidationException ve = new ValidationException(); + ve.addValidationError(validationError.toString()); + throw ve; + } + + // advance to the START_OBJECT token if needed + XContentParser.Token token = parser.currentToken() == null ? parser.nextToken() : parser.currentToken(); + if (token != XContentParser.Token.START_OBJECT) { + throw new ElasticsearchParseException("failed to parse role [{}]. expected an object but found [{}] instead", name, token); + } + String currentFieldName = null; + IndicesPrivileges[] indicesPrivileges = null; + RemoteIndicesPrivileges[] remoteIndicesPrivileges = null; + String[] clusterPrivileges = null; + List configurableClusterPrivileges = Collections.emptyList(); + ApplicationResourcePrivileges[] applicationPrivileges = null; + String[] runAsUsers = null; + Restriction restriction = null; + Map metadata = null; + String description = null; + while ((token = parser.nextToken()) != XContentParser.Token.END_OBJECT) { + if (token == XContentParser.Token.FIELD_NAME) { + currentFieldName = parser.currentName(); + } else if (Fields.INDEX.match(currentFieldName, parser.getDeprecationHandler()) + || Fields.INDICES.match(currentFieldName, parser.getDeprecationHandler())) { + indicesPrivileges = parseIndices(name, parser, allow2xFormat); + } else if (Fields.RUN_AS.match(currentFieldName, parser.getDeprecationHandler())) { + runAsUsers = readStringArray(name, parser, true); + } else if (Fields.CLUSTER.match(currentFieldName, parser.getDeprecationHandler())) { + clusterPrivileges = readStringArray(name, parser, true); + } else if (Fields.APPLICATIONS.match(currentFieldName, parser.getDeprecationHandler()) + || Fields.APPLICATION.match(currentFieldName, parser.getDeprecationHandler())) { + applicationPrivileges = parseApplicationPrivileges(name, parser); + } else if (Fields.GLOBAL.match(currentFieldName, parser.getDeprecationHandler())) { + configurableClusterPrivileges = ConfigurableClusterPrivileges.parse(parser); + } else if (Fields.METADATA.match(currentFieldName, parser.getDeprecationHandler())) { + if (token != XContentParser.Token.START_OBJECT) { + throw new ElasticsearchParseException( + "expected field [{}] to be of type object, but found [{}] instead", + currentFieldName, + token + ); + } + metadata = parser.map(); + } else if (Fields.TRANSIENT_METADATA.match(currentFieldName, parser.getDeprecationHandler())) { + if (token == XContentParser.Token.START_OBJECT) { + // consume object but just drop + parser.map(); + } else { + throw new ElasticsearchParseException( + "failed to parse role [{}]. unexpected field [{}]", + name, + currentFieldName + ); + } + } else if (Fields.REMOTE_INDICES.match(currentFieldName, parser.getDeprecationHandler())) { + remoteIndicesPrivileges = parseRemoteIndices(name, parser); + } else if (allowRestriction && Fields.RESTRICTION.match(currentFieldName, parser.getDeprecationHandler())) { + restriction = Restriction.parse(name, parser); + } else if (Fields.TYPE.match(currentFieldName, parser.getDeprecationHandler())) { + // don't need it } else { throw new ElasticsearchParseException( "failed to parse role [{}]. unexpected field [{}]", @@ -501,28 +526,22 @@ public static RoleDescriptor parse(String name, XContentParser parser, boolean a currentFieldName ); } - } else if (Fields.REMOTE_INDICES.match(currentFieldName, parser.getDeprecationHandler())) { - remoteIndicesPrivileges = parseRemoteIndices(name, parser); - } else if (allowRestriction && Fields.RESTRICTION.match(currentFieldName, parser.getDeprecationHandler())) { - restriction = Restriction.parse(name, parser); - } else if (Fields.TYPE.match(currentFieldName, parser.getDeprecationHandler())) { - // don't need it - } else { - throw new ElasticsearchParseException("failed to parse role [{}]. unexpected field [{}]", name, currentFieldName); - } + } + return new RoleDescriptor( + name, + clusterPrivileges, + indicesPrivileges, + applicationPrivileges, + configurableClusterPrivileges.toArray(new ConfigurableClusterPrivilege[configurableClusterPrivileges.size()]), + runAsUsers, + metadata, + null, + remoteIndicesPrivileges, + restriction + ); + } - return new RoleDescriptor( - name, - clusterPrivileges, - indicesPrivileges, - applicationPrivileges, - configurableClusterPrivileges.toArray(new ConfigurableClusterPrivilege[configurableClusterPrivileges.size()]), - runAsUsers, - metadata, - null, - remoteIndicesPrivileges, - restriction - ); + } private static String[] readStringArray(String roleName, XContentParser parser, boolean allowNull) throws IOException { diff --git a/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/security/authz/RoleDescriptorsIntersection.java b/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/security/authz/RoleDescriptorsIntersection.java index bdfc87a06c922..d1683b22de6c1 100644 --- a/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/security/authz/RoleDescriptorsIntersection.java +++ b/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/security/authz/RoleDescriptorsIntersection.java @@ -70,7 +70,7 @@ public static RoleDescriptorsIntersection fromXContent(XContentParser xContentPa while ((token = p.nextToken()) != XContentParser.Token.END_OBJECT) { XContentParserUtils.ensureExpectedToken(XContentParser.Token.FIELD_NAME, token, p); XContentParserUtils.ensureExpectedToken(XContentParser.Token.START_OBJECT, p.nextToken(), p); - roleDescriptors.add(RoleDescriptor.parse(p.currentName(), p, false)); + roleDescriptors.add(RoleDescriptor.parser().allowRestriction(true).parse(p.currentName(), p)); } return Set.copyOf(roleDescriptors); }); diff --git a/x-pack/plugin/core/src/test/java/org/elasticsearch/xpack/core/security/action/service/GetServiceAccountResponseTests.java b/x-pack/plugin/core/src/test/java/org/elasticsearch/xpack/core/security/action/service/GetServiceAccountResponseTests.java index b473f64a3fbf9..ee9a4d5943f71 100644 --- a/x-pack/plugin/core/src/test/java/org/elasticsearch/xpack/core/security/action/service/GetServiceAccountResponseTests.java +++ b/x-pack/plugin/core/src/test/java/org/elasticsearch/xpack/core/security/action/service/GetServiceAccountResponseTests.java @@ -97,12 +97,8 @@ private void assertRoleDescriptorEquals(Map responseFragment, Ro @SuppressWarnings("unchecked") final Map descriptorMap = (Map) responseFragment.get("role_descriptor"); assertThat( - RoleDescriptor.parse( - roleDescriptor.getName(), - XContentTestUtils.convertToXContent(descriptorMap, XContentType.JSON), - false, - XContentType.JSON - ), + RoleDescriptor.parser() + .parse(roleDescriptor.getName(), XContentTestUtils.convertToXContent(descriptorMap, XContentType.JSON), XContentType.JSON), equalTo(roleDescriptor) ); } diff --git a/x-pack/plugin/core/src/test/java/org/elasticsearch/xpack/core/security/authz/RoleDescriptorTests.java b/x-pack/plugin/core/src/test/java/org/elasticsearch/xpack/core/security/authz/RoleDescriptorTests.java index 294ad7e975286..b77cff609ab8a 100644 --- a/x-pack/plugin/core/src/test/java/org/elasticsearch/xpack/core/security/authz/RoleDescriptorTests.java +++ b/x-pack/plugin/core/src/test/java/org/elasticsearch/xpack/core/security/authz/RoleDescriptorTests.java @@ -162,13 +162,15 @@ public void testToXContentRoundtrip() throws Exception { final RoleDescriptor descriptor = randomRoleDescriptor(true, true, true); final XContentType xContentType = randomFrom(XContentType.values()); final BytesReference xContentValue = toShuffledXContent(descriptor, xContentType, ToXContent.EMPTY_PARAMS, false); - final RoleDescriptor parsed = RoleDescriptor.parse(descriptor.getName(), xContentValue, false, xContentType); + final RoleDescriptor parsed = RoleDescriptor.parser() + .allowRestriction(true) + .parse(descriptor.getName(), xContentValue, xContentType); assertThat(parsed, equalTo(descriptor)); } public void testParse() throws Exception { String q = "{\"cluster\":[\"a\", \"b\"]}"; - RoleDescriptor rd = RoleDescriptor.parse("test", new BytesArray(q), false, XContentType.JSON); + RoleDescriptor rd = RoleDescriptor.parser().parse("test", new BytesArray(q), XContentType.JSON); assertEquals("test", rd.getName()); assertArrayEquals(new String[] { "a", "b" }, rd.getClusterPrivileges()); assertEquals(0, rd.getIndicesPrivileges().length); @@ -179,7 +181,7 @@ public void testParse() throws Exception { "cluster": [ "a", "b" ], "run_as": [ "m", "n" ] }"""; - rd = RoleDescriptor.parse("test", new BytesArray(q), false, XContentType.JSON); + rd = RoleDescriptor.parser().parse("test", new BytesArray(q), XContentType.JSON); assertEquals("test", rd.getName()); assertArrayEquals(new String[] { "a", "b" }, rd.getClusterPrivileges()); assertEquals(0, rd.getIndicesPrivileges().length); @@ -246,7 +248,7 @@ public void testParse() throws Exception { "workflows": ["search_application_query"] } }"""; - rd = RoleDescriptor.parse("test", new BytesArray(q), false, XContentType.JSON); + rd = RoleDescriptor.parser().allowRestriction(true).parse("test", new BytesArray(q), XContentType.JSON); assertEquals("test", rd.getName()); assertArrayEquals(new String[] { "a", "b" }, rd.getClusterPrivileges()); assertEquals(3, rd.getIndicesPrivileges().length); @@ -274,7 +276,7 @@ public void testParse() throws Exception { } } }"""; - rd = RoleDescriptor.parse("test", new BytesArray(q), false, XContentType.JSON); + rd = RoleDescriptor.parser().parse("test", new BytesArray(q), XContentType.JSON); assertEquals("test", rd.getName()); assertArrayEquals(new String[] { "a", "b" }, rd.getClusterPrivileges()); assertEquals(1, rd.getIndicesPrivileges().length); @@ -285,7 +287,7 @@ public void testParse() throws Exception { q = """ {"cluster":["a", "b"], "metadata":{"foo":"bar"}}"""; - rd = RoleDescriptor.parse("test", new BytesArray(q), false, XContentType.JSON); + rd = RoleDescriptor.parser().parse("test", new BytesArray(q), XContentType.JSON); assertEquals("test", rd.getName()); assertArrayEquals(new String[] { "a", "b" }, rd.getClusterPrivileges()); assertEquals(0, rd.getIndicesPrivileges().length); @@ -327,7 +329,7 @@ public void testParse() throws Exception { } } }"""; - rd = RoleDescriptor.parse("test", new BytesArray(q), false, XContentType.JSON); + rd = RoleDescriptor.parser().parse("test", new BytesArray(q), XContentType.JSON); assertThat(rd.getName(), equalTo("test")); assertThat(rd.getClusterPrivileges(), arrayContaining("a", "b")); assertThat(rd.getIndicesPrivileges().length, equalTo(1)); @@ -368,7 +370,7 @@ public void testParse() throws Exception { } } }"""; - rd = RoleDescriptor.parse("testUpdateProfile", new BytesArray(q), false, XContentType.JSON); + rd = RoleDescriptor.parser().parse("testUpdateProfile", new BytesArray(q), XContentType.JSON); assertThat(rd.getName(), is("testUpdateProfile")); assertThat(rd.getClusterPrivileges(), arrayContaining("manage")); assertThat(rd.getIndicesPrivileges(), Matchers.emptyArray()); @@ -393,7 +395,7 @@ public void testParse() throws Exception { q = """ {"applications": [{"application": "myapp", "resources": ["*"], "privileges": ["login" ]}] }"""; - rd = RoleDescriptor.parse("test", new BytesArray(q), false, XContentType.JSON); + rd = RoleDescriptor.parser().parse("test", new BytesArray(q), XContentType.JSON); assertThat(rd.getName(), equalTo("test")); assertThat(rd.getClusterPrivileges(), emptyArray()); assertThat(rd.getIndicesPrivileges(), emptyArray()); @@ -407,26 +409,26 @@ public void testParse() throws Exception { {"applications":[{"not_supported": true, "resources": ["*"], "privileges": ["my-app:login" ]}] }"""; final IllegalArgumentException ex = expectThrows( IllegalArgumentException.class, - () -> RoleDescriptor.parse("test", new BytesArray(badJson), false, XContentType.JSON) + () -> RoleDescriptor.parser().parse("test", new BytesArray(badJson), XContentType.JSON) ); assertThat(ex.getMessage(), containsString("not_supported")); - rd = RoleDescriptor.parse("test_empty_restriction", new BytesArray(""" + rd = RoleDescriptor.parser().allowRestriction(true).parse("test_empty_restriction", new BytesArray(""" { "index": [{"names": "idx1", "privileges": [ "p1", "p2" ]}], "restriction":{} - }"""), false, XContentType.JSON); + }"""), XContentType.JSON); assertThat(rd.getName(), equalTo("test_empty_restriction")); assertThat(rd.hasRestriction(), equalTo(false)); assertThat(rd.hasWorkflowsRestriction(), equalTo(false)); final ElasticsearchParseException pex1 = expectThrows( ElasticsearchParseException.class, - () -> RoleDescriptor.parse("test_null_workflows", new BytesArray(""" + () -> RoleDescriptor.parser().allowRestriction(true).parse("test_null_workflows", new BytesArray(""" { "index": [{"names": ["idx1"], "privileges": [ "p1", "p2" ]}], "restriction":{"workflows":null} - }"""), false, XContentType.JSON) + }"""), XContentType.JSON) ); assertThat( pex1.getMessage(), @@ -438,11 +440,11 @@ public void testParse() throws Exception { final ElasticsearchParseException pex2 = expectThrows( ElasticsearchParseException.class, - () -> RoleDescriptor.parse("test_empty_workflows", new BytesArray(""" + () -> RoleDescriptor.parser().allowRestriction(true).parse("test_empty_workflows", new BytesArray(""" { "index": [{"names": ["idx1"], "privileges": [ "p1", "p2" ]}], "restriction":{"workflows":[]} - }"""), false, XContentType.JSON) + }"""), XContentType.JSON) ); assertThat( pex2.getMessage(), @@ -477,7 +479,7 @@ public void testParsingFieldPermissionsUsesCache() throws IOException { ] } """; - RoleDescriptor.parse("test", new BytesArray(json), false, XContentType.JSON); + RoleDescriptor.parser().parse("test", new BytesArray(json), XContentType.JSON); final int numberOfFieldSecurityBlocks = 2; final Cache.CacheStats betweenStats = fieldPermissionsCache.getCacheStats(); @@ -486,7 +488,7 @@ public void testParsingFieldPermissionsUsesCache() throws IOException { final int iterations = randomIntBetween(1, 5); for (int i = 0; i < iterations; i++) { - RoleDescriptor.parse("test", new BytesArray(json), false, XContentType.JSON); + RoleDescriptor.parser().parse("test", new BytesArray(json), XContentType.JSON); } final Cache.CacheStats afterStats = fieldPermissionsCache.getCacheStats(); @@ -608,12 +610,12 @@ public void testParseRoleWithRestrictionFailsWhenAllowRestrictionIsFalse() { }"""; final ElasticsearchParseException e = expectThrows( ElasticsearchParseException.class, - () -> RoleDescriptor.parse( - "test_role_with_restriction", - XContentHelper.createParser(XContentParserConfiguration.EMPTY, new BytesArray(json), XContentType.JSON), - randomBoolean(), - false - ) + () -> RoleDescriptor.parser() + .allowRestriction(false) + .parse( + "test_role_with_restriction", + XContentHelper.createParser(XContentParserConfiguration.EMPTY, new BytesArray(json), XContentType.JSON) + ) ); assertThat( e, @@ -630,12 +632,12 @@ public void testParseRoleWithRestrictionWhenAllowRestrictionIsTrue() throws IOEx "workflows": ["search_application"] } }"""; - RoleDescriptor role = RoleDescriptor.parse( - "test_role_with_restriction", - XContentHelper.createParser(XContentParserConfiguration.EMPTY, new BytesArray(json), XContentType.JSON), - randomBoolean(), - true - ); + RoleDescriptor role = RoleDescriptor.parser() + .allowRestriction(true) + .parse( + "test_role_with_restriction", + XContentHelper.createParser(XContentParserConfiguration.EMPTY, new BytesArray(json), XContentType.JSON) + ); assertThat(role.getName(), equalTo("test_role_with_restriction")); assertThat(role.hasRestriction(), equalTo(true)); assertThat(role.hasWorkflowsRestriction(), equalTo(true)); @@ -655,7 +657,7 @@ public void testParseEmptyQuery() throws Exception { } ] }"""; - RoleDescriptor rd = RoleDescriptor.parse("test", new BytesArray(json), false, XContentType.JSON); + RoleDescriptor rd = RoleDescriptor.parser().parse("test", new BytesArray(json), XContentType.JSON); assertEquals("test", rd.getName()); assertArrayEquals(new String[] { "a", "b" }, rd.getClusterPrivileges()); assertEquals(1, rd.getIndicesPrivileges().length); @@ -677,7 +679,7 @@ public void testParseNullQuery() throws Exception { } ] }"""; - RoleDescriptor rd = RoleDescriptor.parse("test", new BytesArray(json), false, XContentType.JSON); + RoleDescriptor rd = RoleDescriptor.parser().parse("test", new BytesArray(json), XContentType.JSON); assertEquals("test", rd.getName()); assertArrayEquals(new String[] { "a", "b" }, rd.getClusterPrivileges()); assertEquals(1, rd.getIndicesPrivileges().length); @@ -699,7 +701,7 @@ public void testParseEmptyQueryUsingDeprecatedIndicesField() throws Exception { } ] }"""; - RoleDescriptor rd = RoleDescriptor.parse("test", new BytesArray(json), false, XContentType.JSON); + RoleDescriptor rd = RoleDescriptor.parser().parse("test", new BytesArray(json), XContentType.JSON); assertEquals("test", rd.getName()); assertArrayEquals(new String[] { "a", "b" }, rd.getClusterPrivileges()); assertEquals(1, rd.getIndicesPrivileges().length); @@ -721,7 +723,7 @@ public void testParseIgnoresTransientMetadata() throws Exception { ); XContentBuilder b = jsonBuilder(); descriptor.toXContent(b, ToXContent.EMPTY_PARAMS); - RoleDescriptor parsed = RoleDescriptor.parse("test", BytesReference.bytes(b), false, XContentType.JSON); + RoleDescriptor parsed = RoleDescriptor.parser().parse("test", BytesReference.bytes(b), XContentType.JSON); assertNotNull(parsed); assertEquals(1, parsed.getTransientMetadata().size()); assertEquals(true, parsed.getTransientMetadata().get("enabled")); @@ -745,7 +747,7 @@ public void testParseIndicesPrivilegesSucceedsWhenExceptFieldsIsSubsetOfGrantedF } ] }""", grant, except); - final RoleDescriptor rd = RoleDescriptor.parse("test", new BytesArray(json), false, XContentType.JSON); + final RoleDescriptor rd = RoleDescriptor.parser().parse("test", new BytesArray(json), XContentType.JSON); assertEquals("test", rd.getName()); assertEquals(1, rd.getIndicesPrivileges().length); assertArrayEquals(new String[] { "idx1", "idx2" }, rd.getIndicesPrivileges()[0].getIndices()); @@ -774,7 +776,7 @@ public void testParseIndicesPrivilegesFailsWhenExceptFieldsAreNotSubsetOfGranted }"""; final ElasticsearchParseException epe = expectThrows( ElasticsearchParseException.class, - () -> RoleDescriptor.parse("test", new BytesArray(json), false, XContentType.JSON) + () -> RoleDescriptor.parser().parse("test", new BytesArray(json), XContentType.JSON) ); assertThat(epe, TestMatchers.throwableWithMessage(containsString("must be a subset of the granted fields "))); assertThat(epe, TestMatchers.throwableWithMessage(containsString("f1"))); @@ -794,7 +796,7 @@ public void testParseRemoteIndicesPrivilegesFailsWhenClustersFieldMissing() { }"""; final ElasticsearchParseException epe = expectThrows( ElasticsearchParseException.class, - () -> RoleDescriptor.parse("test", new BytesArray(json), false, XContentType.JSON) + () -> RoleDescriptor.parser().parse("test", new BytesArray(json), XContentType.JSON) ); assertThat( epe, @@ -817,7 +819,7 @@ public void testParseIndicesPrivilegesFailsWhenClustersFieldPresent() { }"""; final ElasticsearchParseException epe = expectThrows( ElasticsearchParseException.class, - () -> RoleDescriptor.parse("test", new BytesArray(json), false, XContentType.JSON) + () -> RoleDescriptor.parser().parse("test", new BytesArray(json), XContentType.JSON) ); assertThat( epe, @@ -961,7 +963,7 @@ public void testGlobalPrivilegesOrdering() throws IOException { } } }""", profileNamesString, applicationNamesString); - RoleDescriptor role3 = RoleDescriptor.parse(roleName, new BytesArray(json), false, XContentType.JSON); + RoleDescriptor role3 = RoleDescriptor.parser().parse(roleName, new BytesArray(json), XContentType.JSON); assertThat(role3, is(role1)); json = Strings.format(""" { @@ -978,7 +980,7 @@ public void testGlobalPrivilegesOrdering() throws IOException { } } }""", applicationNamesString, profileNamesString); - RoleDescriptor role4 = RoleDescriptor.parse(roleName, new BytesArray(json), false, XContentType.JSON); + RoleDescriptor role4 = RoleDescriptor.parser().parse(roleName, new BytesArray(json), XContentType.JSON); assertThat(role4, is(role1)); } diff --git a/x-pack/plugin/security/qa/security-trial/src/javaRestTest/java/org/elasticsearch/xpack/security/role/RoleWithRemoteIndicesPrivilegesRestIT.java b/x-pack/plugin/security/qa/security-trial/src/javaRestTest/java/org/elasticsearch/xpack/security/role/RoleWithRemoteIndicesPrivilegesRestIT.java index 4e3a520678f70..65344a2d9d631 100644 --- a/x-pack/plugin/security/qa/security-trial/src/javaRestTest/java/org/elasticsearch/xpack/security/role/RoleWithRemoteIndicesPrivilegesRestIT.java +++ b/x-pack/plugin/security/qa/security-trial/src/javaRestTest/java/org/elasticsearch/xpack/security/role/RoleWithRemoteIndicesPrivilegesRestIT.java @@ -323,7 +323,7 @@ private void expectRoleDescriptorInResponse(final Response getRoleResponse, fina throws IOException { final Map actual = responseAsParser(getRoleResponse).map( HashMap::new, - p -> RoleDescriptor.parse(expectedRoleDescriptor.getName(), p, false) + p -> RoleDescriptor.parser().parse(expectedRoleDescriptor.getName(), p) ); assertThat(actual, equalTo(Map.of(expectedRoleDescriptor.getName(), expectedRoleDescriptor))); } diff --git a/x-pack/plugin/security/src/internalClusterTest/java/org/elasticsearch/xpack/security/authc/ApiKeyIntegTests.java b/x-pack/plugin/security/src/internalClusterTest/java/org/elasticsearch/xpack/security/authc/ApiKeyIntegTests.java index 0a8fbb1ecffc0..c4818388a5d4d 100644 --- a/x-pack/plugin/security/src/internalClusterTest/java/org/elasticsearch/xpack/security/authc/ApiKeyIntegTests.java +++ b/x-pack/plugin/security/src/internalClusterTest/java/org/elasticsearch/xpack/security/authc/ApiKeyIntegTests.java @@ -2874,12 +2874,13 @@ private void expectRoleDescriptorsForApiKey( for (RoleDescriptor expectedRoleDescriptor : expectedRoleDescriptors) { assertThat(rawRoleDescriptor, hasKey(expectedRoleDescriptor.getName())); final var descriptor = (Map) rawRoleDescriptor.get(expectedRoleDescriptor.getName()); - final var roleDescriptor = RoleDescriptor.parse( - expectedRoleDescriptor.getName(), - XContentTestUtils.convertToXContent(descriptor, XContentType.JSON), - false, - XContentType.JSON - ); + final var roleDescriptor = RoleDescriptor.parser() + .allowRestriction(true) + .parse( + expectedRoleDescriptor.getName(), + XContentTestUtils.convertToXContent(descriptor, XContentType.JSON), + XContentType.JSON + ); assertEquals(expectedRoleDescriptor, roleDescriptor); } } diff --git a/x-pack/plugin/security/src/internalClusterTest/java/org/elasticsearch/xpack/security/authc/apikey/ApiKeySingleNodeTests.java b/x-pack/plugin/security/src/internalClusterTest/java/org/elasticsearch/xpack/security/authc/apikey/ApiKeySingleNodeTests.java index fe9c1f37e7d49..2aaf77e147a5e 100644 --- a/x-pack/plugin/security/src/internalClusterTest/java/org/elasticsearch/xpack/security/authc/apikey/ApiKeySingleNodeTests.java +++ b/x-pack/plugin/security/src/internalClusterTest/java/org/elasticsearch/xpack/security/authc/apikey/ApiKeySingleNodeTests.java @@ -247,12 +247,8 @@ public void testServiceAccountApiKey() throws IOException { @SuppressWarnings("unchecked") final Map descriptor = (Map) fleetServerRoleDescriptor.get("elastic/fleet-server"); - final RoleDescriptor roleDescriptor = RoleDescriptor.parse( - "elastic/fleet-server", - XContentTestUtils.convertToXContent(descriptor, XContentType.JSON), - false, - XContentType.JSON - ); + final RoleDescriptor roleDescriptor = RoleDescriptor.parser() + .parse("elastic/fleet-server", XContentTestUtils.convertToXContent(descriptor, XContentType.JSON), XContentType.JSON); assertThat(roleDescriptor, equalTo(ServiceAccountService.getServiceAccounts().get("elastic/fleet-server").roleDescriptor())); } @@ -588,12 +584,12 @@ public void testCreateCrossClusterApiKey() throws IOException { final Map roleDescriptors = (Map) document.get("role_descriptors"); assertThat(roleDescriptors.keySet(), contains("cross_cluster")); @SuppressWarnings("unchecked") - final RoleDescriptor actualRoleDescriptor = RoleDescriptor.parse( - "cross_cluster", - XContentTestUtils.convertToXContent((Map) roleDescriptors.get("cross_cluster"), XContentType.JSON), - false, - XContentType.JSON - ); + final RoleDescriptor actualRoleDescriptor = RoleDescriptor.parser() + .parse( + "cross_cluster", + XContentTestUtils.convertToXContent((Map) roleDescriptors.get("cross_cluster"), XContentType.JSON), + XContentType.JSON + ); final RoleDescriptor expectedRoleDescriptor = new RoleDescriptor( "cross_cluster", diff --git a/x-pack/plugin/security/src/main/java/org/elasticsearch/xpack/security/authc/ApiKeyService.java b/x-pack/plugin/security/src/main/java/org/elasticsearch/xpack/security/authc/ApiKeyService.java index ec0e54e96f1af..84eb2ff82beb8 100644 --- a/x-pack/plugin/security/src/main/java/org/elasticsearch/xpack/security/authc/ApiKeyService.java +++ b/x-pack/plugin/security/src/main/java/org/elasticsearch/xpack/security/authc/ApiKeyService.java @@ -985,7 +985,7 @@ public List parseRoleDescriptors( XContentType.JSON ) ) { - return RoleDescriptor.parse(name, parser, false); + return RoleDescriptor.parser().allowRestriction(true).parse(name, parser); } } catch (IOException e) { throw new UncheckedIOException(e); @@ -1025,7 +1025,7 @@ private static List parseRoleDescriptorsBytes( while (parser.nextToken() != XContentParser.Token.END_OBJECT) { parser.nextToken(); // role name String roleName = parser.currentName(); - roleDescriptors.add(RoleDescriptor.parse(roleName, parser, false)); + roleDescriptors.add(RoleDescriptor.parser().allowRestriction(true).parse(roleName, parser)); } } catch (IOException e) { throw new UncheckedIOException(e); diff --git a/x-pack/plugin/security/src/main/java/org/elasticsearch/xpack/security/authz/store/FileRolesStore.java b/x-pack/plugin/security/src/main/java/org/elasticsearch/xpack/security/authz/store/FileRolesStore.java index d7c8f11c467f2..9a515efca6000 100644 --- a/x-pack/plugin/security/src/main/java/org/elasticsearch/xpack/security/authz/store/FileRolesStore.java +++ b/x-pack/plugin/security/src/main/java/org/elasticsearch/xpack/security/authz/store/FileRolesStore.java @@ -308,9 +308,8 @@ static RoleDescriptor parseRoleDescriptor( token = parser.nextToken(); if (token == XContentParser.Token.START_OBJECT) { - // we pass true as last parameter because we do not want to reject files if field permissions - // are given in 2.x syntax - RoleDescriptor descriptor = RoleDescriptor.parse(roleName, parser, true, false); + // we do not want to reject files if field permissions are given in 2.x syntax, hence why we allow2xFormat + RoleDescriptor descriptor = RoleDescriptor.parser().allow2xFormat(true).parse(roleName, parser); return checkDescriptor(descriptor, path, logger, settings, xContentRegistry); } else { logger.error("invalid role definition [{}] in roles file [{}]. skipping role...", roleName, path.toAbsolutePath()); diff --git a/x-pack/plugin/security/src/main/java/org/elasticsearch/xpack/security/authz/store/NativeRolesStore.java b/x-pack/plugin/security/src/main/java/org/elasticsearch/xpack/security/authz/store/NativeRolesStore.java index 31875655a7ee9..1f2b709f145bf 100644 --- a/x-pack/plugin/security/src/main/java/org/elasticsearch/xpack/security/authz/store/NativeRolesStore.java +++ b/x-pack/plugin/security/src/main/java/org/elasticsearch/xpack/security/authz/store/NativeRolesStore.java @@ -482,9 +482,8 @@ static RoleDescriptor transformRole(String id, BytesReference sourceBytes, Logge assert id.startsWith(ROLE_TYPE) : "[" + id + "] does not have role prefix"; final String name = id.substring(ROLE_TYPE.length() + 1); try { - // we pass true as allow2xFormat parameter because we do not want to reject permissions if the field permissions - // are given in 2.x syntax - RoleDescriptor roleDescriptor = RoleDescriptor.parse(name, sourceBytes, true, XContentType.JSON, false); + // we do not want to reject permissions if the field permissions are given in 2.x syntax, hence why we allow2xFormat + RoleDescriptor roleDescriptor = RoleDescriptor.parser().allow2xFormat(true).parse(name, sourceBytes, XContentType.JSON); final boolean dlsEnabled = Arrays.stream(roleDescriptor.getIndicesPrivileges()) .anyMatch(IndicesPrivileges::isUsingDocumentLevelSecurity); final boolean flsEnabled = Arrays.stream(roleDescriptor.getIndicesPrivileges()) diff --git a/x-pack/plugin/security/src/test/java/org/elasticsearch/test/TestSecurityClient.java b/x-pack/plugin/security/src/test/java/org/elasticsearch/test/TestSecurityClient.java index 4888c0f4c9721..cc6af4437dbee 100644 --- a/x-pack/plugin/security/src/test/java/org/elasticsearch/test/TestSecurityClient.java +++ b/x-pack/plugin/security/src/test/java/org/elasticsearch/test/TestSecurityClient.java @@ -212,7 +212,7 @@ private Map getRoleDescriptors(String roleParameter) thr XContentParserUtils.ensureExpectedToken(XContentParser.Token.FIELD_NAME, parser.currentToken(), parser); final String roleName = parser.currentName(); XContentParserUtils.ensureExpectedToken(XContentParser.Token.START_OBJECT, parser.nextToken(), parser); - final RoleDescriptor role = RoleDescriptor.parse(roleName, parser, false); + final RoleDescriptor role = RoleDescriptor.parser().parse(roleName, parser); roles.put(roleName, role); } } diff --git a/x-pack/plugin/security/src/test/java/org/elasticsearch/xpack/security/authc/ApiKeyServiceTests.java b/x-pack/plugin/security/src/test/java/org/elasticsearch/xpack/security/authc/ApiKeyServiceTests.java index daa2b9cf149de..46d5c649e48bb 100644 --- a/x-pack/plugin/security/src/test/java/org/elasticsearch/xpack/security/authc/ApiKeyServiceTests.java +++ b/x-pack/plugin/security/src/test/java/org/elasticsearch/xpack/security/authc/ApiKeyServiceTests.java @@ -1769,7 +1769,7 @@ public void testApiKeyDocCache() throws IOException, ExecutionException, Interru final String apiKey3 = randomAlphaOfLength(16); ApiKeyCredentials apiKeyCredentials3 = getApiKeyCredentials(docId3, apiKey3, type); final List keyRoles = List.of( - RoleDescriptor.parse("key-role", new BytesArray("{\"cluster\":[\"monitor\"]}"), true, XContentType.JSON) + RoleDescriptor.parser().allow2xFormat(true).parse("key-role", new BytesArray("{\"cluster\":[\"monitor\"]}"), XContentType.JSON) ); final Map metadata3 = mockKeyDocument( docId3, diff --git a/x-pack/plugin/security/src/test/java/org/elasticsearch/xpack/security/authz/permission/FieldPermissionsTests.java b/x-pack/plugin/security/src/test/java/org/elasticsearch/xpack/security/authz/permission/FieldPermissionsTests.java index b97d71466f181..275bb864e794b 100644 --- a/x-pack/plugin/security/src/test/java/org/elasticsearch/xpack/security/authz/permission/FieldPermissionsTests.java +++ b/x-pack/plugin/security/src/test/java/org/elasticsearch/xpack/security/authz/permission/FieldPermissionsTests.java @@ -37,7 +37,7 @@ public void testParseFieldPermissions() throws Exception { } ] }"""; - RoleDescriptor rd = RoleDescriptor.parse("test", new BytesArray(q), false, XContentType.JSON); + RoleDescriptor rd = RoleDescriptor.parser().parse("test", new BytesArray(q), XContentType.JSON); assertArrayEquals(rd.getIndicesPrivileges()[0].getGrantedFields(), new String[] { "f1", "f2", "f3", "f4" }); assertArrayEquals(rd.getIndicesPrivileges()[0].getDeniedFields(), new String[] { "f3", "f4" }); @@ -54,7 +54,7 @@ public void testParseFieldPermissions() throws Exception { } ] }"""; - rd = RoleDescriptor.parse("test", new BytesArray(q), false, XContentType.JSON); + rd = RoleDescriptor.parser().parse("test", new BytesArray(q), XContentType.JSON); assertArrayEquals(rd.getIndicesPrivileges()[0].getGrantedFields(), new String[] { "f1", "f2", "f3", "f4" }); assertArrayEquals(rd.getIndicesPrivileges()[0].getDeniedFields(), new String[] { "f3", "f4" }); @@ -70,7 +70,7 @@ public void testParseFieldPermissions() throws Exception { } ] }"""; - rd = RoleDescriptor.parse("test", new BytesArray(q), false, XContentType.JSON); + rd = RoleDescriptor.parser().parse("test", new BytesArray(q), XContentType.JSON); assertArrayEquals(rd.getIndicesPrivileges()[0].getGrantedFields(), new String[] { "f1", "f2" }); assertNull(rd.getIndicesPrivileges()[0].getDeniedFields()); @@ -86,7 +86,7 @@ public void testParseFieldPermissions() throws Exception { } ] }"""; - rd = RoleDescriptor.parse("test", new BytesArray(q), false, XContentType.JSON); + rd = RoleDescriptor.parser().parse("test", new BytesArray(q), XContentType.JSON); assertArrayEquals(rd.getIndicesPrivileges()[0].getGrantedFields(), new String[] {}); assertNull(rd.getIndicesPrivileges()[0].getDeniedFields()); @@ -103,7 +103,7 @@ public void testParseFieldPermissions() throws Exception { } ] }"""; - rd = RoleDescriptor.parse("test", new BytesArray(q), false, XContentType.JSON); + rd = RoleDescriptor.parser().parse("test", new BytesArray(q), XContentType.JSON); assertArrayEquals(rd.getIndicesPrivileges()[0].getGrantedFields(), new String[] {}); assertArrayEquals(rd.getIndicesPrivileges()[0].getDeniedFields(), new String[] {}); @@ -121,7 +121,7 @@ public void testParseFieldPermissions() throws Exception { }"""; ElasticsearchParseException e = expectThrows( ElasticsearchParseException.class, - () -> RoleDescriptor.parse("test", new BytesArray(exceptWithoutGrant), false, XContentType.JSON) + () -> RoleDescriptor.parser().parse("test", new BytesArray(exceptWithoutGrant), XContentType.JSON) ); assertThat( e.getDetailedMessage(), @@ -132,7 +132,7 @@ public void testParseFieldPermissions() throws Exception { {"indices": [ {"names": "idx2", "privileges": ["p3"], "field_security": {"grant": null}}]}"""; e = expectThrows( ElasticsearchParseException.class, - () -> RoleDescriptor.parse("test", new BytesArray(grantNull), false, XContentType.JSON) + () -> RoleDescriptor.parser().parse("test", new BytesArray(grantNull), XContentType.JSON) ); assertThat( e.getDetailedMessage(), @@ -143,7 +143,7 @@ public void testParseFieldPermissions() throws Exception { {"indices": [ {"names": "idx2", "privileges": ["p3"], "field_security": {"grant": ["*"],"except": null}}]}"""; e = expectThrows( ElasticsearchParseException.class, - () -> RoleDescriptor.parse("test", new BytesArray(exceptNull), false, XContentType.JSON) + () -> RoleDescriptor.parser().parse("test", new BytesArray(exceptNull), XContentType.JSON) ); assertThat( e.getDetailedMessage(), @@ -154,7 +154,7 @@ public void testParseFieldPermissions() throws Exception { {"indices": [ {"names": "idx2", "privileges": ["p3"], "field_security": {"grant": null,"except": null}}]}"""; e = expectThrows( ElasticsearchParseException.class, - () -> RoleDescriptor.parse("test", new BytesArray(exceptGrantNull), false, XContentType.JSON) + () -> RoleDescriptor.parser().parse("test", new BytesArray(exceptGrantNull), XContentType.JSON) ); assertThat( e.getDetailedMessage(), @@ -165,7 +165,7 @@ public void testParseFieldPermissions() throws Exception { {"indices": [ {"names": "idx2", "privileges": ["p3"], "field_security": {}}]}"""; e = expectThrows( ElasticsearchParseException.class, - () -> RoleDescriptor.parse("test", new BytesArray(bothFieldsMissing), false, XContentType.JSON) + () -> RoleDescriptor.parser().parse("test", new BytesArray(bothFieldsMissing), XContentType.JSON) ); assertThat( e.getDetailedMessage(), @@ -193,7 +193,7 @@ public void testParseFieldPermissions() throws Exception { } ] }"""; - rd = RoleDescriptor.parse("test", new BytesArray(q), false, XContentType.JSON); + rd = RoleDescriptor.parser().parse("test", new BytesArray(q), XContentType.JSON); assertArrayEquals(rd.getIndicesPrivileges()[0].getGrantedFields(), new String[] {}); assertNull(rd.getIndicesPrivileges()[0].getDeniedFields()); assertArrayEquals(rd.getIndicesPrivileges()[1].getGrantedFields(), new String[] { "*" }); @@ -204,14 +204,14 @@ public void testParseFieldPermissions() throws Exception { public void testBWCFieldPermissions() throws Exception { String q = """ {"indices": [ {"names": "idx2", "privileges": ["p3"], "fields": ["f1", "f2"]}]}"""; - RoleDescriptor rd = RoleDescriptor.parse("test", new BytesArray(q), true, XContentType.JSON); + RoleDescriptor rd = RoleDescriptor.parser().allow2xFormat(true).parse("test", new BytesArray(q), XContentType.JSON); assertArrayEquals(rd.getIndicesPrivileges()[0].getGrantedFields(), new String[] { "f1", "f2" }); assertNull(rd.getIndicesPrivileges()[0].getDeniedFields()); final String failingQuery = q; ElasticsearchParseException e = expectThrows( ElasticsearchParseException.class, - () -> RoleDescriptor.parse("test", new BytesArray(failingQuery), false, XContentType.JSON) + () -> RoleDescriptor.parser().allow2xFormat(false).parse("test", new BytesArray(failingQuery), XContentType.JSON) ); assertThat(e.getDetailedMessage(), containsString(""" ["fields": [...]] format has changed for field permissions in role [test], \ @@ -219,13 +219,13 @@ public void testBWCFieldPermissions() throws Exception { q = """ {"indices": [ {"names": "idx2", "privileges": ["p3"], "fields": []}]}"""; - rd = RoleDescriptor.parse("test", new BytesArray(q), true, XContentType.JSON); + rd = RoleDescriptor.parser().allow2xFormat(true).parse("test", new BytesArray(q), XContentType.JSON); assertArrayEquals(rd.getIndicesPrivileges()[0].getGrantedFields(), new String[] {}); assertNull(rd.getIndicesPrivileges()[0].getDeniedFields()); final String failingQuery2 = q; e = expectThrows( ElasticsearchParseException.class, - () -> RoleDescriptor.parse("test", new BytesArray(failingQuery2), false, XContentType.JSON) + () -> RoleDescriptor.parser().allow2xFormat(false).parse("test", new BytesArray(failingQuery2), XContentType.JSON) ); assertThat(e.getDetailedMessage(), containsString(""" ["fields": [...]] format has changed for field permissions in role [test], \ @@ -233,13 +233,13 @@ public void testBWCFieldPermissions() throws Exception { q = """ {"indices": [ {"names": "idx2", "privileges": ["p3"], "fields": null}]}"""; - rd = RoleDescriptor.parse("test", new BytesArray(q), true, XContentType.JSON); + rd = RoleDescriptor.parser().allow2xFormat(true).parse("test", new BytesArray(q), XContentType.JSON); assertNull(rd.getIndicesPrivileges()[0].getGrantedFields()); assertNull(rd.getIndicesPrivileges()[0].getDeniedFields()); final String failingQuery3 = q; e = expectThrows( ElasticsearchParseException.class, - () -> RoleDescriptor.parse("test", new BytesArray(failingQuery3), false, XContentType.JSON) + () -> RoleDescriptor.parser().allow2xFormat(false).parse("test", new BytesArray(failingQuery3), XContentType.JSON) ); assertThat(e.getDetailedMessage(), containsString(""" ["fields": [...]] format has changed for field permissions in role [test], \ From 519875cff18c37d969b5bd44daa9e41778a1b932 Mon Sep 17 00:00:00 2001 From: Slobodan Adamovic Date: Tue, 16 Apr 2024 13:06:14 +0200 Subject: [PATCH 2/3] Make parser instances immutable and constant to avoid instantiating every time --- .../core/security/action/apikey/ApiKey.java | 3 +- .../BulkUpdateApiKeyRequestTranslator.java | 3 +- .../apikey/CreateApiKeyRequestBuilder.java | 5 +- .../apikey/UpdateApiKeyRequestTranslator.java | 5 +- .../action/role/PutRoleRequestBuilder.java | 4 +- .../authc/CrossClusterAccessSubjectInfo.java | 5 +- .../core/security/authz/RoleDescriptor.java | 33 +++++++----- .../authz/RoleDescriptorsIntersection.java | 4 +- .../GetServiceAccountResponseTests.java | 1 + .../security/authz/RoleDescriptorTests.java | 51 ++++++++++--------- ...RoleWithRemoteIndicesPrivilegesRestIT.java | 2 +- .../security/authc/ApiKeyIntegTests.java | 1 + .../authc/apikey/ApiKeySingleNodeTests.java | 2 + .../xpack/security/authc/ApiKeyService.java | 6 ++- .../security/authz/store/FileRolesStore.java | 3 +- .../authz/store/NativeRolesStore.java | 4 +- .../action/apikey/RestGrantApiKeyAction.java | 3 +- .../test/TestSecurityClient.java | 2 +- .../security/authc/ApiKeyServiceTests.java | 5 +- .../permission/FieldPermissionsTests.java | 41 +++++++-------- 20 files changed, 104 insertions(+), 79 deletions(-) diff --git a/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/security/action/apikey/ApiKey.java b/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/security/action/apikey/ApiKey.java index f358df6c39cfe..89d74db5b57c2 100644 --- a/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/security/action/apikey/ApiKey.java +++ b/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/security/action/apikey/ApiKey.java @@ -395,6 +395,7 @@ public String toString() { + "]"; } + private static final RoleDescriptor.Parser ROLE_DESCRIPTOR_PARSER = RoleDescriptor.parser().allowRestriction(true).build(); static final ConstructingObjectParser PARSER; static { PARSER = new ConstructingObjectParser<>("api_key", true, ApiKey::new); @@ -419,7 +420,7 @@ static int initializeParser(AbstractObjectParser parser) { parser.declareObject(optionalConstructorArg(), (p, c) -> p.map(), new ParseField("metadata")); parser.declareNamedObjects(optionalConstructorArg(), (p, c, n) -> { p.nextToken(); - return RoleDescriptor.parser().allowRestriction(true).parse(n, p); + return ROLE_DESCRIPTOR_PARSER.parse(n, p); }, new ParseField("role_descriptors")); parser.declareField( optionalConstructorArg(), diff --git a/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/security/action/apikey/BulkUpdateApiKeyRequestTranslator.java b/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/security/action/apikey/BulkUpdateApiKeyRequestTranslator.java index 52039a6f11c93..a1d6bd9329139 100644 --- a/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/security/action/apikey/BulkUpdateApiKeyRequestTranslator.java +++ b/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/security/action/apikey/BulkUpdateApiKeyRequestTranslator.java @@ -26,8 +26,9 @@ public interface BulkUpdateApiKeyRequestTranslator { BulkUpdateApiKeyRequest translate(RestRequest request) throws IOException; class Default implements BulkUpdateApiKeyRequestTranslator { + private static final RoleDescriptor.Parser ROLE_DESCRIPTOR_PARSER = RoleDescriptor.parser().allowRestriction(true).build(); private static final ConstructingObjectParser PARSER = createParser( - (n, p) -> RoleDescriptor.parser().allowRestriction(true).parse(n, p) + (n, p) -> ROLE_DESCRIPTOR_PARSER.parse(n, p) ); @SuppressWarnings("unchecked") diff --git a/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/security/action/apikey/CreateApiKeyRequestBuilder.java b/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/security/action/apikey/CreateApiKeyRequestBuilder.java index d7af3eb948648..02d0f978dd12f 100644 --- a/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/security/action/apikey/CreateApiKeyRequestBuilder.java +++ b/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/security/action/apikey/CreateApiKeyRequestBuilder.java @@ -31,9 +31,8 @@ * Request builder for populating a {@link CreateApiKeyRequest} */ public class CreateApiKeyRequestBuilder extends ActionRequestBuilder { - private static final ConstructingObjectParser PARSER = createParser( - (n, p) -> RoleDescriptor.parser().allowRestriction(true).parse(n, p) - ); + private static final RoleDescriptor.Parser ROLE_DESCRIPTOR_PARSER = RoleDescriptor.parser().allowRestriction(true).build(); + private static final ConstructingObjectParser PARSER = createParser(ROLE_DESCRIPTOR_PARSER::parse); @SuppressWarnings("unchecked") public static ConstructingObjectParser createParser( diff --git a/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/security/action/apikey/UpdateApiKeyRequestTranslator.java b/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/security/action/apikey/UpdateApiKeyRequestTranslator.java index e39c8449ddbf2..26f060560255c 100644 --- a/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/security/action/apikey/UpdateApiKeyRequestTranslator.java +++ b/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/security/action/apikey/UpdateApiKeyRequestTranslator.java @@ -25,9 +25,8 @@ public interface UpdateApiKeyRequestTranslator { UpdateApiKeyRequest translate(RestRequest request) throws IOException; class Default implements UpdateApiKeyRequestTranslator { - private static final ConstructingObjectParser PARSER = createParser( - (n, p) -> RoleDescriptor.parser().allowRestriction(true).parse(n, p) - ); + private static final RoleDescriptor.Parser ROLE_DESCRIPTOR_PARSER = RoleDescriptor.parser().allowRestriction(true).build(); + private static final ConstructingObjectParser PARSER = createParser(ROLE_DESCRIPTOR_PARSER::parse); @SuppressWarnings("unchecked") protected static ConstructingObjectParser createParser( diff --git a/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/security/action/role/PutRoleRequestBuilder.java b/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/security/action/role/PutRoleRequestBuilder.java index 3d6f30803c6c1..ae919c9403af5 100644 --- a/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/security/action/role/PutRoleRequestBuilder.java +++ b/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/security/action/role/PutRoleRequestBuilder.java @@ -21,6 +21,8 @@ */ public class PutRoleRequestBuilder extends ActionRequestBuilder { + private static final RoleDescriptor.Parser ROLE_DESCRIPTOR_PARSER = RoleDescriptor.parser().build(); + public PutRoleRequestBuilder(ElasticsearchClient client) { super(client, PutRoleAction.INSTANCE, new PutRoleRequest()); } @@ -30,7 +32,7 @@ public PutRoleRequestBuilder(ElasticsearchClient client) { */ public PutRoleRequestBuilder source(String name, BytesReference source, XContentType xContentType) throws IOException { // we want to reject the request if field permissions are given in 2.x syntax, hence we do not allow2xFormat - RoleDescriptor descriptor = RoleDescriptor.parser().parse(name, source, xContentType); + RoleDescriptor descriptor = ROLE_DESCRIPTOR_PARSER.parse(name, source, xContentType); assert name.equals(descriptor.getName()); request.name(name); request.cluster(descriptor.getClusterPrivileges()); diff --git a/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/security/authc/CrossClusterAccessSubjectInfo.java b/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/security/authc/CrossClusterAccessSubjectInfo.java index efb452667402d..0a0f9710edfc2 100644 --- a/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/security/authc/CrossClusterAccessSubjectInfo.java +++ b/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/security/authc/CrossClusterAccessSubjectInfo.java @@ -223,6 +223,9 @@ private void validate() { public static final class RoleDescriptorsBytes implements Writeable { public static final RoleDescriptorsBytes EMPTY = new RoleDescriptorsBytes(new BytesArray("{}")); + + private static final RoleDescriptor.Parser ROLE_DESCRIPTOR_PARSER = RoleDescriptor.parser().build(); + private final BytesReference rawBytes; public RoleDescriptorsBytes(BytesReference rawBytes) { @@ -263,7 +266,7 @@ public Set toRoleDescriptors() { while (parser.nextToken() != XContentParser.Token.END_OBJECT) { parser.nextToken(); final String roleName = parser.currentName(); - roleDescriptors.add(RoleDescriptor.parser().parse(roleName, parser)); + roleDescriptors.add(ROLE_DESCRIPTOR_PARSER.parse(roleName, parser)); } return Set.copyOf(roleDescriptors); } catch (IOException e) { diff --git a/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/security/authz/RoleDescriptor.java b/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/security/authz/RoleDescriptor.java index 1e41223d287b7..f4fbd37160280 100644 --- a/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/security/authz/RoleDescriptor.java +++ b/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/security/authz/RoleDescriptor.java @@ -420,25 +420,32 @@ public void writeTo(StreamOutput out) throws IOException { } } - public static Parser parser() { - return new Parser(); + public static Parser.Builder parser() { + return new Parser.Builder(); } - public static final class Parser { + public record Parser(boolean allow2xFormat, boolean allowRestriction) { - private boolean allow2xFormat = false; - private boolean allowRestriction = false; + public static final class Builder { + private boolean allow2xFormat = false; + private boolean allowRestriction = false; - private Parser() {} + private Builder() {} - public Parser allow2xFormat(boolean allow2xFormat) { - this.allow2xFormat = allow2xFormat; - return this; - } + public Builder allow2xFormat(boolean allow2xFormat) { + this.allow2xFormat = allow2xFormat; + return this; + } + + public Builder allowRestriction(boolean allowRestriction) { + this.allowRestriction = allowRestriction; + return this; + } + + public Parser build() { + return new Parser(allow2xFormat, allowRestriction); + } - public Parser allowRestriction(boolean allowRestriction) { - this.allowRestriction = allowRestriction; - return this; } public RoleDescriptor parse(String name, BytesReference source, XContentType xContentType) throws IOException { diff --git a/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/security/authz/RoleDescriptorsIntersection.java b/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/security/authz/RoleDescriptorsIntersection.java index d1683b22de6c1..183bd3583484e 100644 --- a/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/security/authz/RoleDescriptorsIntersection.java +++ b/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/security/authz/RoleDescriptorsIntersection.java @@ -26,6 +26,8 @@ public record RoleDescriptorsIntersection(Collection> roleDe public static RoleDescriptorsIntersection EMPTY = new RoleDescriptorsIntersection(Collections.emptyList()); + private static final RoleDescriptor.Parser ROLE_DESCRIPTOR_PARSER = RoleDescriptor.parser().allowRestriction(true).build(); + public RoleDescriptorsIntersection(RoleDescriptor roleDescriptor) { this(List.of(Set.of(roleDescriptor))); } @@ -70,7 +72,7 @@ public static RoleDescriptorsIntersection fromXContent(XContentParser xContentPa while ((token = p.nextToken()) != XContentParser.Token.END_OBJECT) { XContentParserUtils.ensureExpectedToken(XContentParser.Token.FIELD_NAME, token, p); XContentParserUtils.ensureExpectedToken(XContentParser.Token.START_OBJECT, p.nextToken(), p); - roleDescriptors.add(RoleDescriptor.parser().allowRestriction(true).parse(p.currentName(), p)); + roleDescriptors.add(ROLE_DESCRIPTOR_PARSER.parse(p.currentName(), p)); } return Set.copyOf(roleDescriptors); }); diff --git a/x-pack/plugin/core/src/test/java/org/elasticsearch/xpack/core/security/action/service/GetServiceAccountResponseTests.java b/x-pack/plugin/core/src/test/java/org/elasticsearch/xpack/core/security/action/service/GetServiceAccountResponseTests.java index ee9a4d5943f71..6294dcdc97eb5 100644 --- a/x-pack/plugin/core/src/test/java/org/elasticsearch/xpack/core/security/action/service/GetServiceAccountResponseTests.java +++ b/x-pack/plugin/core/src/test/java/org/elasticsearch/xpack/core/security/action/service/GetServiceAccountResponseTests.java @@ -98,6 +98,7 @@ private void assertRoleDescriptorEquals(Map responseFragment, Ro final Map descriptorMap = (Map) responseFragment.get("role_descriptor"); assertThat( RoleDescriptor.parser() + .build() .parse(roleDescriptor.getName(), XContentTestUtils.convertToXContent(descriptorMap, XContentType.JSON), XContentType.JSON), equalTo(roleDescriptor) ); diff --git a/x-pack/plugin/core/src/test/java/org/elasticsearch/xpack/core/security/authz/RoleDescriptorTests.java b/x-pack/plugin/core/src/test/java/org/elasticsearch/xpack/core/security/authz/RoleDescriptorTests.java index b77cff609ab8a..08c2680c35124 100644 --- a/x-pack/plugin/core/src/test/java/org/elasticsearch/xpack/core/security/authz/RoleDescriptorTests.java +++ b/x-pack/plugin/core/src/test/java/org/elasticsearch/xpack/core/security/authz/RoleDescriptorTests.java @@ -164,13 +164,14 @@ public void testToXContentRoundtrip() throws Exception { final BytesReference xContentValue = toShuffledXContent(descriptor, xContentType, ToXContent.EMPTY_PARAMS, false); final RoleDescriptor parsed = RoleDescriptor.parser() .allowRestriction(true) + .build() .parse(descriptor.getName(), xContentValue, xContentType); assertThat(parsed, equalTo(descriptor)); } public void testParse() throws Exception { String q = "{\"cluster\":[\"a\", \"b\"]}"; - RoleDescriptor rd = RoleDescriptor.parser().parse("test", new BytesArray(q), XContentType.JSON); + RoleDescriptor rd = RoleDescriptor.parser().build().parse("test", new BytesArray(q), XContentType.JSON); assertEquals("test", rd.getName()); assertArrayEquals(new String[] { "a", "b" }, rd.getClusterPrivileges()); assertEquals(0, rd.getIndicesPrivileges().length); @@ -181,7 +182,7 @@ public void testParse() throws Exception { "cluster": [ "a", "b" ], "run_as": [ "m", "n" ] }"""; - rd = RoleDescriptor.parser().parse("test", new BytesArray(q), XContentType.JSON); + rd = RoleDescriptor.parser().build().parse("test", new BytesArray(q), XContentType.JSON); assertEquals("test", rd.getName()); assertArrayEquals(new String[] { "a", "b" }, rd.getClusterPrivileges()); assertEquals(0, rd.getIndicesPrivileges().length); @@ -248,7 +249,7 @@ public void testParse() throws Exception { "workflows": ["search_application_query"] } }"""; - rd = RoleDescriptor.parser().allowRestriction(true).parse("test", new BytesArray(q), XContentType.JSON); + rd = RoleDescriptor.parser().allowRestriction(true).build().parse("test", new BytesArray(q), XContentType.JSON); assertEquals("test", rd.getName()); assertArrayEquals(new String[] { "a", "b" }, rd.getClusterPrivileges()); assertEquals(3, rd.getIndicesPrivileges().length); @@ -276,7 +277,7 @@ public void testParse() throws Exception { } } }"""; - rd = RoleDescriptor.parser().parse("test", new BytesArray(q), XContentType.JSON); + rd = RoleDescriptor.parser().build().parse("test", new BytesArray(q), XContentType.JSON); assertEquals("test", rd.getName()); assertArrayEquals(new String[] { "a", "b" }, rd.getClusterPrivileges()); assertEquals(1, rd.getIndicesPrivileges().length); @@ -287,7 +288,7 @@ public void testParse() throws Exception { q = """ {"cluster":["a", "b"], "metadata":{"foo":"bar"}}"""; - rd = RoleDescriptor.parser().parse("test", new BytesArray(q), XContentType.JSON); + rd = RoleDescriptor.parser().build().parse("test", new BytesArray(q), XContentType.JSON); assertEquals("test", rd.getName()); assertArrayEquals(new String[] { "a", "b" }, rd.getClusterPrivileges()); assertEquals(0, rd.getIndicesPrivileges().length); @@ -329,7 +330,7 @@ public void testParse() throws Exception { } } }"""; - rd = RoleDescriptor.parser().parse("test", new BytesArray(q), XContentType.JSON); + rd = RoleDescriptor.parser().build().parse("test", new BytesArray(q), XContentType.JSON); assertThat(rd.getName(), equalTo("test")); assertThat(rd.getClusterPrivileges(), arrayContaining("a", "b")); assertThat(rd.getIndicesPrivileges().length, equalTo(1)); @@ -370,7 +371,7 @@ public void testParse() throws Exception { } } }"""; - rd = RoleDescriptor.parser().parse("testUpdateProfile", new BytesArray(q), XContentType.JSON); + rd = RoleDescriptor.parser().build().parse("testUpdateProfile", new BytesArray(q), XContentType.JSON); assertThat(rd.getName(), is("testUpdateProfile")); assertThat(rd.getClusterPrivileges(), arrayContaining("manage")); assertThat(rd.getIndicesPrivileges(), Matchers.emptyArray()); @@ -395,7 +396,7 @@ public void testParse() throws Exception { q = """ {"applications": [{"application": "myapp", "resources": ["*"], "privileges": ["login" ]}] }"""; - rd = RoleDescriptor.parser().parse("test", new BytesArray(q), XContentType.JSON); + rd = RoleDescriptor.parser().build().parse("test", new BytesArray(q), XContentType.JSON); assertThat(rd.getName(), equalTo("test")); assertThat(rd.getClusterPrivileges(), emptyArray()); assertThat(rd.getIndicesPrivileges(), emptyArray()); @@ -409,11 +410,11 @@ public void testParse() throws Exception { {"applications":[{"not_supported": true, "resources": ["*"], "privileges": ["my-app:login" ]}] }"""; final IllegalArgumentException ex = expectThrows( IllegalArgumentException.class, - () -> RoleDescriptor.parser().parse("test", new BytesArray(badJson), XContentType.JSON) + () -> RoleDescriptor.parser().build().parse("test", new BytesArray(badJson), XContentType.JSON) ); assertThat(ex.getMessage(), containsString("not_supported")); - rd = RoleDescriptor.parser().allowRestriction(true).parse("test_empty_restriction", new BytesArray(""" + rd = RoleDescriptor.parser().allowRestriction(true).build().parse("test_empty_restriction", new BytesArray(""" { "index": [{"names": "idx1", "privileges": [ "p1", "p2" ]}], "restriction":{} @@ -424,7 +425,7 @@ public void testParse() throws Exception { final ElasticsearchParseException pex1 = expectThrows( ElasticsearchParseException.class, - () -> RoleDescriptor.parser().allowRestriction(true).parse("test_null_workflows", new BytesArray(""" + () -> RoleDescriptor.parser().allowRestriction(true).build().parse("test_null_workflows", new BytesArray(""" { "index": [{"names": ["idx1"], "privileges": [ "p1", "p2" ]}], "restriction":{"workflows":null} @@ -440,7 +441,7 @@ public void testParse() throws Exception { final ElasticsearchParseException pex2 = expectThrows( ElasticsearchParseException.class, - () -> RoleDescriptor.parser().allowRestriction(true).parse("test_empty_workflows", new BytesArray(""" + () -> RoleDescriptor.parser().allowRestriction(true).build().parse("test_empty_workflows", new BytesArray(""" { "index": [{"names": ["idx1"], "privileges": [ "p1", "p2" ]}], "restriction":{"workflows":[]} @@ -479,7 +480,7 @@ public void testParsingFieldPermissionsUsesCache() throws IOException { ] } """; - RoleDescriptor.parser().parse("test", new BytesArray(json), XContentType.JSON); + RoleDescriptor.parser().build().parse("test", new BytesArray(json), XContentType.JSON); final int numberOfFieldSecurityBlocks = 2; final Cache.CacheStats betweenStats = fieldPermissionsCache.getCacheStats(); @@ -488,7 +489,7 @@ public void testParsingFieldPermissionsUsesCache() throws IOException { final int iterations = randomIntBetween(1, 5); for (int i = 0; i < iterations; i++) { - RoleDescriptor.parser().parse("test", new BytesArray(json), XContentType.JSON); + RoleDescriptor.parser().build().parse("test", new BytesArray(json), XContentType.JSON); } final Cache.CacheStats afterStats = fieldPermissionsCache.getCacheStats(); @@ -612,6 +613,7 @@ public void testParseRoleWithRestrictionFailsWhenAllowRestrictionIsFalse() { ElasticsearchParseException.class, () -> RoleDescriptor.parser() .allowRestriction(false) + .build() .parse( "test_role_with_restriction", XContentHelper.createParser(XContentParserConfiguration.EMPTY, new BytesArray(json), XContentType.JSON) @@ -634,6 +636,7 @@ public void testParseRoleWithRestrictionWhenAllowRestrictionIsTrue() throws IOEx }"""; RoleDescriptor role = RoleDescriptor.parser() .allowRestriction(true) + .build() .parse( "test_role_with_restriction", XContentHelper.createParser(XContentParserConfiguration.EMPTY, new BytesArray(json), XContentType.JSON) @@ -657,7 +660,7 @@ public void testParseEmptyQuery() throws Exception { } ] }"""; - RoleDescriptor rd = RoleDescriptor.parser().parse("test", new BytesArray(json), XContentType.JSON); + RoleDescriptor rd = RoleDescriptor.parser().build().parse("test", new BytesArray(json), XContentType.JSON); assertEquals("test", rd.getName()); assertArrayEquals(new String[] { "a", "b" }, rd.getClusterPrivileges()); assertEquals(1, rd.getIndicesPrivileges().length); @@ -679,7 +682,7 @@ public void testParseNullQuery() throws Exception { } ] }"""; - RoleDescriptor rd = RoleDescriptor.parser().parse("test", new BytesArray(json), XContentType.JSON); + RoleDescriptor rd = RoleDescriptor.parser().build().parse("test", new BytesArray(json), XContentType.JSON); assertEquals("test", rd.getName()); assertArrayEquals(new String[] { "a", "b" }, rd.getClusterPrivileges()); assertEquals(1, rd.getIndicesPrivileges().length); @@ -701,7 +704,7 @@ public void testParseEmptyQueryUsingDeprecatedIndicesField() throws Exception { } ] }"""; - RoleDescriptor rd = RoleDescriptor.parser().parse("test", new BytesArray(json), XContentType.JSON); + RoleDescriptor rd = RoleDescriptor.parser().build().parse("test", new BytesArray(json), XContentType.JSON); assertEquals("test", rd.getName()); assertArrayEquals(new String[] { "a", "b" }, rd.getClusterPrivileges()); assertEquals(1, rd.getIndicesPrivileges().length); @@ -723,7 +726,7 @@ public void testParseIgnoresTransientMetadata() throws Exception { ); XContentBuilder b = jsonBuilder(); descriptor.toXContent(b, ToXContent.EMPTY_PARAMS); - RoleDescriptor parsed = RoleDescriptor.parser().parse("test", BytesReference.bytes(b), XContentType.JSON); + RoleDescriptor parsed = RoleDescriptor.parser().build().parse("test", BytesReference.bytes(b), XContentType.JSON); assertNotNull(parsed); assertEquals(1, parsed.getTransientMetadata().size()); assertEquals(true, parsed.getTransientMetadata().get("enabled")); @@ -747,7 +750,7 @@ public void testParseIndicesPrivilegesSucceedsWhenExceptFieldsIsSubsetOfGrantedF } ] }""", grant, except); - final RoleDescriptor rd = RoleDescriptor.parser().parse("test", new BytesArray(json), XContentType.JSON); + final RoleDescriptor rd = RoleDescriptor.parser().build().parse("test", new BytesArray(json), XContentType.JSON); assertEquals("test", rd.getName()); assertEquals(1, rd.getIndicesPrivileges().length); assertArrayEquals(new String[] { "idx1", "idx2" }, rd.getIndicesPrivileges()[0].getIndices()); @@ -776,7 +779,7 @@ public void testParseIndicesPrivilegesFailsWhenExceptFieldsAreNotSubsetOfGranted }"""; final ElasticsearchParseException epe = expectThrows( ElasticsearchParseException.class, - () -> RoleDescriptor.parser().parse("test", new BytesArray(json), XContentType.JSON) + () -> RoleDescriptor.parser().build().parse("test", new BytesArray(json), XContentType.JSON) ); assertThat(epe, TestMatchers.throwableWithMessage(containsString("must be a subset of the granted fields "))); assertThat(epe, TestMatchers.throwableWithMessage(containsString("f1"))); @@ -796,7 +799,7 @@ public void testParseRemoteIndicesPrivilegesFailsWhenClustersFieldMissing() { }"""; final ElasticsearchParseException epe = expectThrows( ElasticsearchParseException.class, - () -> RoleDescriptor.parser().parse("test", new BytesArray(json), XContentType.JSON) + () -> RoleDescriptor.parser().build().parse("test", new BytesArray(json), XContentType.JSON) ); assertThat( epe, @@ -819,7 +822,7 @@ public void testParseIndicesPrivilegesFailsWhenClustersFieldPresent() { }"""; final ElasticsearchParseException epe = expectThrows( ElasticsearchParseException.class, - () -> RoleDescriptor.parser().parse("test", new BytesArray(json), XContentType.JSON) + () -> RoleDescriptor.parser().build().parse("test", new BytesArray(json), XContentType.JSON) ); assertThat( epe, @@ -963,7 +966,7 @@ public void testGlobalPrivilegesOrdering() throws IOException { } } }""", profileNamesString, applicationNamesString); - RoleDescriptor role3 = RoleDescriptor.parser().parse(roleName, new BytesArray(json), XContentType.JSON); + RoleDescriptor role3 = RoleDescriptor.parser().build().parse(roleName, new BytesArray(json), XContentType.JSON); assertThat(role3, is(role1)); json = Strings.format(""" { @@ -980,7 +983,7 @@ public void testGlobalPrivilegesOrdering() throws IOException { } } }""", applicationNamesString, profileNamesString); - RoleDescriptor role4 = RoleDescriptor.parser().parse(roleName, new BytesArray(json), XContentType.JSON); + RoleDescriptor role4 = RoleDescriptor.parser().build().parse(roleName, new BytesArray(json), XContentType.JSON); assertThat(role4, is(role1)); } diff --git a/x-pack/plugin/security/qa/security-trial/src/javaRestTest/java/org/elasticsearch/xpack/security/role/RoleWithRemoteIndicesPrivilegesRestIT.java b/x-pack/plugin/security/qa/security-trial/src/javaRestTest/java/org/elasticsearch/xpack/security/role/RoleWithRemoteIndicesPrivilegesRestIT.java index 65344a2d9d631..6534f60e59da8 100644 --- a/x-pack/plugin/security/qa/security-trial/src/javaRestTest/java/org/elasticsearch/xpack/security/role/RoleWithRemoteIndicesPrivilegesRestIT.java +++ b/x-pack/plugin/security/qa/security-trial/src/javaRestTest/java/org/elasticsearch/xpack/security/role/RoleWithRemoteIndicesPrivilegesRestIT.java @@ -323,7 +323,7 @@ private void expectRoleDescriptorInResponse(final Response getRoleResponse, fina throws IOException { final Map actual = responseAsParser(getRoleResponse).map( HashMap::new, - p -> RoleDescriptor.parser().parse(expectedRoleDescriptor.getName(), p) + p -> RoleDescriptor.parser().build().parse(expectedRoleDescriptor.getName(), p) ); assertThat(actual, equalTo(Map.of(expectedRoleDescriptor.getName(), expectedRoleDescriptor))); } diff --git a/x-pack/plugin/security/src/internalClusterTest/java/org/elasticsearch/xpack/security/authc/ApiKeyIntegTests.java b/x-pack/plugin/security/src/internalClusterTest/java/org/elasticsearch/xpack/security/authc/ApiKeyIntegTests.java index c4818388a5d4d..a7d2a7df2976c 100644 --- a/x-pack/plugin/security/src/internalClusterTest/java/org/elasticsearch/xpack/security/authc/ApiKeyIntegTests.java +++ b/x-pack/plugin/security/src/internalClusterTest/java/org/elasticsearch/xpack/security/authc/ApiKeyIntegTests.java @@ -2876,6 +2876,7 @@ private void expectRoleDescriptorsForApiKey( final var descriptor = (Map) rawRoleDescriptor.get(expectedRoleDescriptor.getName()); final var roleDescriptor = RoleDescriptor.parser() .allowRestriction(true) + .build() .parse( expectedRoleDescriptor.getName(), XContentTestUtils.convertToXContent(descriptor, XContentType.JSON), diff --git a/x-pack/plugin/security/src/internalClusterTest/java/org/elasticsearch/xpack/security/authc/apikey/ApiKeySingleNodeTests.java b/x-pack/plugin/security/src/internalClusterTest/java/org/elasticsearch/xpack/security/authc/apikey/ApiKeySingleNodeTests.java index 2aaf77e147a5e..bd35ae6148c6b 100644 --- a/x-pack/plugin/security/src/internalClusterTest/java/org/elasticsearch/xpack/security/authc/apikey/ApiKeySingleNodeTests.java +++ b/x-pack/plugin/security/src/internalClusterTest/java/org/elasticsearch/xpack/security/authc/apikey/ApiKeySingleNodeTests.java @@ -248,6 +248,7 @@ public void testServiceAccountApiKey() throws IOException { final Map descriptor = (Map) fleetServerRoleDescriptor.get("elastic/fleet-server"); final RoleDescriptor roleDescriptor = RoleDescriptor.parser() + .build() .parse("elastic/fleet-server", XContentTestUtils.convertToXContent(descriptor, XContentType.JSON), XContentType.JSON); assertThat(roleDescriptor, equalTo(ServiceAccountService.getServiceAccounts().get("elastic/fleet-server").roleDescriptor())); } @@ -585,6 +586,7 @@ public void testCreateCrossClusterApiKey() throws IOException { assertThat(roleDescriptors.keySet(), contains("cross_cluster")); @SuppressWarnings("unchecked") final RoleDescriptor actualRoleDescriptor = RoleDescriptor.parser() + .build() .parse( "cross_cluster", XContentTestUtils.convertToXContent((Map) roleDescriptors.get("cross_cluster"), XContentType.JSON), diff --git a/x-pack/plugin/security/src/main/java/org/elasticsearch/xpack/security/authc/ApiKeyService.java b/x-pack/plugin/security/src/main/java/org/elasticsearch/xpack/security/authc/ApiKeyService.java index cc93d47d7881e..47cb053e4b5aa 100644 --- a/x-pack/plugin/security/src/main/java/org/elasticsearch/xpack/security/authc/ApiKeyService.java +++ b/x-pack/plugin/security/src/main/java/org/elasticsearch/xpack/security/authc/ApiKeyService.java @@ -202,6 +202,8 @@ public class ApiKeyService { Property.NodeScope ); + private static final RoleDescriptor.Parser ROLE_DESCRIPTOR_PARSER = RoleDescriptor.parser().allowRestriction(true).build(); + private final Clock clock; private final Client client; private final SecurityIndexManager securityIndex; @@ -987,7 +989,7 @@ public List parseRoleDescriptors( XContentType.JSON ) ) { - return RoleDescriptor.parser().allowRestriction(true).parse(name, parser); + return ROLE_DESCRIPTOR_PARSER.parse(name, parser); } } catch (IOException e) { throw new UncheckedIOException(e); @@ -1027,7 +1029,7 @@ private static List parseRoleDescriptorsBytes( while (parser.nextToken() != XContentParser.Token.END_OBJECT) { parser.nextToken(); // role name String roleName = parser.currentName(); - roleDescriptors.add(RoleDescriptor.parser().allowRestriction(true).parse(roleName, parser)); + roleDescriptors.add(ROLE_DESCRIPTOR_PARSER.parse(roleName, parser)); } } catch (IOException e) { throw new UncheckedIOException(e); diff --git a/x-pack/plugin/security/src/main/java/org/elasticsearch/xpack/security/authz/store/FileRolesStore.java b/x-pack/plugin/security/src/main/java/org/elasticsearch/xpack/security/authz/store/FileRolesStore.java index 99de43ae8521b..e259875b533b3 100644 --- a/x-pack/plugin/security/src/main/java/org/elasticsearch/xpack/security/authz/store/FileRolesStore.java +++ b/x-pack/plugin/security/src/main/java/org/elasticsearch/xpack/security/authz/store/FileRolesStore.java @@ -67,6 +67,7 @@ public class FileRolesStore implements BiConsumer, ActionListener, ActionListener< private static final Logger logger = LogManager.getLogger(NativeRolesStore.class); + private static final RoleDescriptor.Parser ROLE_DESCRIPTOR_PARSER = RoleDescriptor.parser().allow2xFormat(true).build(); + private final Settings settings; private final Client client; private final XPackLicenseState licenseState; @@ -483,7 +485,7 @@ static RoleDescriptor transformRole(String id, BytesReference sourceBytes, Logge final String name = id.substring(ROLE_TYPE.length() + 1); try { // we do not want to reject permissions if the field permissions are given in 2.x syntax, hence why we allow2xFormat - RoleDescriptor roleDescriptor = RoleDescriptor.parser().allow2xFormat(true).parse(name, sourceBytes, XContentType.JSON); + RoleDescriptor roleDescriptor = ROLE_DESCRIPTOR_PARSER.parse(name, sourceBytes, XContentType.JSON); final boolean dlsEnabled = Arrays.stream(roleDescriptor.getIndicesPrivileges()) .anyMatch(IndicesPrivileges::isUsingDocumentLevelSecurity); final boolean flsEnabled = Arrays.stream(roleDescriptor.getIndicesPrivileges()) diff --git a/x-pack/plugin/security/src/main/java/org/elasticsearch/xpack/security/rest/action/apikey/RestGrantApiKeyAction.java b/x-pack/plugin/security/src/main/java/org/elasticsearch/xpack/security/rest/action/apikey/RestGrantApiKeyAction.java index 8fda0f0518c93..7e38b3c1968ce 100644 --- a/x-pack/plugin/security/src/main/java/org/elasticsearch/xpack/security/rest/action/apikey/RestGrantApiKeyAction.java +++ b/x-pack/plugin/security/src/main/java/org/elasticsearch/xpack/security/rest/action/apikey/RestGrantApiKeyAction.java @@ -50,7 +50,8 @@ public interface RequestTranslator { GrantApiKeyRequest translate(RestRequest request) throws IOException; class Default implements RequestTranslator { - private static final ObjectParser PARSER = createParser((n, p) -> RoleDescriptor.parse(n, p, false)); + private static final RoleDescriptor.Parser ROLE_DESCRIPTOR_PARSER = RoleDescriptor.parser().allowRestriction(true).build(); + private static final ObjectParser PARSER = createParser(ROLE_DESCRIPTOR_PARSER::parse); protected static ObjectParser createParser( CheckedBiFunction roleDescriptorParser diff --git a/x-pack/plugin/security/src/test/java/org/elasticsearch/test/TestSecurityClient.java b/x-pack/plugin/security/src/test/java/org/elasticsearch/test/TestSecurityClient.java index cc6af4437dbee..f540a4a128d33 100644 --- a/x-pack/plugin/security/src/test/java/org/elasticsearch/test/TestSecurityClient.java +++ b/x-pack/plugin/security/src/test/java/org/elasticsearch/test/TestSecurityClient.java @@ -212,7 +212,7 @@ private Map getRoleDescriptors(String roleParameter) thr XContentParserUtils.ensureExpectedToken(XContentParser.Token.FIELD_NAME, parser.currentToken(), parser); final String roleName = parser.currentName(); XContentParserUtils.ensureExpectedToken(XContentParser.Token.START_OBJECT, parser.nextToken(), parser); - final RoleDescriptor role = RoleDescriptor.parser().parse(roleName, parser); + final RoleDescriptor role = RoleDescriptor.parser().build().parse(roleName, parser); roles.put(roleName, role); } } diff --git a/x-pack/plugin/security/src/test/java/org/elasticsearch/xpack/security/authc/ApiKeyServiceTests.java b/x-pack/plugin/security/src/test/java/org/elasticsearch/xpack/security/authc/ApiKeyServiceTests.java index e42a0170fcbb9..ad72ff513aee6 100644 --- a/x-pack/plugin/security/src/test/java/org/elasticsearch/xpack/security/authc/ApiKeyServiceTests.java +++ b/x-pack/plugin/security/src/test/java/org/elasticsearch/xpack/security/authc/ApiKeyServiceTests.java @@ -1866,7 +1866,10 @@ public void testApiKeyDocCache() throws IOException, ExecutionException, Interru final String apiKey3 = randomAlphaOfLength(16); ApiKeyCredentials apiKeyCredentials3 = getApiKeyCredentials(docId3, apiKey3, type); final List keyRoles = List.of( - RoleDescriptor.parser().allow2xFormat(true).parse("key-role", new BytesArray("{\"cluster\":[\"monitor\"]}"), XContentType.JSON) + RoleDescriptor.parser() + .allow2xFormat(true) + .build() + .parse("key-role", new BytesArray("{\"cluster\":[\"monitor\"]}"), XContentType.JSON) ); final Map metadata3 = mockKeyDocument( docId3, diff --git a/x-pack/plugin/security/src/test/java/org/elasticsearch/xpack/security/authz/permission/FieldPermissionsTests.java b/x-pack/plugin/security/src/test/java/org/elasticsearch/xpack/security/authz/permission/FieldPermissionsTests.java index 275bb864e794b..b7c50336df0d8 100644 --- a/x-pack/plugin/security/src/test/java/org/elasticsearch/xpack/security/authz/permission/FieldPermissionsTests.java +++ b/x-pack/plugin/security/src/test/java/org/elasticsearch/xpack/security/authz/permission/FieldPermissionsTests.java @@ -37,7 +37,8 @@ public void testParseFieldPermissions() throws Exception { } ] }"""; - RoleDescriptor rd = RoleDescriptor.parser().parse("test", new BytesArray(q), XContentType.JSON); + RoleDescriptor.Parser roleParser = RoleDescriptor.parser().build(); + RoleDescriptor rd = roleParser.parse("test", new BytesArray(q), XContentType.JSON); assertArrayEquals(rd.getIndicesPrivileges()[0].getGrantedFields(), new String[] { "f1", "f2", "f3", "f4" }); assertArrayEquals(rd.getIndicesPrivileges()[0].getDeniedFields(), new String[] { "f3", "f4" }); @@ -54,7 +55,7 @@ public void testParseFieldPermissions() throws Exception { } ] }"""; - rd = RoleDescriptor.parser().parse("test", new BytesArray(q), XContentType.JSON); + rd = roleParser.parse("test", new BytesArray(q), XContentType.JSON); assertArrayEquals(rd.getIndicesPrivileges()[0].getGrantedFields(), new String[] { "f1", "f2", "f3", "f4" }); assertArrayEquals(rd.getIndicesPrivileges()[0].getDeniedFields(), new String[] { "f3", "f4" }); @@ -70,7 +71,7 @@ public void testParseFieldPermissions() throws Exception { } ] }"""; - rd = RoleDescriptor.parser().parse("test", new BytesArray(q), XContentType.JSON); + rd = roleParser.parse("test", new BytesArray(q), XContentType.JSON); assertArrayEquals(rd.getIndicesPrivileges()[0].getGrantedFields(), new String[] { "f1", "f2" }); assertNull(rd.getIndicesPrivileges()[0].getDeniedFields()); @@ -86,7 +87,7 @@ public void testParseFieldPermissions() throws Exception { } ] }"""; - rd = RoleDescriptor.parser().parse("test", new BytesArray(q), XContentType.JSON); + rd = roleParser.parse("test", new BytesArray(q), XContentType.JSON); assertArrayEquals(rd.getIndicesPrivileges()[0].getGrantedFields(), new String[] {}); assertNull(rd.getIndicesPrivileges()[0].getDeniedFields()); @@ -103,7 +104,7 @@ public void testParseFieldPermissions() throws Exception { } ] }"""; - rd = RoleDescriptor.parser().parse("test", new BytesArray(q), XContentType.JSON); + rd = roleParser.parse("test", new BytesArray(q), XContentType.JSON); assertArrayEquals(rd.getIndicesPrivileges()[0].getGrantedFields(), new String[] {}); assertArrayEquals(rd.getIndicesPrivileges()[0].getDeniedFields(), new String[] {}); @@ -121,7 +122,7 @@ public void testParseFieldPermissions() throws Exception { }"""; ElasticsearchParseException e = expectThrows( ElasticsearchParseException.class, - () -> RoleDescriptor.parser().parse("test", new BytesArray(exceptWithoutGrant), XContentType.JSON) + () -> roleParser.parse("test", new BytesArray(exceptWithoutGrant), XContentType.JSON) ); assertThat( e.getDetailedMessage(), @@ -130,10 +131,7 @@ public void testParseFieldPermissions() throws Exception { final String grantNull = """ {"indices": [ {"names": "idx2", "privileges": ["p3"], "field_security": {"grant": null}}]}"""; - e = expectThrows( - ElasticsearchParseException.class, - () -> RoleDescriptor.parser().parse("test", new BytesArray(grantNull), XContentType.JSON) - ); + e = expectThrows(ElasticsearchParseException.class, () -> roleParser.parse("test", new BytesArray(grantNull), XContentType.JSON)); assertThat( e.getDetailedMessage(), containsString("failed to parse indices privileges for" + " role [test]. grant must not be null.") @@ -141,10 +139,7 @@ public void testParseFieldPermissions() throws Exception { final String exceptNull = """ {"indices": [ {"names": "idx2", "privileges": ["p3"], "field_security": {"grant": ["*"],"except": null}}]}"""; - e = expectThrows( - ElasticsearchParseException.class, - () -> RoleDescriptor.parser().parse("test", new BytesArray(exceptNull), XContentType.JSON) - ); + e = expectThrows(ElasticsearchParseException.class, () -> roleParser.parse("test", new BytesArray(exceptNull), XContentType.JSON)); assertThat( e.getDetailedMessage(), containsString("failed to parse indices privileges for role [test]. except must" + " not be null.") @@ -154,7 +149,7 @@ public void testParseFieldPermissions() throws Exception { {"indices": [ {"names": "idx2", "privileges": ["p3"], "field_security": {"grant": null,"except": null}}]}"""; e = expectThrows( ElasticsearchParseException.class, - () -> RoleDescriptor.parser().parse("test", new BytesArray(exceptGrantNull), XContentType.JSON) + () -> roleParser.parse("test", new BytesArray(exceptGrantNull), XContentType.JSON) ); assertThat( e.getDetailedMessage(), @@ -165,7 +160,7 @@ public void testParseFieldPermissions() throws Exception { {"indices": [ {"names": "idx2", "privileges": ["p3"], "field_security": {}}]}"""; e = expectThrows( ElasticsearchParseException.class, - () -> RoleDescriptor.parser().parse("test", new BytesArray(bothFieldsMissing), XContentType.JSON) + () -> roleParser.parse("test", new BytesArray(bothFieldsMissing), XContentType.JSON) ); assertThat( e.getDetailedMessage(), @@ -193,7 +188,7 @@ public void testParseFieldPermissions() throws Exception { } ] }"""; - rd = RoleDescriptor.parser().parse("test", new BytesArray(q), XContentType.JSON); + rd = roleParser.parse("test", new BytesArray(q), XContentType.JSON); assertArrayEquals(rd.getIndicesPrivileges()[0].getGrantedFields(), new String[] {}); assertNull(rd.getIndicesPrivileges()[0].getDeniedFields()); assertArrayEquals(rd.getIndicesPrivileges()[1].getGrantedFields(), new String[] { "*" }); @@ -204,14 +199,14 @@ public void testParseFieldPermissions() throws Exception { public void testBWCFieldPermissions() throws Exception { String q = """ {"indices": [ {"names": "idx2", "privileges": ["p3"], "fields": ["f1", "f2"]}]}"""; - RoleDescriptor rd = RoleDescriptor.parser().allow2xFormat(true).parse("test", new BytesArray(q), XContentType.JSON); + RoleDescriptor rd = RoleDescriptor.parser().allow2xFormat(true).build().parse("test", new BytesArray(q), XContentType.JSON); assertArrayEquals(rd.getIndicesPrivileges()[0].getGrantedFields(), new String[] { "f1", "f2" }); assertNull(rd.getIndicesPrivileges()[0].getDeniedFields()); final String failingQuery = q; ElasticsearchParseException e = expectThrows( ElasticsearchParseException.class, - () -> RoleDescriptor.parser().allow2xFormat(false).parse("test", new BytesArray(failingQuery), XContentType.JSON) + () -> RoleDescriptor.parser().allow2xFormat(false).build().parse("test", new BytesArray(failingQuery), XContentType.JSON) ); assertThat(e.getDetailedMessage(), containsString(""" ["fields": [...]] format has changed for field permissions in role [test], \ @@ -219,13 +214,13 @@ public void testBWCFieldPermissions() throws Exception { q = """ {"indices": [ {"names": "idx2", "privileges": ["p3"], "fields": []}]}"""; - rd = RoleDescriptor.parser().allow2xFormat(true).parse("test", new BytesArray(q), XContentType.JSON); + rd = RoleDescriptor.parser().allow2xFormat(true).build().parse("test", new BytesArray(q), XContentType.JSON); assertArrayEquals(rd.getIndicesPrivileges()[0].getGrantedFields(), new String[] {}); assertNull(rd.getIndicesPrivileges()[0].getDeniedFields()); final String failingQuery2 = q; e = expectThrows( ElasticsearchParseException.class, - () -> RoleDescriptor.parser().allow2xFormat(false).parse("test", new BytesArray(failingQuery2), XContentType.JSON) + () -> RoleDescriptor.parser().allow2xFormat(false).build().parse("test", new BytesArray(failingQuery2), XContentType.JSON) ); assertThat(e.getDetailedMessage(), containsString(""" ["fields": [...]] format has changed for field permissions in role [test], \ @@ -233,13 +228,13 @@ public void testBWCFieldPermissions() throws Exception { q = """ {"indices": [ {"names": "idx2", "privileges": ["p3"], "fields": null}]}"""; - rd = RoleDescriptor.parser().allow2xFormat(true).parse("test", new BytesArray(q), XContentType.JSON); + rd = RoleDescriptor.parser().allow2xFormat(true).build().parse("test", new BytesArray(q), XContentType.JSON); assertNull(rd.getIndicesPrivileges()[0].getGrantedFields()); assertNull(rd.getIndicesPrivileges()[0].getDeniedFields()); final String failingQuery3 = q; e = expectThrows( ElasticsearchParseException.class, - () -> RoleDescriptor.parser().allow2xFormat(false).parse("test", new BytesArray(failingQuery3), XContentType.JSON) + () -> RoleDescriptor.parser().allow2xFormat(false).build().parse("test", new BytesArray(failingQuery3), XContentType.JSON) ); assertThat(e.getDetailedMessage(), containsString(""" ["fields": [...]] format has changed for field permissions in role [test], \ From f72ad5187207c99b61f64a4321cd77b51d5941ff Mon Sep 17 00:00:00 2001 From: Slobodan Adamovic Date: Tue, 16 Apr 2024 13:25:35 +0200 Subject: [PATCH 3/3] nit: method naming --- .../core/security/action/apikey/ApiKey.java | 2 +- .../BulkUpdateApiKeyRequestTranslator.java | 2 +- .../apikey/CreateApiKeyRequestBuilder.java | 2 +- .../apikey/UpdateApiKeyRequestTranslator.java | 2 +- .../action/role/PutRoleRequestBuilder.java | 2 +- .../authc/CrossClusterAccessSubjectInfo.java | 2 +- .../core/security/authz/RoleDescriptor.java | 2 +- .../authz/RoleDescriptorsIntersection.java | 2 +- .../GetServiceAccountResponseTests.java | 2 +- .../security/authz/RoleDescriptorTests.java | 54 +++++++++---------- ...RoleWithRemoteIndicesPrivilegesRestIT.java | 2 +- .../security/authc/ApiKeyIntegTests.java | 2 +- .../authc/apikey/ApiKeySingleNodeTests.java | 4 +- .../xpack/security/authc/ApiKeyService.java | 2 +- .../security/authz/store/FileRolesStore.java | 2 +- .../authz/store/NativeRolesStore.java | 2 +- .../action/apikey/RestGrantApiKeyAction.java | 4 +- .../test/TestSecurityClient.java | 2 +- .../security/authc/ApiKeyServiceTests.java | 2 +- .../permission/FieldPermissionsTests.java | 20 ++++--- 20 files changed, 61 insertions(+), 53 deletions(-) diff --git a/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/security/action/apikey/ApiKey.java b/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/security/action/apikey/ApiKey.java index 89d74db5b57c2..57cf816a46072 100644 --- a/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/security/action/apikey/ApiKey.java +++ b/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/security/action/apikey/ApiKey.java @@ -395,7 +395,7 @@ public String toString() { + "]"; } - private static final RoleDescriptor.Parser ROLE_DESCRIPTOR_PARSER = RoleDescriptor.parser().allowRestriction(true).build(); + private static final RoleDescriptor.Parser ROLE_DESCRIPTOR_PARSER = RoleDescriptor.parserBuilder().allowRestriction(true).build(); static final ConstructingObjectParser PARSER; static { PARSER = new ConstructingObjectParser<>("api_key", true, ApiKey::new); diff --git a/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/security/action/apikey/BulkUpdateApiKeyRequestTranslator.java b/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/security/action/apikey/BulkUpdateApiKeyRequestTranslator.java index a1d6bd9329139..d4fdb2d7f1028 100644 --- a/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/security/action/apikey/BulkUpdateApiKeyRequestTranslator.java +++ b/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/security/action/apikey/BulkUpdateApiKeyRequestTranslator.java @@ -26,7 +26,7 @@ public interface BulkUpdateApiKeyRequestTranslator { BulkUpdateApiKeyRequest translate(RestRequest request) throws IOException; class Default implements BulkUpdateApiKeyRequestTranslator { - private static final RoleDescriptor.Parser ROLE_DESCRIPTOR_PARSER = RoleDescriptor.parser().allowRestriction(true).build(); + private static final RoleDescriptor.Parser ROLE_DESCRIPTOR_PARSER = RoleDescriptor.parserBuilder().allowRestriction(true).build(); private static final ConstructingObjectParser PARSER = createParser( (n, p) -> ROLE_DESCRIPTOR_PARSER.parse(n, p) ); diff --git a/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/security/action/apikey/CreateApiKeyRequestBuilder.java b/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/security/action/apikey/CreateApiKeyRequestBuilder.java index 02d0f978dd12f..b8c4ab326fd34 100644 --- a/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/security/action/apikey/CreateApiKeyRequestBuilder.java +++ b/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/security/action/apikey/CreateApiKeyRequestBuilder.java @@ -31,7 +31,7 @@ * Request builder for populating a {@link CreateApiKeyRequest} */ public class CreateApiKeyRequestBuilder extends ActionRequestBuilder { - private static final RoleDescriptor.Parser ROLE_DESCRIPTOR_PARSER = RoleDescriptor.parser().allowRestriction(true).build(); + private static final RoleDescriptor.Parser ROLE_DESCRIPTOR_PARSER = RoleDescriptor.parserBuilder().allowRestriction(true).build(); private static final ConstructingObjectParser PARSER = createParser(ROLE_DESCRIPTOR_PARSER::parse); @SuppressWarnings("unchecked") diff --git a/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/security/action/apikey/UpdateApiKeyRequestTranslator.java b/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/security/action/apikey/UpdateApiKeyRequestTranslator.java index 26f060560255c..fa157224c79be 100644 --- a/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/security/action/apikey/UpdateApiKeyRequestTranslator.java +++ b/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/security/action/apikey/UpdateApiKeyRequestTranslator.java @@ -25,7 +25,7 @@ public interface UpdateApiKeyRequestTranslator { UpdateApiKeyRequest translate(RestRequest request) throws IOException; class Default implements UpdateApiKeyRequestTranslator { - private static final RoleDescriptor.Parser ROLE_DESCRIPTOR_PARSER = RoleDescriptor.parser().allowRestriction(true).build(); + private static final RoleDescriptor.Parser ROLE_DESCRIPTOR_PARSER = RoleDescriptor.parserBuilder().allowRestriction(true).build(); private static final ConstructingObjectParser PARSER = createParser(ROLE_DESCRIPTOR_PARSER::parse); @SuppressWarnings("unchecked") diff --git a/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/security/action/role/PutRoleRequestBuilder.java b/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/security/action/role/PutRoleRequestBuilder.java index ae919c9403af5..e2da04bb61534 100644 --- a/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/security/action/role/PutRoleRequestBuilder.java +++ b/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/security/action/role/PutRoleRequestBuilder.java @@ -21,7 +21,7 @@ */ public class PutRoleRequestBuilder extends ActionRequestBuilder { - private static final RoleDescriptor.Parser ROLE_DESCRIPTOR_PARSER = RoleDescriptor.parser().build(); + private static final RoleDescriptor.Parser ROLE_DESCRIPTOR_PARSER = RoleDescriptor.parserBuilder().build(); public PutRoleRequestBuilder(ElasticsearchClient client) { super(client, PutRoleAction.INSTANCE, new PutRoleRequest()); diff --git a/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/security/authc/CrossClusterAccessSubjectInfo.java b/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/security/authc/CrossClusterAccessSubjectInfo.java index 0a0f9710edfc2..f91df320bb92d 100644 --- a/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/security/authc/CrossClusterAccessSubjectInfo.java +++ b/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/security/authc/CrossClusterAccessSubjectInfo.java @@ -224,7 +224,7 @@ public static final class RoleDescriptorsBytes implements Writeable { public static final RoleDescriptorsBytes EMPTY = new RoleDescriptorsBytes(new BytesArray("{}")); - private static final RoleDescriptor.Parser ROLE_DESCRIPTOR_PARSER = RoleDescriptor.parser().build(); + private static final RoleDescriptor.Parser ROLE_DESCRIPTOR_PARSER = RoleDescriptor.parserBuilder().build(); private final BytesReference rawBytes; diff --git a/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/security/authz/RoleDescriptor.java b/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/security/authz/RoleDescriptor.java index f4fbd37160280..d1d24e2e4461e 100644 --- a/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/security/authz/RoleDescriptor.java +++ b/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/security/authz/RoleDescriptor.java @@ -420,7 +420,7 @@ public void writeTo(StreamOutput out) throws IOException { } } - public static Parser.Builder parser() { + public static Parser.Builder parserBuilder() { return new Parser.Builder(); } diff --git a/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/security/authz/RoleDescriptorsIntersection.java b/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/security/authz/RoleDescriptorsIntersection.java index 183bd3583484e..446209b1d7ac3 100644 --- a/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/security/authz/RoleDescriptorsIntersection.java +++ b/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/security/authz/RoleDescriptorsIntersection.java @@ -26,7 +26,7 @@ public record RoleDescriptorsIntersection(Collection> roleDe public static RoleDescriptorsIntersection EMPTY = new RoleDescriptorsIntersection(Collections.emptyList()); - private static final RoleDescriptor.Parser ROLE_DESCRIPTOR_PARSER = RoleDescriptor.parser().allowRestriction(true).build(); + private static final RoleDescriptor.Parser ROLE_DESCRIPTOR_PARSER = RoleDescriptor.parserBuilder().allowRestriction(true).build(); public RoleDescriptorsIntersection(RoleDescriptor roleDescriptor) { this(List.of(Set.of(roleDescriptor))); diff --git a/x-pack/plugin/core/src/test/java/org/elasticsearch/xpack/core/security/action/service/GetServiceAccountResponseTests.java b/x-pack/plugin/core/src/test/java/org/elasticsearch/xpack/core/security/action/service/GetServiceAccountResponseTests.java index 6294dcdc97eb5..b37b923ce96c5 100644 --- a/x-pack/plugin/core/src/test/java/org/elasticsearch/xpack/core/security/action/service/GetServiceAccountResponseTests.java +++ b/x-pack/plugin/core/src/test/java/org/elasticsearch/xpack/core/security/action/service/GetServiceAccountResponseTests.java @@ -97,7 +97,7 @@ private void assertRoleDescriptorEquals(Map responseFragment, Ro @SuppressWarnings("unchecked") final Map descriptorMap = (Map) responseFragment.get("role_descriptor"); assertThat( - RoleDescriptor.parser() + RoleDescriptor.parserBuilder() .build() .parse(roleDescriptor.getName(), XContentTestUtils.convertToXContent(descriptorMap, XContentType.JSON), XContentType.JSON), equalTo(roleDescriptor) diff --git a/x-pack/plugin/core/src/test/java/org/elasticsearch/xpack/core/security/authz/RoleDescriptorTests.java b/x-pack/plugin/core/src/test/java/org/elasticsearch/xpack/core/security/authz/RoleDescriptorTests.java index 08c2680c35124..efa1dc2e29d10 100644 --- a/x-pack/plugin/core/src/test/java/org/elasticsearch/xpack/core/security/authz/RoleDescriptorTests.java +++ b/x-pack/plugin/core/src/test/java/org/elasticsearch/xpack/core/security/authz/RoleDescriptorTests.java @@ -162,7 +162,7 @@ public void testToXContentRoundtrip() throws Exception { final RoleDescriptor descriptor = randomRoleDescriptor(true, true, true); final XContentType xContentType = randomFrom(XContentType.values()); final BytesReference xContentValue = toShuffledXContent(descriptor, xContentType, ToXContent.EMPTY_PARAMS, false); - final RoleDescriptor parsed = RoleDescriptor.parser() + final RoleDescriptor parsed = RoleDescriptor.parserBuilder() .allowRestriction(true) .build() .parse(descriptor.getName(), xContentValue, xContentType); @@ -171,7 +171,7 @@ public void testToXContentRoundtrip() throws Exception { public void testParse() throws Exception { String q = "{\"cluster\":[\"a\", \"b\"]}"; - RoleDescriptor rd = RoleDescriptor.parser().build().parse("test", new BytesArray(q), XContentType.JSON); + RoleDescriptor rd = RoleDescriptor.parserBuilder().build().parse("test", new BytesArray(q), XContentType.JSON); assertEquals("test", rd.getName()); assertArrayEquals(new String[] { "a", "b" }, rd.getClusterPrivileges()); assertEquals(0, rd.getIndicesPrivileges().length); @@ -182,7 +182,7 @@ public void testParse() throws Exception { "cluster": [ "a", "b" ], "run_as": [ "m", "n" ] }"""; - rd = RoleDescriptor.parser().build().parse("test", new BytesArray(q), XContentType.JSON); + rd = RoleDescriptor.parserBuilder().build().parse("test", new BytesArray(q), XContentType.JSON); assertEquals("test", rd.getName()); assertArrayEquals(new String[] { "a", "b" }, rd.getClusterPrivileges()); assertEquals(0, rd.getIndicesPrivileges().length); @@ -249,7 +249,7 @@ public void testParse() throws Exception { "workflows": ["search_application_query"] } }"""; - rd = RoleDescriptor.parser().allowRestriction(true).build().parse("test", new BytesArray(q), XContentType.JSON); + rd = RoleDescriptor.parserBuilder().allowRestriction(true).build().parse("test", new BytesArray(q), XContentType.JSON); assertEquals("test", rd.getName()); assertArrayEquals(new String[] { "a", "b" }, rd.getClusterPrivileges()); assertEquals(3, rd.getIndicesPrivileges().length); @@ -277,7 +277,7 @@ public void testParse() throws Exception { } } }"""; - rd = RoleDescriptor.parser().build().parse("test", new BytesArray(q), XContentType.JSON); + rd = RoleDescriptor.parserBuilder().build().parse("test", new BytesArray(q), XContentType.JSON); assertEquals("test", rd.getName()); assertArrayEquals(new String[] { "a", "b" }, rd.getClusterPrivileges()); assertEquals(1, rd.getIndicesPrivileges().length); @@ -288,7 +288,7 @@ public void testParse() throws Exception { q = """ {"cluster":["a", "b"], "metadata":{"foo":"bar"}}"""; - rd = RoleDescriptor.parser().build().parse("test", new BytesArray(q), XContentType.JSON); + rd = RoleDescriptor.parserBuilder().build().parse("test", new BytesArray(q), XContentType.JSON); assertEquals("test", rd.getName()); assertArrayEquals(new String[] { "a", "b" }, rd.getClusterPrivileges()); assertEquals(0, rd.getIndicesPrivileges().length); @@ -330,7 +330,7 @@ public void testParse() throws Exception { } } }"""; - rd = RoleDescriptor.parser().build().parse("test", new BytesArray(q), XContentType.JSON); + rd = RoleDescriptor.parserBuilder().build().parse("test", new BytesArray(q), XContentType.JSON); assertThat(rd.getName(), equalTo("test")); assertThat(rd.getClusterPrivileges(), arrayContaining("a", "b")); assertThat(rd.getIndicesPrivileges().length, equalTo(1)); @@ -371,7 +371,7 @@ public void testParse() throws Exception { } } }"""; - rd = RoleDescriptor.parser().build().parse("testUpdateProfile", new BytesArray(q), XContentType.JSON); + rd = RoleDescriptor.parserBuilder().build().parse("testUpdateProfile", new BytesArray(q), XContentType.JSON); assertThat(rd.getName(), is("testUpdateProfile")); assertThat(rd.getClusterPrivileges(), arrayContaining("manage")); assertThat(rd.getIndicesPrivileges(), Matchers.emptyArray()); @@ -396,7 +396,7 @@ public void testParse() throws Exception { q = """ {"applications": [{"application": "myapp", "resources": ["*"], "privileges": ["login" ]}] }"""; - rd = RoleDescriptor.parser().build().parse("test", new BytesArray(q), XContentType.JSON); + rd = RoleDescriptor.parserBuilder().build().parse("test", new BytesArray(q), XContentType.JSON); assertThat(rd.getName(), equalTo("test")); assertThat(rd.getClusterPrivileges(), emptyArray()); assertThat(rd.getIndicesPrivileges(), emptyArray()); @@ -410,11 +410,11 @@ public void testParse() throws Exception { {"applications":[{"not_supported": true, "resources": ["*"], "privileges": ["my-app:login" ]}] }"""; final IllegalArgumentException ex = expectThrows( IllegalArgumentException.class, - () -> RoleDescriptor.parser().build().parse("test", new BytesArray(badJson), XContentType.JSON) + () -> RoleDescriptor.parserBuilder().build().parse("test", new BytesArray(badJson), XContentType.JSON) ); assertThat(ex.getMessage(), containsString("not_supported")); - rd = RoleDescriptor.parser().allowRestriction(true).build().parse("test_empty_restriction", new BytesArray(""" + rd = RoleDescriptor.parserBuilder().allowRestriction(true).build().parse("test_empty_restriction", new BytesArray(""" { "index": [{"names": "idx1", "privileges": [ "p1", "p2" ]}], "restriction":{} @@ -425,7 +425,7 @@ public void testParse() throws Exception { final ElasticsearchParseException pex1 = expectThrows( ElasticsearchParseException.class, - () -> RoleDescriptor.parser().allowRestriction(true).build().parse("test_null_workflows", new BytesArray(""" + () -> RoleDescriptor.parserBuilder().allowRestriction(true).build().parse("test_null_workflows", new BytesArray(""" { "index": [{"names": ["idx1"], "privileges": [ "p1", "p2" ]}], "restriction":{"workflows":null} @@ -441,7 +441,7 @@ public void testParse() throws Exception { final ElasticsearchParseException pex2 = expectThrows( ElasticsearchParseException.class, - () -> RoleDescriptor.parser().allowRestriction(true).build().parse("test_empty_workflows", new BytesArray(""" + () -> RoleDescriptor.parserBuilder().allowRestriction(true).build().parse("test_empty_workflows", new BytesArray(""" { "index": [{"names": ["idx1"], "privileges": [ "p1", "p2" ]}], "restriction":{"workflows":[]} @@ -480,7 +480,7 @@ public void testParsingFieldPermissionsUsesCache() throws IOException { ] } """; - RoleDescriptor.parser().build().parse("test", new BytesArray(json), XContentType.JSON); + RoleDescriptor.parserBuilder().build().parse("test", new BytesArray(json), XContentType.JSON); final int numberOfFieldSecurityBlocks = 2; final Cache.CacheStats betweenStats = fieldPermissionsCache.getCacheStats(); @@ -489,7 +489,7 @@ public void testParsingFieldPermissionsUsesCache() throws IOException { final int iterations = randomIntBetween(1, 5); for (int i = 0; i < iterations; i++) { - RoleDescriptor.parser().build().parse("test", new BytesArray(json), XContentType.JSON); + RoleDescriptor.parserBuilder().build().parse("test", new BytesArray(json), XContentType.JSON); } final Cache.CacheStats afterStats = fieldPermissionsCache.getCacheStats(); @@ -611,7 +611,7 @@ public void testParseRoleWithRestrictionFailsWhenAllowRestrictionIsFalse() { }"""; final ElasticsearchParseException e = expectThrows( ElasticsearchParseException.class, - () -> RoleDescriptor.parser() + () -> RoleDescriptor.parserBuilder() .allowRestriction(false) .build() .parse( @@ -634,7 +634,7 @@ public void testParseRoleWithRestrictionWhenAllowRestrictionIsTrue() throws IOEx "workflows": ["search_application"] } }"""; - RoleDescriptor role = RoleDescriptor.parser() + RoleDescriptor role = RoleDescriptor.parserBuilder() .allowRestriction(true) .build() .parse( @@ -660,7 +660,7 @@ public void testParseEmptyQuery() throws Exception { } ] }"""; - RoleDescriptor rd = RoleDescriptor.parser().build().parse("test", new BytesArray(json), XContentType.JSON); + RoleDescriptor rd = RoleDescriptor.parserBuilder().build().parse("test", new BytesArray(json), XContentType.JSON); assertEquals("test", rd.getName()); assertArrayEquals(new String[] { "a", "b" }, rd.getClusterPrivileges()); assertEquals(1, rd.getIndicesPrivileges().length); @@ -682,7 +682,7 @@ public void testParseNullQuery() throws Exception { } ] }"""; - RoleDescriptor rd = RoleDescriptor.parser().build().parse("test", new BytesArray(json), XContentType.JSON); + RoleDescriptor rd = RoleDescriptor.parserBuilder().build().parse("test", new BytesArray(json), XContentType.JSON); assertEquals("test", rd.getName()); assertArrayEquals(new String[] { "a", "b" }, rd.getClusterPrivileges()); assertEquals(1, rd.getIndicesPrivileges().length); @@ -704,7 +704,7 @@ public void testParseEmptyQueryUsingDeprecatedIndicesField() throws Exception { } ] }"""; - RoleDescriptor rd = RoleDescriptor.parser().build().parse("test", new BytesArray(json), XContentType.JSON); + RoleDescriptor rd = RoleDescriptor.parserBuilder().build().parse("test", new BytesArray(json), XContentType.JSON); assertEquals("test", rd.getName()); assertArrayEquals(new String[] { "a", "b" }, rd.getClusterPrivileges()); assertEquals(1, rd.getIndicesPrivileges().length); @@ -726,7 +726,7 @@ public void testParseIgnoresTransientMetadata() throws Exception { ); XContentBuilder b = jsonBuilder(); descriptor.toXContent(b, ToXContent.EMPTY_PARAMS); - RoleDescriptor parsed = RoleDescriptor.parser().build().parse("test", BytesReference.bytes(b), XContentType.JSON); + RoleDescriptor parsed = RoleDescriptor.parserBuilder().build().parse("test", BytesReference.bytes(b), XContentType.JSON); assertNotNull(parsed); assertEquals(1, parsed.getTransientMetadata().size()); assertEquals(true, parsed.getTransientMetadata().get("enabled")); @@ -750,7 +750,7 @@ public void testParseIndicesPrivilegesSucceedsWhenExceptFieldsIsSubsetOfGrantedF } ] }""", grant, except); - final RoleDescriptor rd = RoleDescriptor.parser().build().parse("test", new BytesArray(json), XContentType.JSON); + final RoleDescriptor rd = RoleDescriptor.parserBuilder().build().parse("test", new BytesArray(json), XContentType.JSON); assertEquals("test", rd.getName()); assertEquals(1, rd.getIndicesPrivileges().length); assertArrayEquals(new String[] { "idx1", "idx2" }, rd.getIndicesPrivileges()[0].getIndices()); @@ -779,7 +779,7 @@ public void testParseIndicesPrivilegesFailsWhenExceptFieldsAreNotSubsetOfGranted }"""; final ElasticsearchParseException epe = expectThrows( ElasticsearchParseException.class, - () -> RoleDescriptor.parser().build().parse("test", new BytesArray(json), XContentType.JSON) + () -> RoleDescriptor.parserBuilder().build().parse("test", new BytesArray(json), XContentType.JSON) ); assertThat(epe, TestMatchers.throwableWithMessage(containsString("must be a subset of the granted fields "))); assertThat(epe, TestMatchers.throwableWithMessage(containsString("f1"))); @@ -799,7 +799,7 @@ public void testParseRemoteIndicesPrivilegesFailsWhenClustersFieldMissing() { }"""; final ElasticsearchParseException epe = expectThrows( ElasticsearchParseException.class, - () -> RoleDescriptor.parser().build().parse("test", new BytesArray(json), XContentType.JSON) + () -> RoleDescriptor.parserBuilder().build().parse("test", new BytesArray(json), XContentType.JSON) ); assertThat( epe, @@ -822,7 +822,7 @@ public void testParseIndicesPrivilegesFailsWhenClustersFieldPresent() { }"""; final ElasticsearchParseException epe = expectThrows( ElasticsearchParseException.class, - () -> RoleDescriptor.parser().build().parse("test", new BytesArray(json), XContentType.JSON) + () -> RoleDescriptor.parserBuilder().build().parse("test", new BytesArray(json), XContentType.JSON) ); assertThat( epe, @@ -966,7 +966,7 @@ public void testGlobalPrivilegesOrdering() throws IOException { } } }""", profileNamesString, applicationNamesString); - RoleDescriptor role3 = RoleDescriptor.parser().build().parse(roleName, new BytesArray(json), XContentType.JSON); + RoleDescriptor role3 = RoleDescriptor.parserBuilder().build().parse(roleName, new BytesArray(json), XContentType.JSON); assertThat(role3, is(role1)); json = Strings.format(""" { @@ -983,7 +983,7 @@ public void testGlobalPrivilegesOrdering() throws IOException { } } }""", applicationNamesString, profileNamesString); - RoleDescriptor role4 = RoleDescriptor.parser().build().parse(roleName, new BytesArray(json), XContentType.JSON); + RoleDescriptor role4 = RoleDescriptor.parserBuilder().build().parse(roleName, new BytesArray(json), XContentType.JSON); assertThat(role4, is(role1)); } diff --git a/x-pack/plugin/security/qa/security-trial/src/javaRestTest/java/org/elasticsearch/xpack/security/role/RoleWithRemoteIndicesPrivilegesRestIT.java b/x-pack/plugin/security/qa/security-trial/src/javaRestTest/java/org/elasticsearch/xpack/security/role/RoleWithRemoteIndicesPrivilegesRestIT.java index 6534f60e59da8..d76902efc35b5 100644 --- a/x-pack/plugin/security/qa/security-trial/src/javaRestTest/java/org/elasticsearch/xpack/security/role/RoleWithRemoteIndicesPrivilegesRestIT.java +++ b/x-pack/plugin/security/qa/security-trial/src/javaRestTest/java/org/elasticsearch/xpack/security/role/RoleWithRemoteIndicesPrivilegesRestIT.java @@ -323,7 +323,7 @@ private void expectRoleDescriptorInResponse(final Response getRoleResponse, fina throws IOException { final Map actual = responseAsParser(getRoleResponse).map( HashMap::new, - p -> RoleDescriptor.parser().build().parse(expectedRoleDescriptor.getName(), p) + p -> RoleDescriptor.parserBuilder().build().parse(expectedRoleDescriptor.getName(), p) ); assertThat(actual, equalTo(Map.of(expectedRoleDescriptor.getName(), expectedRoleDescriptor))); } diff --git a/x-pack/plugin/security/src/internalClusterTest/java/org/elasticsearch/xpack/security/authc/ApiKeyIntegTests.java b/x-pack/plugin/security/src/internalClusterTest/java/org/elasticsearch/xpack/security/authc/ApiKeyIntegTests.java index a7d2a7df2976c..b8f6551f36037 100644 --- a/x-pack/plugin/security/src/internalClusterTest/java/org/elasticsearch/xpack/security/authc/ApiKeyIntegTests.java +++ b/x-pack/plugin/security/src/internalClusterTest/java/org/elasticsearch/xpack/security/authc/ApiKeyIntegTests.java @@ -2874,7 +2874,7 @@ private void expectRoleDescriptorsForApiKey( for (RoleDescriptor expectedRoleDescriptor : expectedRoleDescriptors) { assertThat(rawRoleDescriptor, hasKey(expectedRoleDescriptor.getName())); final var descriptor = (Map) rawRoleDescriptor.get(expectedRoleDescriptor.getName()); - final var roleDescriptor = RoleDescriptor.parser() + final var roleDescriptor = RoleDescriptor.parserBuilder() .allowRestriction(true) .build() .parse( diff --git a/x-pack/plugin/security/src/internalClusterTest/java/org/elasticsearch/xpack/security/authc/apikey/ApiKeySingleNodeTests.java b/x-pack/plugin/security/src/internalClusterTest/java/org/elasticsearch/xpack/security/authc/apikey/ApiKeySingleNodeTests.java index bd35ae6148c6b..f4a314c55acfc 100644 --- a/x-pack/plugin/security/src/internalClusterTest/java/org/elasticsearch/xpack/security/authc/apikey/ApiKeySingleNodeTests.java +++ b/x-pack/plugin/security/src/internalClusterTest/java/org/elasticsearch/xpack/security/authc/apikey/ApiKeySingleNodeTests.java @@ -247,7 +247,7 @@ public void testServiceAccountApiKey() throws IOException { @SuppressWarnings("unchecked") final Map descriptor = (Map) fleetServerRoleDescriptor.get("elastic/fleet-server"); - final RoleDescriptor roleDescriptor = RoleDescriptor.parser() + final RoleDescriptor roleDescriptor = RoleDescriptor.parserBuilder() .build() .parse("elastic/fleet-server", XContentTestUtils.convertToXContent(descriptor, XContentType.JSON), XContentType.JSON); assertThat(roleDescriptor, equalTo(ServiceAccountService.getServiceAccounts().get("elastic/fleet-server").roleDescriptor())); @@ -585,7 +585,7 @@ public void testCreateCrossClusterApiKey() throws IOException { final Map roleDescriptors = (Map) document.get("role_descriptors"); assertThat(roleDescriptors.keySet(), contains("cross_cluster")); @SuppressWarnings("unchecked") - final RoleDescriptor actualRoleDescriptor = RoleDescriptor.parser() + final RoleDescriptor actualRoleDescriptor = RoleDescriptor.parserBuilder() .build() .parse( "cross_cluster", diff --git a/x-pack/plugin/security/src/main/java/org/elasticsearch/xpack/security/authc/ApiKeyService.java b/x-pack/plugin/security/src/main/java/org/elasticsearch/xpack/security/authc/ApiKeyService.java index 47cb053e4b5aa..e4436d4fabe71 100644 --- a/x-pack/plugin/security/src/main/java/org/elasticsearch/xpack/security/authc/ApiKeyService.java +++ b/x-pack/plugin/security/src/main/java/org/elasticsearch/xpack/security/authc/ApiKeyService.java @@ -202,7 +202,7 @@ public class ApiKeyService { Property.NodeScope ); - private static final RoleDescriptor.Parser ROLE_DESCRIPTOR_PARSER = RoleDescriptor.parser().allowRestriction(true).build(); + private static final RoleDescriptor.Parser ROLE_DESCRIPTOR_PARSER = RoleDescriptor.parserBuilder().allowRestriction(true).build(); private final Clock clock; private final Client client; diff --git a/x-pack/plugin/security/src/main/java/org/elasticsearch/xpack/security/authz/store/FileRolesStore.java b/x-pack/plugin/security/src/main/java/org/elasticsearch/xpack/security/authz/store/FileRolesStore.java index e259875b533b3..368ec3825c0c2 100644 --- a/x-pack/plugin/security/src/main/java/org/elasticsearch/xpack/security/authz/store/FileRolesStore.java +++ b/x-pack/plugin/security/src/main/java/org/elasticsearch/xpack/security/authz/store/FileRolesStore.java @@ -67,7 +67,7 @@ public class FileRolesStore implements BiConsumer, ActionListener, ActionListener< private static final Logger logger = LogManager.getLogger(NativeRolesStore.class); - private static final RoleDescriptor.Parser ROLE_DESCRIPTOR_PARSER = RoleDescriptor.parser().allow2xFormat(true).build(); + private static final RoleDescriptor.Parser ROLE_DESCRIPTOR_PARSER = RoleDescriptor.parserBuilder().allow2xFormat(true).build(); private final Settings settings; private final Client client; diff --git a/x-pack/plugin/security/src/main/java/org/elasticsearch/xpack/security/rest/action/apikey/RestGrantApiKeyAction.java b/x-pack/plugin/security/src/main/java/org/elasticsearch/xpack/security/rest/action/apikey/RestGrantApiKeyAction.java index 7e38b3c1968ce..572cf70586f7d 100644 --- a/x-pack/plugin/security/src/main/java/org/elasticsearch/xpack/security/rest/action/apikey/RestGrantApiKeyAction.java +++ b/x-pack/plugin/security/src/main/java/org/elasticsearch/xpack/security/rest/action/apikey/RestGrantApiKeyAction.java @@ -50,7 +50,9 @@ public interface RequestTranslator { GrantApiKeyRequest translate(RestRequest request) throws IOException; class Default implements RequestTranslator { - private static final RoleDescriptor.Parser ROLE_DESCRIPTOR_PARSER = RoleDescriptor.parser().allowRestriction(true).build(); + private static final RoleDescriptor.Parser ROLE_DESCRIPTOR_PARSER = RoleDescriptor.parserBuilder() + .allowRestriction(true) + .build(); private static final ObjectParser PARSER = createParser(ROLE_DESCRIPTOR_PARSER::parse); protected static ObjectParser createParser( diff --git a/x-pack/plugin/security/src/test/java/org/elasticsearch/test/TestSecurityClient.java b/x-pack/plugin/security/src/test/java/org/elasticsearch/test/TestSecurityClient.java index f540a4a128d33..e8eb50e3a6529 100644 --- a/x-pack/plugin/security/src/test/java/org/elasticsearch/test/TestSecurityClient.java +++ b/x-pack/plugin/security/src/test/java/org/elasticsearch/test/TestSecurityClient.java @@ -212,7 +212,7 @@ private Map getRoleDescriptors(String roleParameter) thr XContentParserUtils.ensureExpectedToken(XContentParser.Token.FIELD_NAME, parser.currentToken(), parser); final String roleName = parser.currentName(); XContentParserUtils.ensureExpectedToken(XContentParser.Token.START_OBJECT, parser.nextToken(), parser); - final RoleDescriptor role = RoleDescriptor.parser().build().parse(roleName, parser); + final RoleDescriptor role = RoleDescriptor.parserBuilder().build().parse(roleName, parser); roles.put(roleName, role); } } diff --git a/x-pack/plugin/security/src/test/java/org/elasticsearch/xpack/security/authc/ApiKeyServiceTests.java b/x-pack/plugin/security/src/test/java/org/elasticsearch/xpack/security/authc/ApiKeyServiceTests.java index ad72ff513aee6..269031804f7e3 100644 --- a/x-pack/plugin/security/src/test/java/org/elasticsearch/xpack/security/authc/ApiKeyServiceTests.java +++ b/x-pack/plugin/security/src/test/java/org/elasticsearch/xpack/security/authc/ApiKeyServiceTests.java @@ -1866,7 +1866,7 @@ public void testApiKeyDocCache() throws IOException, ExecutionException, Interru final String apiKey3 = randomAlphaOfLength(16); ApiKeyCredentials apiKeyCredentials3 = getApiKeyCredentials(docId3, apiKey3, type); final List keyRoles = List.of( - RoleDescriptor.parser() + RoleDescriptor.parserBuilder() .allow2xFormat(true) .build() .parse("key-role", new BytesArray("{\"cluster\":[\"monitor\"]}"), XContentType.JSON) diff --git a/x-pack/plugin/security/src/test/java/org/elasticsearch/xpack/security/authz/permission/FieldPermissionsTests.java b/x-pack/plugin/security/src/test/java/org/elasticsearch/xpack/security/authz/permission/FieldPermissionsTests.java index b7c50336df0d8..fc5374fb324ac 100644 --- a/x-pack/plugin/security/src/test/java/org/elasticsearch/xpack/security/authz/permission/FieldPermissionsTests.java +++ b/x-pack/plugin/security/src/test/java/org/elasticsearch/xpack/security/authz/permission/FieldPermissionsTests.java @@ -37,7 +37,7 @@ public void testParseFieldPermissions() throws Exception { } ] }"""; - RoleDescriptor.Parser roleParser = RoleDescriptor.parser().build(); + RoleDescriptor.Parser roleParser = RoleDescriptor.parserBuilder().build(); RoleDescriptor rd = roleParser.parse("test", new BytesArray(q), XContentType.JSON); assertArrayEquals(rd.getIndicesPrivileges()[0].getGrantedFields(), new String[] { "f1", "f2", "f3", "f4" }); assertArrayEquals(rd.getIndicesPrivileges()[0].getDeniedFields(), new String[] { "f3", "f4" }); @@ -199,14 +199,14 @@ public void testParseFieldPermissions() throws Exception { public void testBWCFieldPermissions() throws Exception { String q = """ {"indices": [ {"names": "idx2", "privileges": ["p3"], "fields": ["f1", "f2"]}]}"""; - RoleDescriptor rd = RoleDescriptor.parser().allow2xFormat(true).build().parse("test", new BytesArray(q), XContentType.JSON); + RoleDescriptor rd = RoleDescriptor.parserBuilder().allow2xFormat(true).build().parse("test", new BytesArray(q), XContentType.JSON); assertArrayEquals(rd.getIndicesPrivileges()[0].getGrantedFields(), new String[] { "f1", "f2" }); assertNull(rd.getIndicesPrivileges()[0].getDeniedFields()); final String failingQuery = q; ElasticsearchParseException e = expectThrows( ElasticsearchParseException.class, - () -> RoleDescriptor.parser().allow2xFormat(false).build().parse("test", new BytesArray(failingQuery), XContentType.JSON) + () -> RoleDescriptor.parserBuilder().allow2xFormat(false).build().parse("test", new BytesArray(failingQuery), XContentType.JSON) ); assertThat(e.getDetailedMessage(), containsString(""" ["fields": [...]] format has changed for field permissions in role [test], \ @@ -214,13 +214,16 @@ public void testBWCFieldPermissions() throws Exception { q = """ {"indices": [ {"names": "idx2", "privileges": ["p3"], "fields": []}]}"""; - rd = RoleDescriptor.parser().allow2xFormat(true).build().parse("test", new BytesArray(q), XContentType.JSON); + rd = RoleDescriptor.parserBuilder().allow2xFormat(true).build().parse("test", new BytesArray(q), XContentType.JSON); assertArrayEquals(rd.getIndicesPrivileges()[0].getGrantedFields(), new String[] {}); assertNull(rd.getIndicesPrivileges()[0].getDeniedFields()); final String failingQuery2 = q; e = expectThrows( ElasticsearchParseException.class, - () -> RoleDescriptor.parser().allow2xFormat(false).build().parse("test", new BytesArray(failingQuery2), XContentType.JSON) + () -> RoleDescriptor.parserBuilder() + .allow2xFormat(false) + .build() + .parse("test", new BytesArray(failingQuery2), XContentType.JSON) ); assertThat(e.getDetailedMessage(), containsString(""" ["fields": [...]] format has changed for field permissions in role [test], \ @@ -228,13 +231,16 @@ public void testBWCFieldPermissions() throws Exception { q = """ {"indices": [ {"names": "idx2", "privileges": ["p3"], "fields": null}]}"""; - rd = RoleDescriptor.parser().allow2xFormat(true).build().parse("test", new BytesArray(q), XContentType.JSON); + rd = RoleDescriptor.parserBuilder().allow2xFormat(true).build().parse("test", new BytesArray(q), XContentType.JSON); assertNull(rd.getIndicesPrivileges()[0].getGrantedFields()); assertNull(rd.getIndicesPrivileges()[0].getDeniedFields()); final String failingQuery3 = q; e = expectThrows( ElasticsearchParseException.class, - () -> RoleDescriptor.parser().allow2xFormat(false).build().parse("test", new BytesArray(failingQuery3), XContentType.JSON) + () -> RoleDescriptor.parserBuilder() + .allow2xFormat(false) + .build() + .parse("test", new BytesArray(failingQuery3), XContentType.JSON) ); assertThat(e.getDetailedMessage(), containsString(""" ["fields": [...]] format has changed for field permissions in role [test], \