Skip to content
New issue

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

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

Already on GitHub? Sign in to your account

Authorize Directive Serialization Issues #485

Merged
merged 9 commits into from
Jan 15, 2019
38 changes: 37 additions & 1 deletion src/Core/Core.Tests/Execution/Errors/ErrorBehaviourTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ namespace HotChocolate.Execution
{
public class ErrorBehaviourTests
{
[Fact]
[Fact]
public async Task SyntaxError()
{
// arrange
Expand Down Expand Up @@ -231,6 +231,42 @@ public async Task Property_Return_UnexpectedErrorWithPath()
result.Snapshot();
}

[Fact]
public async Task RootTypeNotDefined()
{
// arrange
string query = "mutation { foo }";

var schema = Schema.Create(
"type Query { foo: String }",
c => c.Use(next => context => Task.CompletedTask));
IQueryExecuter executer = schema.MakeExecutable();

// act
IExecutionResult result = await executer.ExecuteAsync(query);

// assert
result.Snapshot();
}

[Fact]
public async Task RootFieldNotDefined()
{
// arrange
string query = "mutation { foo }";

var schema = Schema.Create(
"type Mutation { bar: String }",
c => c.Use(next => context => Task.CompletedTask));
IQueryExecuter executer = schema.MakeExecutable();

// act
IExecutionResult result = await executer.ExecuteAsync(query);

// assert
result.Snapshot();
}

private async Task<IExecutionResult> ExecuteQuery(
string query,
Action errorHandled)
Expand Down
15 changes: 15 additions & 0 deletions src/Core/Core.Tests/__snapshots__/RootFieldNotDefined.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
{
"Data": {},
"Extensions": {},
"Errors": [
{
"message": "The field `foo` does not exist on the type `Mutation`.",
"locations": [
{
"line": 1,
"column": 12
}
]
}
]
}
9 changes: 9 additions & 0 deletions src/Core/Core.Tests/__snapshots__/RootTypeNotDefined.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
{
"Data": {},
"Extensions": {},
"Errors": [
{
"message": "The specified root type `Mutation` does not exist."
}
]
}
23 changes: 17 additions & 6 deletions src/Core/Core/Validation/QueryVisitor.cs
Original file line number Diff line number Diff line change
Expand Up @@ -81,9 +81,17 @@ protected virtual void VisitOperationDefinition(
ImmutableStack<ISyntaxNode> path)
{
IType operationType = Schema.GetOperationType(operation.Operation);
ImmutableStack<ISyntaxNode> newPath = path.Push(operation);
VisitSelectionSet(operation.SelectionSet, operationType, newPath);
VisitDirectives(operation.Directives, newPath);
if (operationType != null)
{
ImmutableStack<ISyntaxNode> newPath = path.Push(operation);

VisitSelectionSet(
operation.SelectionSet,
operationType,
newPath);

VisitDirectives(operation.Directives, newPath);
}
_visitedFragments.Clear();
}

Expand All @@ -107,7 +115,8 @@ protected virtual void VisitSelectionSet(
}
else if (selection is InlineFragmentNode inlineFragment)
{
VisitInlineFragmentInternal(inlineFragment, type, newpath);
VisitInlineFragmentInternal(
inlineFragment, type, newpath);
}
}
}
Expand Down Expand Up @@ -252,7 +261,8 @@ protected bool ContainsFragment(string fragmentName)
return _fragments.ContainsKey(fragmentName);
}

