Skip to content

Commit

Permalink
Authorize Directive Serialization Issues (#485)
Browse files Browse the repository at this point in the history
  • Loading branch information
michaelstaib authored Jan 15, 2019
1 parent ff56fb0 commit eff0f49
Show file tree
Hide file tree
Showing 22 changed files with 914 additions and 44 deletions.
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

0 comments on commit eff0f49

Please sign in to comment.