Skip to content

Commit

Permalink
Iteration 2
Browse files Browse the repository at this point in the history
  • Loading branch information
queil committed Jun 13, 2022
1 parent a40dd0e commit b79d5d4
Show file tree
Hide file tree
Showing 8 changed files with 127 additions and 89 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,11 @@
<Nullable>enable</Nullable>
</PropertyGroup>

<ItemGroup>
<PackageReference Include="Microsoft.Extensions.Configuration.Abstractions" Version="3.1.4" />
<PackageReference Include="Microsoft.Extensions.Http" Version="3.1.4" />
</ItemGroup>

<ItemGroup>
<ProjectReference Include="..\..\..\Core\src\Types\HotChocolate.Types.csproj" />
<ProjectReference Include="..\AspNetCore.Authorization\HotChocolate.AspNetCore.Authorization.csproj" />
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
using HotChocolate.AspNetCore.Authorization;
using HotChocolate.Execution.Configuration;
using Microsoft.Extensions.Configuration;

namespace Microsoft.Extensions.DependencyInjection;

/// <summary>
/// Provides extension methods for the GraphQL builder.
/// </summary>
public static class HotChocolateAuthorizeRequestExecutorBuilder
{
/// <summary>
/// Adds OPA authorization handler.
/// </summary>
/// <param name="builder">
/// The <see cref="IRequestExecutorBuilder"/>.
/// </param>
/// <param name="configure">
/// Configure <see cref="OpaOptions"/>.
/// </param>
/// <returns>
/// Returns the <see cref="IRequestExecutorBuilder"/> for chaining in more configurations.
/// </returns>
public static IRequestExecutorBuilder AddOpaAuthorizationHandler(
this IRequestExecutorBuilder builder, Action<IConfiguration, OpaOptions>? configure = null)
{
builder.AddAuthorization();
builder.AddAuthorizationHandler<OpaAuthorizationHandler>();
builder.Services.AddSingleton<IOpaDecision, OpaDecision>();
builder.Services.AddHttpClient<OpaService>((f, c) =>
{
OpaOptions? options = f.GetRequiredService<OpaOptions>();
c.BaseAddress = options.BaseAddress;
c.Timeout = options.ConnectionTimeout;
});
builder.Services.AddSingleton(f =>
{
var options = new OpaOptions();
configure?.Invoke(f.GetRequiredService<IConfiguration>(), options);
return options;
});
return builder;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -18,30 +18,13 @@ public sealed class QueryRequest
public Input Input { get; set; } = Input.Empty;
}

internal static class OpaHttpExtensions
public sealed class OriginalRequest
{
internal static HttpContent ToJsonContent(this QueryRequest request, JsonSerializerOptions options)
{
#if NET6_0
return JsonContent.Create(request, options: options);
#else
var body = JsonSerializer.Serialize(request, options);
return new StringContent(body, System.Text.Encoding.UTF8, "application/json");
#endif
}

internal static async Task<QueryResponse?> QueryResponseFromJsonAsync(this HttpContent content, JsonSerializerOptions options, CancellationToken token)
{
#if NET6_0
return await content.ReadFromJsonAsync<QueryResponse>(options, token);
#else
return await JsonSerializer.DeserializeAsync<QueryResponse>(await content.ReadAsStreamAsync(), options, token);
#endif
}
}

public sealed class Input
{
public OriginalRequest Request { get; set; } = new();
public static readonly Input Empty = new();
}

Expand All @@ -52,32 +35,11 @@ public interface IOpaService

public sealed class OpaOptions
{
public Uri BaseAddress { get; set; } = new Uri("http://127.0.0.1:8181");
public TimeSpan ConnectionTimeout { get; set; } = TimeSpan.FromMilliseconds(250);
public JsonSerializerOptions JsonSerializerOptions { get; set; } = new JsonSerializerOptions();
}

public sealed class OpaService : IOpaService
{
private readonly HttpClient _httpClient;
private readonly OpaOptions _options;

public OpaService(HttpClient httpClient, OpaOptions options)
{
_httpClient = httpClient ?? throw new ArgumentNullException(nameof(httpClient));
_options = options ?? throw new ArgumentNullException(nameof(options));
}

public async Task<QueryResponse?> QueryAsync(string policyPath, QueryRequest request, CancellationToken token)
{
if (policyPath is null) throw new ArgumentNullException(nameof(policyPath));
if (request is null) throw new ArgumentNullException(nameof(request));

HttpResponseMessage? response = await _httpClient.PostAsync(policyPath, request.ToJsonContent(_options.JsonSerializerOptions), token);
response.EnsureSuccessStatusCode();
return await response.Content.QueryResponseFromJsonAsync(_options.JsonSerializerOptions, token);
}
}


public interface IOpaDecision
{
AuthorizeResult Map(QueryResponse? response);
Expand Down Expand Up @@ -113,8 +75,9 @@ public async ValueTask<AuthorizeResult> AuthorizeAsync(
IMiddlewareContext context,
AuthorizeDirective directive)
{
IOpaService? opaService = context.Services.GetRequiredService<IOpaService>();
OpaService? opaService = context.Services.GetRequiredService<OpaService>();
IOpaDecision? opaDecision = context.Services.GetRequiredService<IOpaDecision>();

var request = new QueryRequest { Input = new Input()};
QueryResponse? response = await opaService.QueryAsync(directive.Policy ?? string.Empty, request, context.RequestAborted);
return opaDecision.Map(response);
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
#if NET6_0
using System.Net.Http.Json;
#endif
using System.Text.Json;

namespace HotChocolate.AspNetCore.Authorization;

internal static class OpaJsonExtensions
{
internal static HttpContent ToJsonContent(this QueryRequest request, JsonSerializerOptions options)
{
#if NET6_0
return JsonContent.Create(request, options: options);
#else
var body = JsonSerializer.Serialize(request, options);
return new StringContent(body, System.Text.Encoding.UTF8, "application/json");
#endif
}

internal static async Task<QueryResponse?> QueryResponseFromJsonAsync(this HttpContent content, JsonSerializerOptions options, CancellationToken token)
{
#if NET6_0
return await content.ReadFromJsonAsync<QueryResponse>(options, token);
#else
return await JsonSerializer.DeserializeAsync<QueryResponse>(await content.ReadAsStreamAsync(), options, token);
#endif
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
namespace HotChocolate.AspNetCore.Authorization;

public sealed class OpaService : IOpaService
{
private readonly HttpClient _httpClient;
private readonly OpaOptions _options;

public OpaService(HttpClient httpClient, OpaOptions options)
{
_httpClient = httpClient ?? throw new ArgumentNullException(nameof(httpClient));
_options = options ?? throw new ArgumentNullException(nameof(options));
}

public async Task<QueryResponse?> QueryAsync(string policyPath, QueryRequest request, CancellationToken token)
{
if (policyPath is null) throw new ArgumentNullException(nameof(policyPath));
if (request is null) throw new ArgumentNullException(nameof(request));

HttpResponseMessage? response = await _httpClient.PostAsync(policyPath, request.ToJsonContent(_options.JsonSerializerOptions), token);
response.EnsureSuccessStatusCode();
return await response.Content.QueryResponseFromJsonAsync(_options.JsonSerializerOptions, token);
}
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
using System;
using System.Collections;
using System.Collections.Generic;
using System.Text.Json;
using HotChocolate.Execution.Configuration;
using Microsoft.Extensions.DependencyInjection;

Expand Down Expand Up @@ -34,7 +35,13 @@ public class Query
private Action<IRequestExecutorBuilder> CreateSchema() =>
builder => builder
.AddQueryType<Query>()
.AddAuthorization();
.AddAuthorization()
.AddOpaAuthorizationHandler((c, o) =>
{
o.BaseAddress = new Uri("http://127.0.0.1:8181");
o.ConnectionTimeout = TimeSpan.FromSeconds(10);
o.JsonSerializerOptions = new JsonSerializerOptions();
});

public IEnumerator<object[]> GetEnumerator()
{
Expand Down

This file was deleted.

Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
using System;
using System.Collections;
using System.Collections.Generic;
using System.Text.Json;
using HotChocolate.Execution.Configuration;
using HotChocolate.Resolvers;
using Microsoft.Extensions.DependencyInjection;
Expand Down Expand Up @@ -33,12 +34,24 @@ private Action<IRequestExecutorBuilder> CreateSchema() =>
sb => sb
.AddDocumentFromString(SchemaCode)
.AddAuthorization()
.AddOpaAuthorizationHandler((c, o) =>
{
o.BaseAddress = new Uri("http://127.0.0.1:8181");
o.ConnectionTimeout = TimeSpan.FromSeconds(10);
o.JsonSerializerOptions = new JsonSerializerOptions();
})
.UseField(_schemaMiddleware);

private Action<IRequestExecutorBuilder> CreateSchemaWithBuilder() =>
sb => sb
.AddDocumentFromString(SchemaCode)
.AddAuthorization()
.AddOpaAuthorizationHandler((c, o) =>
{
o.BaseAddress = new Uri("http://127.0.0.1:8181");
o.ConnectionTimeout = TimeSpan.FromSeconds(10);
o.JsonSerializerOptions = new JsonSerializerOptions();
})
.UseField(_schemaMiddleware);

public IEnumerator<object[]> GetEnumerator()
Expand Down

0 comments on commit b79d5d4

Please sign in to comment.