in src/Core/Configurations/RuntimeConfigValidator.cs [748:844]
public void ValidatePermissionsInConfig(RuntimeConfig runtimeConfig)
{
foreach ((string entityName, Entity entity) in runtimeConfig.Entities)
{
HashSet<EntityActionOperation> totalSupportedOperationsFromAllRoles = new();
foreach (EntityPermission permissionSetting in entity.Permissions)
{
string roleName = permissionSetting.Role;
EntityAction[] actions = permissionSetting.Actions;
List<EntityActionOperation> operationsList = new();
foreach (EntityAction action in actions)
{
try
{
if (action is null)
{
throw GetInvalidActionException(entityName, roleName, actionName: "null");
}
// Evaluate actionOp as the current operation to be validated.
EntityActionOperation actionOp = action.Action;
// If we have reached this point, it means that we don't have any invalid
// data type in actions. However we need to ensure that the actionOp is valid.
if (!IsValidPermissionAction(actionOp, entity, entityName))
{
throw GetInvalidActionException(entityName, roleName, actionOp.ToString());
}
if (action.Fields is not null)
{
// Check if the IncludeSet/ExcludeSet contain wildcard. If they contain wildcard, we make sure that they
// don't contain any other field. If they do, we HandleOrRecordException(an appropriate exception.
if (action.Fields.Include is not null && action.Fields.Include.Contains(AuthorizationResolver.WILDCARD)
&& action.Fields.Include.Count > 1 ||
action.Fields.Exclude.Contains(AuthorizationResolver.WILDCARD) && action.Fields.Exclude.Count > 1)
{
// See if included or excluded columns contain wildcard and another field.
// If that's the case with both of them, we specify 'included' in error.
string misconfiguredColumnSet = action.Fields.Exclude.Contains(AuthorizationResolver.WILDCARD)
&& action.Fields.Exclude.Count > 1 ? "excluded" : "included";
string actionName = actionOp is EntityActionOperation.All ? "*" : actionOp.ToString();
HandleOrRecordException(new DataApiBuilderException(
message: $"No other field can be present with wildcard in the {misconfiguredColumnSet} set for:" +
$" entity:{entityName}, role:{permissionSetting.Role}, action:{actionName}",
statusCode: HttpStatusCode.ServiceUnavailable,
subStatusCode: DataApiBuilderException.SubStatusCodes.ConfigValidationError));
}
if (action.Policy is not null && action.Policy.Database is not null)
{
// validate that all the fields mentioned in database policy are accessible to user.
AreFieldsAccessible(action.Policy.Database,
action.Fields.Include, action.Fields.Exclude);
// validate that all the claimTypes in the policy are well formed.
ValidateClaimsInPolicy(action.Policy.Database, runtimeConfig);
}
}
DataSource entityDataSource = runtimeConfig.GetDataSourceFromEntityName(entityName);
if (entityDataSource.DatabaseType is not DatabaseType.MSSQL && !IsValidDatabasePolicyForAction(action))
{
throw new DataApiBuilderException(
message: $"The Create action does not support defining a database policy." +
$" entity:{entityName}, role:{permissionSetting.Role}, action:{action.Action}",
statusCode: HttpStatusCode.ServiceUnavailable,
subStatusCode: DataApiBuilderException.SubStatusCodes.ConfigValidationError);
}
operationsList.Add(actionOp);
totalSupportedOperationsFromAllRoles.Add(actionOp);
}
catch (Exception e)
{
HandleOrRecordException(e);
}
}
// Stored procedures only support the "execute" operation.
if (entity.Source.Type is EntitySourceType.StoredProcedure)
{
if ((operationsList.Count > 1)
|| (operationsList.Count is 1 && !IsValidPermissionAction(operationsList[0], entity, entityName)))
{
HandleOrRecordException(new DataApiBuilderException(
message: $"Invalid Operations for Entity: {entityName}. " +
$"Stored procedures can only be configured with the 'execute' operation.",
statusCode: HttpStatusCode.ServiceUnavailable,
subStatusCode: DataApiBuilderException.SubStatusCodes.ConfigValidationError));
}
}
}
}
}