From 75fa1d5e7a0966f50c2edc26784decb724282507 Mon Sep 17 00:00:00 2001 From: Sean Leonard Date: Fri, 8 Jul 2022 15:51:34 -0700 Subject: [PATCH 01/18] Updated FieldToRolesMap definitions and comment descriptions --- DataGateway.Auth/AuthorizationMetadataHelpers.cs | 2 +- DataGateway.Auth/IAuthorizationResolver.cs | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/DataGateway.Auth/AuthorizationMetadataHelpers.cs b/DataGateway.Auth/AuthorizationMetadataHelpers.cs index d12ccc5a80..b7873bd70d 100644 --- a/DataGateway.Auth/AuthorizationMetadataHelpers.cs +++ b/DataGateway.Auth/AuthorizationMetadataHelpers.cs @@ -19,7 +19,7 @@ public class EntityMetadata /// Key(field): id -> Value(collection): permitted in {Role1, Role2, ..., RoleN} /// Key(field): title -> Value(collection): permitted in {Role1} /// - public Dictionary>> FieldToRolesMap { get; set; } = new(); + public Dictionary>> FieldToRolesMap { get; set; } = new(); /// /// Given the key (actionName) returns a collection of roles diff --git a/DataGateway.Auth/IAuthorizationResolver.cs b/DataGateway.Auth/IAuthorizationResolver.cs index 0e9786399e..934a84de7e 100644 --- a/DataGateway.Auth/IAuthorizationResolver.cs +++ b/DataGateway.Auth/IAuthorizationResolver.cs @@ -79,10 +79,10 @@ public interface IAuthorizationResolver /// Applicable to GraphQL field directive @authorize on ObjectType fields. /// /// EntityName whose actionMetadata will be searched. - /// ActionName to lookup field permissions - /// Specific field to get collection of roles - /// Collection of role names allowed to perform actionType on Entity's field. - public IEnumerable GetRolesForField(string entityName, string actionName, string field); + /// Field to lookup action permissions + /// Specific action to get collection of roles + /// Collection of role names allowed to perform actionName on Entity's field. + public IEnumerable GetRolesForField(string entityName, string field, string actionName); /// /// Returns a list of roles which define permissions for the provided action. From 75414f59fcc9fe23d22372162fb2a9ba2d56b5f4 Mon Sep 17 00:00:00 2001 From: Sean Leonard Date: Fri, 8 Jul 2022 15:52:49 -0700 Subject: [PATCH 02/18] Populate FieldToRolesMap during permissions configuration processing in Authorization Resolver. --- .../Authorization/AuthorizationResolver.cs | 36 ++++++++++++++++--- 1 file changed, 32 insertions(+), 4 deletions(-) diff --git a/DataGateway.Service/Authorization/AuthorizationResolver.cs b/DataGateway.Service/Authorization/AuthorizationResolver.cs index 038e0494d9..584839799a 100644 --- a/DataGateway.Service/Authorization/AuthorizationResolver.cs +++ b/DataGateway.Service/Authorization/AuthorizationResolver.cs @@ -230,6 +230,9 @@ public void SetEntityPermissionMap(RuntimeConfig? runtimeConfig) string actionName = string.Empty; ActionMetadata actionToColumn = new(); IEnumerable allTableColumns = ResolveTableDefinitionColumns(entityName); + + // Implicitly, all table collumns are 'allowed' when an actiontype is a string. + // Since no granular field permissions exist for this action within the current role. if (actionElement.ValueKind is JsonValueKind.String) { actionName = actionElement.ToString(); @@ -291,6 +294,12 @@ public void SetEntityPermissionMap(RuntimeConfig? runtimeConfig) entityToRoleMap.ActionToRolesMap[actionName].Add(role); } + foreach (string allowedColumn in actionToColumn.Allowed) + { + entityToRoleMap.FieldToRolesMap.TryAdd(key: allowedColumn, CreateActionToRoleMap()); + entityToRoleMap.FieldToRolesMap[allowedColumn][actionName].Add(role); + } + roleToAction.ActionToColumnMap[actionName] = actionToColumn; } @@ -492,12 +501,12 @@ public IEnumerable GetRolesForAction(string entityName, string actionNam /// Applicable to GraphQL field directive @authorize on ObjectType fields. /// /// EntityName whose actionMetadata will be searched. - /// ActionName to lookup field permissions - /// Specific field to get collection of roles + /// Field to lookup action permissions + /// Specific action to get collection of roles /// Collection of role names allowed to perform actionName on Entity's field. - public IEnumerable GetRolesForField(string entityName, string actionName, string field) + public IEnumerable GetRolesForField(string entityName, string field, string actionName) { - return EntityPermissionsMap[entityName].FieldToRolesMap[actionName][field]; + return EntityPermissionsMap[entityName].FieldToRolesMap[field][actionName]; } /// @@ -515,6 +524,25 @@ private IEnumerable ResolveTableDefinitionColumns(string entityName) return _metadataProvider.GetTableDefinition(entityName).Columns.Keys; } + + /// + /// Creates new key value map of + /// Key: ActionType + /// Value: Collection of role names. + /// There are only four possible actions + /// + /// + private static Dictionary> CreateActionToRoleMap() + { + return new Dictionary>() + { + { ActionType.CREATE, new List()}, + { ActionType.READ, new List()}, + { ActionType.UPDATE, new List()}, + { ActionType.DELETE, new List()} + }; + } + #endregion } } From cd1bf6a9e97ebfb89ed041074f9579c698009a37 Mon Sep 17 00:00:00 2001 From: Sean Leonard Date: Fri, 8 Jul 2022 15:54:58 -0700 Subject: [PATCH 03/18] Add @authorize directive for field level READ operations in GraphQL --- .../Sql/SchemaConverter.cs | 28 ++++++++++++------- .../Services/GraphQLService.cs | 25 ++++++++++++++++- 2 files changed, 42 insertions(+), 11 deletions(-) diff --git a/DataGateway.Service.GraphQLBuilder/Sql/SchemaConverter.cs b/DataGateway.Service.GraphQLBuilder/Sql/SchemaConverter.cs index a9ea8b56dc..dac637986a 100644 --- a/DataGateway.Service.GraphQLBuilder/Sql/SchemaConverter.cs +++ b/DataGateway.Service.GraphQLBuilder/Sql/SchemaConverter.cs @@ -26,7 +26,8 @@ public static ObjectTypeDefinitionNode FromTableDefinition( TableDefinition tableDefinition, [NotNull] Entity configEntity, Dictionary entities, - IEnumerable? rolesAllowedForEntity = null) + IEnumerable? rolesAllowedForEntity = null, + IDictionary>? rolesAllowedForFields = null) { Dictionary fields = new(); List objectTypeDirectives = new(); @@ -70,16 +71,23 @@ public static ObjectTypeDefinitionNode FromTableDefinition( directives.Add(new DirectiveNode(DefaultValueDirectiveType.DirectiveName, new ArgumentNode("value", arg))); } - NamedTypeNode fieldType = new(GetGraphQLTypeForColumnType(column.SystemType)); - FieldDefinitionNode field = new( - location: null, - new(FormatNameForField(columnName)), - description: null, - new List(), - column.IsNullable ? fieldType : new NonNullTypeNode(fieldType), - directives); + // If no roles are allowed for the field, we should not include it in the schema. + // Consequently, the field is only added to schema if this conditional evaluates to TRUE. + if (rolesAllowedForFields is not null && rolesAllowedForFields.TryGetValue(key: columnName, out IEnumerable? roles)) + { + directives.Add(GraphQLUtils.CreateAuthorizationDirective(roles)); + + NamedTypeNode fieldType = new(GetGraphQLTypeForColumnType(column.SystemType)); + FieldDefinitionNode field = new( + location: null, + new(FormatNameForField(columnName)), + description: null, + new List(), + column.IsNullable ? fieldType : new NonNullTypeNode(fieldType), + directives); - fields.Add(columnName, field); + fields.Add(columnName, field); + } } if (configEntity.Relationships is not null) diff --git a/DataGateway.Service/Services/GraphQLService.cs b/DataGateway.Service/Services/GraphQLService.cs index bd9bb01d34..0272466f5f 100644 --- a/DataGateway.Service/Services/GraphQLService.cs +++ b/DataGateway.Service/Services/GraphQLService.cs @@ -13,6 +13,7 @@ using Azure.DataGateway.Service.GraphQLBuilder.Mutations; using Azure.DataGateway.Service.GraphQLBuilder.Queries; using Azure.DataGateway.Service.GraphQLBuilder.Sql; +using Azure.DataGateway.Service.Models; using Azure.DataGateway.Service.Resolvers; using Azure.DataGateway.Service.Services.MetadataProviders; using HotChocolate; @@ -191,8 +192,30 @@ DatabaseType.postgresql or // Collection of role names allowed to access entity, to be added to the authorize directive // of the objectTypeDefinitionNode. The authorize Directive is one of many directives created. IEnumerable rolesAllowedForEntity = _authorizationResolver.GetRolesForEntity(entityName); + Dictionary> rolesAllowedForFields = new(); + foreach (string column in tableDefinition.Columns.Keys) + { + IEnumerable roles = _authorizationResolver.GetRolesForField(entityName, field: column, actionName: ActionType.READ ); + if (!rolesAllowedForFields.TryAdd(key: column, value: roles)) + { + throw new DataGatewayException( + message: "Column already processed for building ObjectTypeDefinition authorization definition.", + statusCode: System.Net.HttpStatusCode.InternalServerError, + subStatusCode: DataGatewayException.SubStatusCodes.ErrorInInitialization + ); + } + } + + // The roles allowed for Fields are the roles allowed to READ the fields, so any role that has a read definition for the field. + ObjectTypeDefinitionNode node = SchemaConverter.FromTableDefinition( + entityName, + tableDefinition, + entity, + entities, + rolesAllowedForEntity, + rolesAllowedForFields + ); - ObjectTypeDefinitionNode node = SchemaConverter.FromTableDefinition(entityName, tableDefinition, entity, entities, rolesAllowedForEntity); InputTypeBuilder.GenerateInputTypesForObjectType(node, inputObjects); objectTypes.Add(entityName, node); } From e45b0679cc84fda635e0130601c1b525f513a5f0 Mon Sep 17 00:00:00 2001 From: Sean Leonard Date: Fri, 8 Jul 2022 17:11:52 -0700 Subject: [PATCH 04/18] Basic test to check AuthZ Field for authorize Directive on objectTypeDefinition which is created for READ. --- .../Sql/SchemaConverterTests.cs | 186 ++++++++++++++++-- 1 file changed, 167 insertions(+), 19 deletions(-) diff --git a/DataGateway.Service.Tests/GraphQLBuilder/Sql/SchemaConverterTests.cs b/DataGateway.Service.Tests/GraphQLBuilder/Sql/SchemaConverterTests.cs index 638aba991a..b433d1aa80 100644 --- a/DataGateway.Service.Tests/GraphQLBuilder/Sql/SchemaConverterTests.cs +++ b/DataGateway.Service.Tests/GraphQLBuilder/Sql/SchemaConverterTests.cs @@ -2,6 +2,7 @@ using System.Collections.Generic; using System.Linq; using Azure.DataGateway.Config; +using Azure.DataGateway.Service.GraphQLBuilder; using Azure.DataGateway.Service.GraphQLBuilder.Directives; using Azure.DataGateway.Service.GraphQLBuilder.Queries; using Azure.DataGateway.Service.GraphQLBuilder.Sql; @@ -65,7 +66,14 @@ public void ColumnNameBecomesFieldName(string columnName, string expected) SystemType = typeof(string) }); - ObjectTypeDefinitionNode od = SchemaConverter.FromTableDefinition("table", table, GenerateEmptyEntity(), new()); + ObjectTypeDefinitionNode od = SchemaConverter.FromTableDefinition( + "table", + table, + GenerateEmptyEntity(), + new(), + rolesAllowedForEntity: GetRolesAllowedForEntity(), + rolesAllowedForFields: GetFieldToRolesMap(columnName: table.Columns.First().Key) + ); Assert.AreEqual(expected, od.Fields[0].Name.Value); } @@ -82,10 +90,18 @@ public void PrimaryKeyColumnHasAppropriateDirective() }); table.PrimaryKey.Add(columnName); - ObjectTypeDefinitionNode od = SchemaConverter.FromTableDefinition("table", table, GenerateEmptyEntity(), new()); + ObjectTypeDefinitionNode od = SchemaConverter.FromTableDefinition( + "table", + table, + GenerateEmptyEntity(), + new(), + rolesAllowedForEntity: GetRolesAllowedForEntity(), + rolesAllowedForFields: GetFieldToRolesMap() + ); FieldDefinitionNode field = od.Fields.First(f => f.Name.Value == columnName); - Assert.AreEqual(1, field.Directives.Count); + // Authorization directive implicitly created so actual count should be 1 + {expected number of directives}. + Assert.AreEqual(2, field.Directives.Count); Assert.AreEqual(PrimaryKeyDirectiveType.DirectiveName, field.Directives[0].Name.Value); } @@ -113,14 +129,23 @@ public void MultiplePrimaryKeysAllMappedWithDirectives() [TestMethod] public void MultipleColumnsAllMapped() { + int customColumnCount = 5; + TableDefinition table = new(); - for (int i = 0; i < 5; i++) + for (int i = 0; i < customColumnCount; i++) { table.Columns.Add($"col{i}", new ColumnDefinition { SystemType = typeof(string) }); } - ObjectTypeDefinitionNode od = SchemaConverter.FromTableDefinition("table", table, GenerateEmptyEntity(), new()); + ObjectTypeDefinitionNode od = SchemaConverter.FromTableDefinition( + "table", + table, + GenerateEmptyEntity(), + new(), + rolesAllowedForEntity: GetRolesAllowedForEntity(), + rolesAllowedForFields: GetFieldToRolesMap(additionalColumns: customColumnCount) + ); Assert.AreEqual(table.Columns.Count, od.Fields.Count); } @@ -147,7 +172,14 @@ public void SystemTypeMapsToCorrectGraphQLType(Type systemType, string graphQLTy SystemType = systemType }); - ObjectTypeDefinitionNode od = SchemaConverter.FromTableDefinition("table", table, GenerateEmptyEntity(), new()); + ObjectTypeDefinitionNode od = SchemaConverter.FromTableDefinition( + "table", + table, + GenerateEmptyEntity(), + new(), + rolesAllowedForEntity: GetRolesAllowedForEntity(), + rolesAllowedForFields: GetFieldToRolesMap() + ); FieldDefinitionNode field = od.Fields.First(f => f.Name.Value == columnName); Assert.AreEqual(graphQLType, field.Type.NamedType().Name.Value); @@ -165,7 +197,14 @@ public void NullColumnBecomesNullField() IsNullable = true, }); - ObjectTypeDefinitionNode od = SchemaConverter.FromTableDefinition("table", table, GenerateEmptyEntity(), new()); + ObjectTypeDefinitionNode od = SchemaConverter.FromTableDefinition( + "table", + table, + GenerateEmptyEntity(), + new(), + rolesAllowedForEntity: GetRolesAllowedForEntity(), + rolesAllowedForFields: GetFieldToRolesMap() + ); FieldDefinitionNode field = od.Fields.First(f => f.Name.Value == columnName); Assert.IsFalse(field.Type.IsNonNullType()); @@ -183,7 +222,14 @@ public void NonNullColumnBecomesNonNullField() IsNullable = false, }); - ObjectTypeDefinitionNode od = SchemaConverter.FromTableDefinition("table", table, GenerateEmptyEntity(), new()); + ObjectTypeDefinitionNode od = SchemaConverter.FromTableDefinition( + "table", + table, + GenerateEmptyEntity(), + new(), + rolesAllowedForEntity: GetRolesAllowedForEntity(), + rolesAllowedForFields: GetFieldToRolesMap() + ); FieldDefinitionNode field = od.Fields.First(f => f.Name.Value == columnName); Assert.IsTrue(field.Type.IsNonNullType()); @@ -236,7 +282,13 @@ public void WhenForeignKeyDefinedButNoRelationship_GraphQLWontModelIt() ObjectTypeDefinitionNode od = SchemaConverter.FromTableDefinition( - SOURCE_ENTITY, table, configEntity, new() { { TARGET_ENTITY, relationshipEntity } }); + SOURCE_ENTITY, + table, + configEntity, + new() { { TARGET_ENTITY, relationshipEntity } }, + rolesAllowedForEntity: GetRolesAllowedForEntity(), + rolesAllowedForFields: GetFieldToRolesMap() + ); Assert.AreEqual(2, od.Fields.Count); } @@ -255,6 +307,11 @@ public void SingularNamingRulesDeterminedByRuntimeConfig(string entityName, stri Assert.AreEqual(expected, od.Name.Value); } + /// + /// When schema ObjectTypeDefinition is created, + /// it's fields contain the authorize directive + /// when rolesAllowedForFields() returns a role list + /// [TestMethod] public void AutoGeneratedFieldHasDirectiveIndicatingSuch() { @@ -268,9 +325,16 @@ public void AutoGeneratedFieldHasDirectiveIndicatingSuch() }); Entity configEntity = GenerateEmptyEntity(); - ObjectTypeDefinitionNode od = SchemaConverter.FromTableDefinition("entity", table, configEntity, new()); - - Assert.IsTrue(od.Fields[0].Directives.Any(d => d.Name.Value == AutoGeneratedDirectiveType.DirectiveName)); + ObjectTypeDefinitionNode od = SchemaConverter.FromTableDefinition( + "entity", + table, + configEntity, + new(), + rolesAllowedForEntity: GetRolesAllowedForEntity(), + rolesAllowedForFields: GetFieldToRolesMap() + ); + + Assert.IsTrue(od.Fields[0].Directives.Any(d => d.Name.Value == GraphQLUtils.AUTHORIZE_DIRECTIVE)); } [DataTestMethod] @@ -310,15 +374,96 @@ public void DefaultValueGetsSetOnDirective(object defaultValue, string fieldName }); Entity configEntity = GenerateEmptyEntity(); - ObjectTypeDefinitionNode od = SchemaConverter.FromTableDefinition("entity", table, configEntity, new()); - - Assert.AreEqual(1, od.Fields[0].Directives.Count); + ObjectTypeDefinitionNode od = SchemaConverter.FromTableDefinition( + "entity", + table, + configEntity, + new(), + rolesAllowedForEntity: GetRolesAllowedForEntity(), + rolesAllowedForFields: GetFieldToRolesMap() + ); + + // @authorize directive is implicitly created so the count to compare to is 2 + Assert.AreEqual(2, od.Fields[0].Directives.Count); DirectiveNode directive = od.Fields[0].Directives[0]; ObjectValueNode value = (ObjectValueNode)directive.Arguments[0].Value; Assert.AreEqual(fieldName, value.Fields[0].Name.Value); Assert.AreEqual(kind, value.Fields[0].Value.Kind); } + [TestMethod] + public void AutoGeneratedFieldHasAuthorizeDirective() + { + TableDefinition table = new(); + string columnName = "columnName"; + table.Columns.Add(columnName, new ColumnDefinition + { + SystemType = typeof(string), + IsNullable = false, + IsAutoGenerated = true, + }); + + Entity configEntity = GenerateEmptyEntity(); + ObjectTypeDefinitionNode od = SchemaConverter.FromTableDefinition( + "entity", + table, + configEntity, + new(), + rolesAllowedForEntity: GetRolesAllowedForEntity(), + rolesAllowedForFields: GetFieldToRolesMap() + ); + + Assert.IsTrue(od.Fields[0].Directives.Any(d => d.Name.Value == GraphQLUtils.AUTHORIZE_DIRECTIVE)); + } + + /// + /// Mocks a list of roles for the Schema Converter Tests + /// + /// Collection of roles + private static IEnumerable GetRolesAllowedForEntity() + { + return new List() + { + "anonymous", + "authenticated" + }; + } + + /// + /// Mocks FieldToRoleMap for Schema Converter Tests + /// For tests that require arbitrary number of columns, + /// the additionalColumns argument should be used to define + /// the desired number of columns. + /// Default is 0 and results in the two constant fields created that are + /// relevant to most tests in SchemaConverterTests. + /// + /// number of columns/fields to generate + /// custom column name + /// Key Value Map of Field to Roles + private static IDictionary> GetFieldToRolesMap(int additionalColumns = 0, string columnName = "") + { + Dictionary> fieldToRolesMap = new(); + + if (additionalColumns != 0) + { + for (int columnNumber = 0; columnNumber < additionalColumns; columnNumber++) + { + fieldToRolesMap.Add("col" + columnNumber.ToString(), GetRolesAllowedForEntity()); + } + } + else if (!string.IsNullOrEmpty(columnName)) + { + fieldToRolesMap.Add(columnName, GetRolesAllowedForEntity()); + } + else + { + fieldToRolesMap.Add(COLUMN_NAME, GetRolesAllowedForEntity()); + fieldToRolesMap.Add(REF_COLNAME, GetRolesAllowedForEntity()); + } + + return fieldToRolesMap; + } + private static Entity GenerateEmptyEntity() { return new Entity("dbo.entity", Rest: null, GraphQL: null, Array.Empty(), Relationships: new(), Mappings: new()); @@ -346,10 +491,13 @@ private static ObjectTypeDefinitionNode GenerateObjectWithRelationship(Cardinali Entity configEntity = GenerateEmptyEntity() with { Relationships = relationships }; Entity relationshipEntity = GenerateEmptyEntity(); - return SchemaConverter.FromTableDefinition - (SOURCE_ENTITY, - table, - configEntity, new() { { TARGET_ENTITY, relationshipEntity } }); + return SchemaConverter.FromTableDefinition( + SOURCE_ENTITY, + table, + configEntity, new() { { TARGET_ENTITY, relationshipEntity } }, + rolesAllowedForEntity: GetRolesAllowedForEntity(), + rolesAllowedForFields: GetFieldToRolesMap() + ); } private static TableDefinition GenerateTableWithForeignKeyDefinition() From 4ed517af6ea4b70dda9d7ef4169372f0760fdd97 Mon Sep 17 00:00:00 2001 From: Sean Leonard Date: Sun, 10 Jul 2022 08:17:56 -0700 Subject: [PATCH 05/18] Remove whitespace. --- DataGateway.Service/Services/GraphQLService.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/DataGateway.Service/Services/GraphQLService.cs b/DataGateway.Service/Services/GraphQLService.cs index 0272466f5f..e2c618c9ca 100644 --- a/DataGateway.Service/Services/GraphQLService.cs +++ b/DataGateway.Service/Services/GraphQLService.cs @@ -195,7 +195,7 @@ DatabaseType.postgresql or Dictionary> rolesAllowedForFields = new(); foreach (string column in tableDefinition.Columns.Keys) { - IEnumerable roles = _authorizationResolver.GetRolesForField(entityName, field: column, actionName: ActionType.READ ); + IEnumerable roles = _authorizationResolver.GetRolesForField(entityName, field: column, actionName: ActionType.READ); if (!rolesAllowedForFields.TryAdd(key: column, value: roles)) { throw new DataGatewayException( From 54659550daee613c57ec09e2c6ff94f57ca14710 Mon Sep 17 00:00:00 2001 From: Sean Leonard Date: Sun, 10 Jul 2022 08:24:56 -0700 Subject: [PATCH 06/18] add using --- DataGateway.Service/Authorization/AuthorizationResolver.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/DataGateway.Service/Authorization/AuthorizationResolver.cs b/DataGateway.Service/Authorization/AuthorizationResolver.cs index 584839799a..088bd76122 100644 --- a/DataGateway.Service/Authorization/AuthorizationResolver.cs +++ b/DataGateway.Service/Authorization/AuthorizationResolver.cs @@ -9,6 +9,7 @@ using Azure.DataGateway.Config; using Azure.DataGateway.Service.Configurations; using Azure.DataGateway.Service.Exceptions; +using Azure.DataGateway.Service.Models; using Azure.DataGateway.Service.Services; using Microsoft.AspNetCore.Http; using Microsoft.Extensions.Primitives; From a50e6d4621c9b68254b409dea77ec95ddb2bf6ef Mon Sep 17 00:00:00 2001 From: Sean Leonard Date: Tue, 12 Jul 2022 09:00:02 -0700 Subject: [PATCH 07/18] `AutoGeneratedFieldHasAuthorizeDirective()` test method comment and enhancement to cover all fields on objecttypedefinitionnode. --- .../GraphQLBuilder/Sql/SchemaConverterTests.cs | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/DataGateway.Service.Tests/GraphQLBuilder/Sql/SchemaConverterTests.cs b/DataGateway.Service.Tests/GraphQLBuilder/Sql/SchemaConverterTests.cs index b433d1aa80..3c35c904b0 100644 --- a/DataGateway.Service.Tests/GraphQLBuilder/Sql/SchemaConverterTests.cs +++ b/DataGateway.Service.Tests/GraphQLBuilder/Sql/SchemaConverterTests.cs @@ -391,6 +391,15 @@ public void DefaultValueGetsSetOnDirective(object defaultValue, string fieldName Assert.AreEqual(kind, value.Fields[0].Value.Kind); } + /// + /// Tests that each field on an ObjectTypeDefinition includes + /// the expected @authorize directive. + /// Given a set of roles provided by GetFieldToRolesMap() + /// id - {anonymous, authenticated, role3, roleN} + /// title - {authenticated} + /// field3 - {role3, roleN} + /// Adds directive @authorize(roles=[role1, role2, role3]). + /// [TestMethod] public void AutoGeneratedFieldHasAuthorizeDirective() { @@ -413,7 +422,8 @@ public void AutoGeneratedFieldHasAuthorizeDirective() rolesAllowedForFields: GetFieldToRolesMap() ); - Assert.IsTrue(od.Fields[0].Directives.Any(d => d.Name.Value == GraphQLUtils.AUTHORIZE_DIRECTIVE)); + // Ensures all fields added have the appropriate @authorize directive. + Assert.IsTrue(od.Fields.All(field => field.Directives.Any(d => d.Name.Value == GraphQLUtils.AUTHORIZE_DIRECTIVE))); } /// From 15c0983de4066318a2171ca3c8d71c1f8617a45c Mon Sep 17 00:00:00 2001 From: Sean Leonard Date: Tue, 12 Jul 2022 09:00:16 -0700 Subject: [PATCH 08/18] Fixed typo. --- DataGateway.Service/Authorization/AuthorizationResolver.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/DataGateway.Service/Authorization/AuthorizationResolver.cs b/DataGateway.Service/Authorization/AuthorizationResolver.cs index 088bd76122..a1cc890681 100644 --- a/DataGateway.Service/Authorization/AuthorizationResolver.cs +++ b/DataGateway.Service/Authorization/AuthorizationResolver.cs @@ -232,7 +232,7 @@ public void SetEntityPermissionMap(RuntimeConfig? runtimeConfig) ActionMetadata actionToColumn = new(); IEnumerable allTableColumns = ResolveTableDefinitionColumns(entityName); - // Implicitly, all table collumns are 'allowed' when an actiontype is a string. + // Implicitly, all table columns are 'allowed' when an actiontype is a string. // Since no granular field permissions exist for this action within the current role. if (actionElement.ValueKind is JsonValueKind.String) { From fc914dbd72b7cd030e859b6bd474a0e94cbc6df7 Mon Sep 17 00:00:00 2001 From: Sean Leonard Date: Tue, 12 Jul 2022 09:15:10 -0700 Subject: [PATCH 09/18] Remove default null parameter in SchemaConverter.FromTableDefinition() for rolesAllowedForEntity and rolesAllowedForFields and fixed the downstream tests that that assumption broke. --- .../Sql/SchemaConverter.cs | 4 +-- .../Sql/SchemaConverterTests.cs | 27 ++++++++++++++++--- 2 files changed, 26 insertions(+), 5 deletions(-) diff --git a/DataGateway.Service.GraphQLBuilder/Sql/SchemaConverter.cs b/DataGateway.Service.GraphQLBuilder/Sql/SchemaConverter.cs index dac637986a..2a4e7d251b 100644 --- a/DataGateway.Service.GraphQLBuilder/Sql/SchemaConverter.cs +++ b/DataGateway.Service.GraphQLBuilder/Sql/SchemaConverter.cs @@ -26,8 +26,8 @@ public static ObjectTypeDefinitionNode FromTableDefinition( TableDefinition tableDefinition, [NotNull] Entity configEntity, Dictionary entities, - IEnumerable? rolesAllowedForEntity = null, - IDictionary>? rolesAllowedForFields = null) + IEnumerable? rolesAllowedForEntity, + IDictionary>? rolesAllowedForFields) { Dictionary fields = new(); List objectTypeDirectives = new(); diff --git a/DataGateway.Service.Tests/GraphQLBuilder/Sql/SchemaConverterTests.cs b/DataGateway.Service.Tests/GraphQLBuilder/Sql/SchemaConverterTests.cs index 3c35c904b0..f1c10ff8da 100644 --- a/DataGateway.Service.Tests/GraphQLBuilder/Sql/SchemaConverterTests.cs +++ b/DataGateway.Service.Tests/GraphQLBuilder/Sql/SchemaConverterTests.cs @@ -41,7 +41,14 @@ public void EntityNameBecomesObjectName(string entityName, string expected) { TableDefinition table = new(); - ObjectTypeDefinitionNode od = SchemaConverter.FromTableDefinition(entityName, table, GenerateEmptyEntity(), new()); + ObjectTypeDefinitionNode od = SchemaConverter.FromTableDefinition( + entityName, + table, + GenerateEmptyEntity(), + new(), + rolesAllowedForEntity: GetRolesAllowedForEntity(), + rolesAllowedForFields: GetFieldToRolesMap() + ); Assert.AreEqual(expected, od.Name.Value); } @@ -117,7 +124,14 @@ public void MultiplePrimaryKeysAllMappedWithDirectives() table.PrimaryKey.Add(columnName); } - ObjectTypeDefinitionNode od = SchemaConverter.FromTableDefinition("table", table, GenerateEmptyEntity(), new()); + ObjectTypeDefinitionNode od = SchemaConverter.FromTableDefinition( + "table", + table, + GenerateEmptyEntity(), + new(), + rolesAllowedForEntity: GetRolesAllowedForEntity(), + rolesAllowedForFields: GetFieldToRolesMap() + ); foreach (FieldDefinitionNode field in od.Fields) { @@ -302,7 +316,14 @@ public void SingularNamingRulesDeterminedByRuntimeConfig(string entityName, stri TableDefinition table = new(); Entity configEntity = GenerateEmptyEntity() with { GraphQL = new SingularPlural(singular, null) }; - ObjectTypeDefinitionNode od = SchemaConverter.FromTableDefinition(entityName, table, configEntity, new()); + ObjectTypeDefinitionNode od = SchemaConverter.FromTableDefinition( + entityName, + table, + configEntity, + new(), + rolesAllowedForEntity: GetRolesAllowedForEntity(), + rolesAllowedForFields: GetFieldToRolesMap() + ); Assert.AreEqual(expected, od.Name.Value); } From 0df8d3f70fe39057d4ef8fd23ad2cf24c735863d Mon Sep 17 00:00:00 2001 From: Sean Leonard Date: Tue, 12 Jul 2022 09:33:52 -0700 Subject: [PATCH 10/18] Add anonymous check when adding fields. and check role count in order to add field and directive. --- .../GraphQLUtils.cs | 1 + .../Sql/SchemaConverter.cs | 33 ++++++++++++------- 2 files changed, 22 insertions(+), 12 deletions(-) diff --git a/DataGateway.Service.GraphQLBuilder/GraphQLUtils.cs b/DataGateway.Service.GraphQLBuilder/GraphQLUtils.cs index 1c17876cec..4136c7dff8 100644 --- a/DataGateway.Service.GraphQLBuilder/GraphQLUtils.cs +++ b/DataGateway.Service.GraphQLBuilder/GraphQLUtils.cs @@ -15,6 +15,7 @@ public static class GraphQLUtils public const string AUTHORIZE_DIRECTIVE_ARGUMENT_ROLES = "roles"; public const string OBJECT_TYPE_MUTATION = "mutation"; public const string OBJECT_TYPE_QUERY = "query"; + public const string SYSTEM_ROLE_ANONYMOUS = "anonymous"; public static bool IsModelType(ObjectTypeDefinitionNode objectTypeDefinitionNode) { diff --git a/DataGateway.Service.GraphQLBuilder/Sql/SchemaConverter.cs b/DataGateway.Service.GraphQLBuilder/Sql/SchemaConverter.cs index 2a4e7d251b..401ec6a299 100644 --- a/DataGateway.Service.GraphQLBuilder/Sql/SchemaConverter.cs +++ b/DataGateway.Service.GraphQLBuilder/Sql/SchemaConverter.cs @@ -75,18 +75,27 @@ public static ObjectTypeDefinitionNode FromTableDefinition( // Consequently, the field is only added to schema if this conditional evaluates to TRUE. if (rolesAllowedForFields is not null && rolesAllowedForFields.TryGetValue(key: columnName, out IEnumerable? roles)) { - directives.Add(GraphQLUtils.CreateAuthorizationDirective(roles)); - - NamedTypeNode fieldType = new(GetGraphQLTypeForColumnType(column.SystemType)); - FieldDefinitionNode field = new( - location: null, - new(FormatNameForField(columnName)), - description: null, - new List(), - column.IsNullable ? fieldType : new NonNullTypeNode(fieldType), - directives); - - fields.Add(columnName, field); + // Roles will not be null here if TryGetValue evaluates to true, so here we check if there are any roles to process. + if (roles.Count() > 0) + { + // Add field to object definition but do not add @authorize directive + // if anonymous is defined for field since authentication is not required. + if (!roles.Contains(GraphQLUtils.SYSTEM_ROLE_ANONYMOUS)) + { + directives.Add(GraphQLUtils.CreateAuthorizationDirective(roles)); + } + + NamedTypeNode fieldType = new(GetGraphQLTypeForColumnType(column.SystemType)); + FieldDefinitionNode field = new( + location: null, + new(FormatNameForField(columnName)), + description: null, + new List(), + column.IsNullable ? fieldType : new NonNullTypeNode(fieldType), + directives); + + fields.Add(columnName, field); + } } } From 46c165e41a4b42e374eca658eee195ab3e5e0435 Mon Sep 17 00:00:00 2001 From: Sean Leonard Date: Tue, 12 Jul 2022 09:35:47 -0700 Subject: [PATCH 11/18] Remove anonymous default role since this results in authorize directive not being added. --- .../GraphQLBuilder/Sql/SchemaConverterTests.cs | 1 - 1 file changed, 1 deletion(-) diff --git a/DataGateway.Service.Tests/GraphQLBuilder/Sql/SchemaConverterTests.cs b/DataGateway.Service.Tests/GraphQLBuilder/Sql/SchemaConverterTests.cs index f1c10ff8da..fc21e60113 100644 --- a/DataGateway.Service.Tests/GraphQLBuilder/Sql/SchemaConverterTests.cs +++ b/DataGateway.Service.Tests/GraphQLBuilder/Sql/SchemaConverterTests.cs @@ -455,7 +455,6 @@ private static IEnumerable GetRolesAllowedForEntity() { return new List() { - "anonymous", "authenticated" }; } From 7a7df69868a8417c908e97d6772e8eee37125179 Mon Sep 17 00:00:00 2001 From: Sean Leonard Date: Tue, 12 Jul 2022 09:44:42 -0700 Subject: [PATCH 12/18] Add method comment which did not originally have one. Adding since I worked in this method. Small effort to add comment coverage on existing code. --- DataGateway.Service/Services/GraphQLService.cs | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/DataGateway.Service/Services/GraphQLService.cs b/DataGateway.Service/Services/GraphQLService.cs index e2c618c9ca..dd01f819a7 100644 --- a/DataGateway.Service/Services/GraphQLService.cs +++ b/DataGateway.Service/Services/GraphQLService.cs @@ -174,6 +174,13 @@ DatabaseType.postgresql or Parse(root, inputTypes); } + /// + /// Generates the ObjectTypeDefinitionNodes and InputObjectTypeDefinitionNodes as part of GraphQL Schema generation + /// with the provided entities listed in the runtime configuration. + /// + /// Key/Value Collection {entityName -> Entity object} + /// Root GraphQLSchema DocumentNode and inputNodes to be processed by downstream schema generation helpers. + /// private (DocumentNode, Dictionary) GenerateSqlGraphQLObjects(Dictionary entities) { Dictionary objectTypes = new(); From d0513c9fce6d9b39d989d26ebf8a2c17895d13c1 Mon Sep 17 00:00:00 2001 From: Sean Leonard Date: Wed, 13 Jul 2022 10:12:07 -0700 Subject: [PATCH 13/18] Change param of `rolesAllowedForEntity` to not be nullable, since it would be not null and Count() would be 0-n. Also added param comments. --- .../Sql/SchemaConverter.cs | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/DataGateway.Service.GraphQLBuilder/Sql/SchemaConverter.cs b/DataGateway.Service.GraphQLBuilder/Sql/SchemaConverter.cs index 401ec6a299..0897799417 100644 --- a/DataGateway.Service.GraphQLBuilder/Sql/SchemaConverter.cs +++ b/DataGateway.Service.GraphQLBuilder/Sql/SchemaConverter.cs @@ -20,14 +20,18 @@ public static class SchemaConverter /// Name of the entity in the runtime config to generate the GraphQL object type for. /// SQL table definition information. /// Runtime config information for the table. + /// Key/Value Collection mapping entity name to the entity object, + /// currently used to lookup relationship metadata. + /// Roles to add to authorize directive at the object level (applies to query/read ops). + /// Roles to add to authorize directive at the field level (applies to mutations). /// A GraphQL object type to be provided to a Hot Chocolate GraphQL document. public static ObjectTypeDefinitionNode FromTableDefinition( string entityName, TableDefinition tableDefinition, [NotNull] Entity configEntity, Dictionary entities, - IEnumerable? rolesAllowedForEntity, - IDictionary>? rolesAllowedForFields) + IEnumerable rolesAllowedForEntity, + IDictionary> rolesAllowedForFields) { Dictionary fields = new(); List objectTypeDirectives = new(); @@ -73,7 +77,7 @@ public static ObjectTypeDefinitionNode FromTableDefinition( // If no roles are allowed for the field, we should not include it in the schema. // Consequently, the field is only added to schema if this conditional evaluates to TRUE. - if (rolesAllowedForFields is not null && rolesAllowedForFields.TryGetValue(key: columnName, out IEnumerable? roles)) + if (rolesAllowedForFields.TryGetValue(key: columnName, out IEnumerable? roles)) { // Roles will not be null here if TryGetValue evaluates to true, so here we check if there are any roles to process. if (roles.Count() > 0) @@ -142,7 +146,7 @@ public static ObjectTypeDefinitionNode FromTableDefinition( // Any roles passed in will be added to the authorize directive for this ObjectType // taking the form: @authorize(roles: [“role1”, ..., “roleN”]) - if (rolesAllowedForEntity is not null) + if (rolesAllowedForEntity.Count() >= 1) { objectTypeDirectives.Add(GraphQLUtils.CreateAuthorizationDirective(rolesAllowedForEntity)); } From 5f950a2b2287a2c6a3aaae361d9047b453501507 Mon Sep 17 00:00:00 2001 From: Sean Leonard Date: Thu, 14 Jul 2022 13:06:34 -0700 Subject: [PATCH 14/18] Fixed typo'd directive in irrelevant test. Add test for anonymous role resulting in no authorize directive on field. --- .../Sql/SchemaConverterTests.cs | 58 ++++++++++++++++--- 1 file changed, 51 insertions(+), 7 deletions(-) diff --git a/DataGateway.Service.Tests/GraphQLBuilder/Sql/SchemaConverterTests.cs b/DataGateway.Service.Tests/GraphQLBuilder/Sql/SchemaConverterTests.cs index fc21e60113..b235ad06fb 100644 --- a/DataGateway.Service.Tests/GraphQLBuilder/Sql/SchemaConverterTests.cs +++ b/DataGateway.Service.Tests/GraphQLBuilder/Sql/SchemaConverterTests.cs @@ -330,7 +330,7 @@ public void SingularNamingRulesDeterminedByRuntimeConfig(string entityName, stri /// /// When schema ObjectTypeDefinition is created, - /// it's fields contain the authorize directive + /// it's fields contain the @authorize directive /// when rolesAllowedForFields() returns a role list /// [TestMethod] @@ -355,7 +355,7 @@ public void AutoGeneratedFieldHasDirectiveIndicatingSuch() rolesAllowedForFields: GetFieldToRolesMap() ); - Assert.IsTrue(od.Fields[0].Directives.Any(d => d.Name.Value == GraphQLUtils.AUTHORIZE_DIRECTIVE)); + Assert.IsTrue(od.Fields[0].Directives.Any(d => d.Name.Value == AutoGeneratedDirectiveType.DirectiveName)); } [DataTestMethod] @@ -447,6 +447,45 @@ public void AutoGeneratedFieldHasAuthorizeDirective() Assert.IsTrue(od.Fields.All(field => field.Directives.Any(d => d.Name.Value == GraphQLUtils.AUTHORIZE_DIRECTIVE))); } + /// + /// Tests that each field on an ObjectTypeDefinition does not include + /// an @authorize directive. + /// Given a set of roles provided by GetFieldToRolesMap() + /// id - {anonymous, authenticated, role3, roleN} + /// title - {authenticated} + /// field3 - {role3, roleN} + /// Adds directive @authorize(roles=[role1, role2, role3]). + /// + [DataRow(new string[] { "anonymous" }, DisplayName = "Anonymous is only role for field")] + [DataRow(new string[] { "anonymous" , "Role1" }, DisplayName = "Anonymous is 1 of many roles for field")] + [DataRow(new string[] { "authenticated", "anonymous" }, DisplayName = "Anonymous and authenticated are present and randomly ordered, anonymous wins.")] + [DataTestMethod] + public void FieldWithAnonymousAccessHasNoAuthorizeDirective(string[] rolesForField) + { + TableDefinition table = new(); + string columnName = "columnName"; + table.Columns.Add(columnName, new ColumnDefinition + { + SystemType = typeof(string), + IsNullable = false, + IsAutoGenerated = true, + }); + + Entity configEntity = GenerateEmptyEntity(); + ObjectTypeDefinitionNode od = SchemaConverter.FromTableDefinition( + "entity", + table, + configEntity, + new(), + rolesAllowedForEntity: GetRolesAllowedForEntity(), + rolesAllowedForFields: GetFieldToRolesMap(rolesForField: rolesForField) + ); + + // Ensures no field has the @authorize directive. + Assert.IsFalse(od.Fields.All(field => field.Directives.Any(d => d.Name.Value == GraphQLUtils.AUTHORIZE_DIRECTIVE)), + message: "@authorize directive must not be present for field with anonymous access permissions."); + } + /// /// Mocks a list of roles for the Schema Converter Tests /// @@ -470,25 +509,30 @@ private static IEnumerable GetRolesAllowedForEntity() /// number of columns/fields to generate /// custom column name /// Key Value Map of Field to Roles - private static IDictionary> GetFieldToRolesMap(int additionalColumns = 0, string columnName = "") + private static IDictionary> GetFieldToRolesMap(int additionalColumns = 0, string columnName = "", IEnumerable rolesForField = null) { Dictionary> fieldToRolesMap = new(); + if (rolesForField is null) + { + rolesForField = GetRolesAllowedForEntity(); + } + if (additionalColumns != 0) { for (int columnNumber = 0; columnNumber < additionalColumns; columnNumber++) { - fieldToRolesMap.Add("col" + columnNumber.ToString(), GetRolesAllowedForEntity()); + fieldToRolesMap.Add("col" + columnNumber.ToString(), rolesForField); } } else if (!string.IsNullOrEmpty(columnName)) { - fieldToRolesMap.Add(columnName, GetRolesAllowedForEntity()); + fieldToRolesMap.Add(columnName, rolesForField); } else { - fieldToRolesMap.Add(COLUMN_NAME, GetRolesAllowedForEntity()); - fieldToRolesMap.Add(REF_COLNAME, GetRolesAllowedForEntity()); + fieldToRolesMap.Add(COLUMN_NAME, rolesForField); + fieldToRolesMap.Add(REF_COLNAME, rolesForField); } return fieldToRolesMap; From 29704b08494a96095dbc76f33e53087ce41b2e76 Mon Sep 17 00:00:00 2001 From: Sean Leonard Date: Thu, 14 Jul 2022 13:08:29 -0700 Subject: [PATCH 15/18] fixed typo --- .../GraphQLBuilder/Sql/SchemaConverterTests.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/DataGateway.Service.Tests/GraphQLBuilder/Sql/SchemaConverterTests.cs b/DataGateway.Service.Tests/GraphQLBuilder/Sql/SchemaConverterTests.cs index b235ad06fb..0a02b179f3 100644 --- a/DataGateway.Service.Tests/GraphQLBuilder/Sql/SchemaConverterTests.cs +++ b/DataGateway.Service.Tests/GraphQLBuilder/Sql/SchemaConverterTests.cs @@ -330,7 +330,7 @@ public void SingularNamingRulesDeterminedByRuntimeConfig(string entityName, stri /// /// When schema ObjectTypeDefinition is created, - /// it's fields contain the @authorize directive + /// its fields contain the @authorize directive /// when rolesAllowedForFields() returns a role list /// [TestMethod] From b41d5fba9d360c2f65ed905e9952808ca21d15b3 Mon Sep 17 00:00:00 2001 From: Sean Leonard Date: Thu, 14 Jul 2022 13:14:27 -0700 Subject: [PATCH 16/18] Added datarow tests for checking presence of authorize directive. --- .../GraphQLBuilder/Sql/SchemaConverterTests.cs | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/DataGateway.Service.Tests/GraphQLBuilder/Sql/SchemaConverterTests.cs b/DataGateway.Service.Tests/GraphQLBuilder/Sql/SchemaConverterTests.cs index 0a02b179f3..5341d5eb3f 100644 --- a/DataGateway.Service.Tests/GraphQLBuilder/Sql/SchemaConverterTests.cs +++ b/DataGateway.Service.Tests/GraphQLBuilder/Sql/SchemaConverterTests.cs @@ -415,14 +415,17 @@ public void DefaultValueGetsSetOnDirective(object defaultValue, string fieldName /// /// Tests that each field on an ObjectTypeDefinition includes /// the expected @authorize directive. - /// Given a set of roles provided by GetFieldToRolesMap() + /// Given a the anonymous role provided by GetFieldToRolesMap() /// id - {anonymous, authenticated, role3, roleN} /// title - {authenticated} /// field3 - {role3, roleN} /// Adds directive @authorize(roles=[role1, role2, role3]). /// - [TestMethod] - public void AutoGeneratedFieldHasAuthorizeDirective() + [DataRow(new string[] { "authenticated" }, DisplayName = "One non-anonymous system role (authenticated) defined for field, @authorize directive added.")] + [DataRow(new string[] { "authenticated", "role1" }, DisplayName = "Mixed role types (non-anonymous) roles defined for field, @authorize directive added.")] + [DataRow(new string[] { "role1", "role2", "role3" }, DisplayName = "Multiple non-system roles defined for field, @authorize directive added.")] + [DataTestMethod] + public void AutoGeneratedFieldHasAuthorizeDirective(string[] rolesForField) { TableDefinition table = new(); string columnName = "columnName"; @@ -440,7 +443,7 @@ public void AutoGeneratedFieldHasAuthorizeDirective() configEntity, new(), rolesAllowedForEntity: GetRolesAllowedForEntity(), - rolesAllowedForFields: GetFieldToRolesMap() + rolesAllowedForFields: GetFieldToRolesMap(rolesForField: rolesForField) ); // Ensures all fields added have the appropriate @authorize directive. From ad56828f67b445e03a8ca78c056af5c12fea93ab Mon Sep 17 00:00:00 2001 From: Sean Leonard Date: Thu, 14 Jul 2022 13:20:44 -0700 Subject: [PATCH 17/18] consistency with attribute and spacing --- .../GraphQLBuilder/Sql/SchemaConverterTests.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/DataGateway.Service.Tests/GraphQLBuilder/Sql/SchemaConverterTests.cs b/DataGateway.Service.Tests/GraphQLBuilder/Sql/SchemaConverterTests.cs index 5341d5eb3f..3e3e2c0c06 100644 --- a/DataGateway.Service.Tests/GraphQLBuilder/Sql/SchemaConverterTests.cs +++ b/DataGateway.Service.Tests/GraphQLBuilder/Sql/SchemaConverterTests.cs @@ -421,10 +421,10 @@ public void DefaultValueGetsSetOnDirective(object defaultValue, string fieldName /// field3 - {role3, roleN} /// Adds directive @authorize(roles=[role1, role2, role3]). /// + [DataTestMethod] [DataRow(new string[] { "authenticated" }, DisplayName = "One non-anonymous system role (authenticated) defined for field, @authorize directive added.")] [DataRow(new string[] { "authenticated", "role1" }, DisplayName = "Mixed role types (non-anonymous) roles defined for field, @authorize directive added.")] [DataRow(new string[] { "role1", "role2", "role3" }, DisplayName = "Multiple non-system roles defined for field, @authorize directive added.")] - [DataTestMethod] public void AutoGeneratedFieldHasAuthorizeDirective(string[] rolesForField) { TableDefinition table = new(); @@ -459,10 +459,10 @@ public void AutoGeneratedFieldHasAuthorizeDirective(string[] rolesForField) /// field3 - {role3, roleN} /// Adds directive @authorize(roles=[role1, role2, role3]). /// + [DataTestMethod] [DataRow(new string[] { "anonymous" }, DisplayName = "Anonymous is only role for field")] [DataRow(new string[] { "anonymous" , "Role1" }, DisplayName = "Anonymous is 1 of many roles for field")] [DataRow(new string[] { "authenticated", "anonymous" }, DisplayName = "Anonymous and authenticated are present and randomly ordered, anonymous wins.")] - [DataTestMethod] public void FieldWithAnonymousAccessHasNoAuthorizeDirective(string[] rolesForField) { TableDefinition table = new(); From 24cd581e33a1258028708f3390569567a0cbba4f Mon Sep 17 00:00:00 2001 From: Sean Leonard Date: Thu, 14 Jul 2022 13:24:00 -0700 Subject: [PATCH 18/18] Extra space --- .../GraphQLBuilder/Sql/SchemaConverterTests.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/DataGateway.Service.Tests/GraphQLBuilder/Sql/SchemaConverterTests.cs b/DataGateway.Service.Tests/GraphQLBuilder/Sql/SchemaConverterTests.cs index 3e3e2c0c06..550bd596eb 100644 --- a/DataGateway.Service.Tests/GraphQLBuilder/Sql/SchemaConverterTests.cs +++ b/DataGateway.Service.Tests/GraphQLBuilder/Sql/SchemaConverterTests.cs @@ -461,7 +461,7 @@ public void AutoGeneratedFieldHasAuthorizeDirective(string[] rolesForField) /// [DataTestMethod] [DataRow(new string[] { "anonymous" }, DisplayName = "Anonymous is only role for field")] - [DataRow(new string[] { "anonymous" , "Role1" }, DisplayName = "Anonymous is 1 of many roles for field")] + [DataRow(new string[] { "anonymous", "Role1" }, DisplayName = "Anonymous is 1 of many roles for field")] [DataRow(new string[] { "authenticated", "anonymous" }, DisplayName = "Anonymous and authenticated are present and randomly ordered, anonymous wins.")] public void FieldWithAnonymousAccessHasNoAuthorizeDirective(string[] rolesForField) {