protected bool IsFragmentVisited(FragmentDefinitionNode fragmentDefinition)
protected bool IsFragmentVisited(
FragmentDefinitionNode fragmentDefinition)
{
if (fragmentDefinition == null)
{
Expand All @@ -262,7 +272,8 @@ protected bool IsFragmentVisited(FragmentDefinitionNode fragmentDefinition)
return _visitedFragments.Contains(fragmentDefinition);
}

protected bool MarkFragmentVisited(FragmentDefinitionNode fragmentDefinition)
protected bool MarkFragmentVisited(
FragmentDefinitionNode fragmentDefinition)
{
if (fragmentDefinition == null)
{
Expand Down
95 changes: 92 additions & 3 deletions src/Server/AspNetCore.Authorization/AuthorizeDirective.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.Serialization;
using HotChocolate.Language;

#if !ASPNETCLASSIC
using System.Collections.ObjectModel;
Expand All @@ -13,17 +15,54 @@ namespace HotChocolate.AspNetCore.Authorization
#endif
{
public class AuthorizeDirective
: ISerializable
{
public AuthorizeDirective()
{
Roles = Array.Empty<string>();
}

#if ASPNETCLASSIC
public AuthorizeDirective(IEnumerable<string> roles)
{
if (roles == null)
{
throw new ArgumentNullException(nameof(roles));
}

Roles = roles.ToArray();
}

public AuthorizeDirective(
SerializationInfo info,
StreamingContext context)
{
var node = info.GetValue(
nameof(DirectiveNode),
typeof(DirectiveNode))
as DirectiveNode;

if (node == null)
{
Roles = (string[])info.GetValue(
nameof(Roles),
typeof(string[]));
}
else
{
ArgumentNode rolesArgument = node.Arguments
.FirstOrDefault(t => t.Name.Value == "roles");

Roles = (rolesArgument != null
&& rolesArgument.Value is ListValueNode lv)
? lv.Items.OfType<StringValueNode>()
.Select(t => t.Value?.Trim())
.Where(s => !string.IsNullOrEmpty(s))
.ToArray()
: Array.Empty<string>();
}
}

#else
public AuthorizeDirective(string policy)
: this(policy, null)
Expand All @@ -39,14 +78,53 @@ public AuthorizeDirective(string policy, IEnumerable<string> roles)
roles?.ToList().AsReadOnly();

if (string.IsNullOrEmpty(policy)
&& (readOnlyRoles == null || readOnlyRoles.Any()))
&& (readOnlyRoles == null || readOnlyRoles.Count > 0))
{
throw new ArgumentException(
"Either policy or roles has to be set.");
}

Policy = policy;
Roles = readOnlyRoles;
Roles = (IReadOnlyCollection<string>)readOnlyRoles
?? Array.Empty<string>();
}

public AuthorizeDirective(
SerializationInfo info,
StreamingContext context)
{
var node = info.GetValue(
nameof(DirectiveNode),
typeof(DirectiveNode))
as DirectiveNode;

if (node == null)
{
Policy = info.GetString(nameof(Policy));
Roles = (string[])info.GetValue(
nameof(Roles),
typeof(string[]));
}
else
{
ArgumentNode policyArgument = node.Arguments
.FirstOrDefault(t => t.Name.Value == "policy");
ArgumentNode rolesArgument = node.Arguments
.FirstOrDefault(t => t.Name.Value == "roles");

Policy = (policyArgument != null
&& policyArgument.Value is StringValueNode sv)
? sv.Value
: null;

Roles = (rolesArgument != null
&& rolesArgument.Value is ListValueNode lv)
? lv.Items.OfType<StringValueNode>()
.Select(t => t.Value?.Trim())
.Where(s => !string.IsNullOrEmpty(s))
.ToArray()
: Array.Empty<string>();
}
}

/// <summary>
Expand All @@ -59,5 +137,16 @@ public AuthorizeDirective(string policy, IEnumerable<string> roles)
/// Gets or sets of roles that are allowed to access the resource.
/// </summary>
public IReadOnlyCollection<string> Roles { get; }


public void GetObjectData(
SerializationInfo info,
StreamingContext context)
{
#if !ASPNETCLASSIC
info.AddValue(nameof(Policy), Policy);
#endif
info.AddValue(nameof(Roles), Roles?.ToArray());
}
}
}
Loading