diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 0c1844c..7c0d0f3 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -11,12 +11,12 @@ jobs: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v3 - name: Setup .NET - uses: actions/setup-dotnet@v1 + uses: actions/setup-dotnet@v3 with: - dotnet-version: '6.0.x' + dotnet-version: '7.0.x' - name: Run build & test run: ./build.sh Test diff --git a/.github/workflows/nuget-push.yml b/.github/workflows/nuget-push.yml index 3ee84ee..ebe1d47 100644 --- a/.github/workflows/nuget-push.yml +++ b/.github/workflows/nuget-push.yml @@ -8,12 +8,12 @@ jobs: steps: - name: Checkout code - uses: actions/checkout@v2 + uses: actions/checkout@v3 - name: Setup .NET Core - uses: actions/setup-dotnet@v1 + uses: actions/setup-dotnet@v3 with: - dotnet-version: '6.0.x' + dotnet-version: '7.0.x' - name: Run Nuget Pack run: ./build.sh NugetPack diff --git a/Package.Build.props b/Package.Build.props index 3e4cfc6..9c59b8c 100644 --- a/Package.Build.props +++ b/Package.Build.props @@ -1,6 +1,6 @@ - 0.7.0-alpha + 0.8.0-alpha Hawxy true Apache-2.0 diff --git a/README.md b/README.md index 9c4ec01..29e53f6 100644 --- a/README.md +++ b/README.md @@ -30,12 +30,14 @@ Ensure you have a Store ID, Client ID, and Client Secret ready from [How to get 1. Add your `StoreId`, `ClientId` and `ClientSecret` to your application configuration, ideally via the [dotnet secrets manager](https://docs.microsoft.com/en-us/aspnet/core/security/app-secrets?view=aspnetcore-6.0&tabs=windows#enable-secret-storage). 2. Add the following code to your ASP.NET Core services configuration: ```cs -builder.Services.AddOpenFga(x => +builder.Services.AddOpenFgaClient(x => { x.WithAuth0FgaDefaults(builder.Configuration["Auth0Fga:ClientId"], builder.Configuration["Auth0Fga:ClientSecret"]); x.StoreId = builder.Configuration["Auth0Fga:StoreId"]; }); + +builder.Services.AddOpenFgaMiddleware(); ``` The `WithAuth0FgaDefaults` extension will configure the relevant OpenFGA client settings to work with Auth0 FGA's US environment. @@ -47,17 +49,19 @@ OpenFGA configuration is very similar to the [SDK Setup Guide](https://openfga.d 1. Add the FGA `ApiScheme`, `ApiHost` & `StoreId` to your application configuration. 2. Add the following code to your ASP.NET Core configuration: ```cs -builder.Services.AddOpenFga(x => +builder.Services.AddOpenFgaClient(x => { x.ApiScheme = builder.Configuration["Fga:ApiScheme"]; x.ApiHost = builder.Configuration["Fga:ApiHost"]; x.StoreId = builder.Configuration["Fga:StoreId"]; }); + +builder.Services.AddOpenFgaMiddleware(); ``` ### Authorization Policy Setup -We'll need to setup our authorization middleware like so: +We'll need to setup our authorization policy like so: ```cs builder.Services.AddAuthorization(options => @@ -105,12 +109,11 @@ If you want to use the built-in attributes, you need to configure how the user's The example below uses the Name, which should be suitable for most people (given the claim is mapped correctly). ```cs -builder.Services.AddOpenFga(x => -{ - //... -}, config => +builder.Services.AddOpenFgaMiddleware(config => { config.UserIdentityResolver = principal => principal.Identity!.Name!; + //If you're using DSL v1.1 it requires the user type to be included + //config.UserIdentityResolver = principal => $"user:{principal.Identity!.Name!}"; }); ``` diff --git a/build/_build.csproj b/build/_build.csproj index 6184984..a748288 100644 --- a/build/_build.csproj +++ b/build/_build.csproj @@ -11,7 +11,7 @@ - + diff --git a/samples/Fga.Example.AspNetCore/Fga.Example.AspNetCore.csproj b/samples/Fga.Example.AspNetCore/Fga.Example.AspNetCore.csproj index d567c00..d9ba989 100644 --- a/samples/Fga.Example.AspNetCore/Fga.Example.AspNetCore.csproj +++ b/samples/Fga.Example.AspNetCore/Fga.Example.AspNetCore.csproj @@ -8,7 +8,7 @@ - + diff --git a/samples/Fga.Example.AspNetCore/Program.cs b/samples/Fga.Example.AspNetCore/Program.cs index 71a3181..7097335 100644 --- a/samples/Fga.Example.AspNetCore/Program.cs +++ b/samples/Fga.Example.AspNetCore/Program.cs @@ -30,25 +30,27 @@ // Auth0 FGA -builder.Services.AddOpenFga(clientConfig => +builder.Services.AddOpenFgaClient(clientConfig => { - clientConfig.WithAuth0FgaDefaults(builder.Configuration["Auth0Fga:ClientId"], builder.Configuration["Auth0Fga:ClientSecret"]); + clientConfig.WithAuth0FgaDefaults(builder.Configuration["Auth0Fga:ClientId"], + builder.Configuration["Auth0Fga:ClientSecret"]); clientConfig.StoreId = builder.Configuration["Auth0Fga:StoreId"]; - -}, middlewareConfig => -{ - middlewareConfig.UserIdentityResolver = principal => principal.Identity!.Name!; -}); +}); // OpenFGA -/*builder.Services.AddOpenFga(x => +/*builder.Services.AddOpenFgaClient(x => { x.ApiScheme = builder.Configuration["Fga:ApiScheme"]; x.ApiHost = builder.Configuration["Fga:ApiHost"]; x.StoreId = builder.Configuration["Fga:StoreId"]; });*/ +builder.Services.AddOpenFgaMiddleware(middlewareConfig => +{ + middlewareConfig.UserIdentityResolver = principal => principal.Identity!.Name!; +}); + builder.Services.AddAuthorization(options => { options.AddPolicy(FgaAuthorizationDefaults.PolicyKey, diff --git a/src/Fga.Net.AspNetCore/Authorization/Attributes/FgaPropertyObjectAttribute.cs b/src/Fga.Net.AspNetCore/Authorization/Attributes/FgaPropertyObjectAttribute.cs index 48525a8..e101a55 100644 --- a/src/Fga.Net.AspNetCore/Authorization/Attributes/FgaPropertyObjectAttribute.cs +++ b/src/Fga.Net.AspNetCore/Authorization/Attributes/FgaPropertyObjectAttribute.cs @@ -35,14 +35,14 @@ public override ValueTask GetRelation(HttpContext context) } /// - public override ValueTask GetObject(HttpContext context) + public override async ValueTask GetObject(HttpContext context) { context.Request.EnableBuffering(); - using var document = JsonDocument.Parse(context.Request.Body); + using var document = await JsonDocument.ParseAsync(context.Request.Body, cancellationToken: context.RequestAborted); if (document.RootElement.TryGetProperty(_property, out var element)) { context.Request.Body.Position = 0; - return ValueTask.FromResult(FormatObject(_type,element.GetString()!)); + return FormatObject(_type,element.GetString()!); } throw new FgaMiddlewareException($"Unable to resolve JSON property {_property}"); diff --git a/src/Fga.Net.AspNetCore/Authorization/FineGrainedAuthorizationHandler.cs b/src/Fga.Net.AspNetCore/Authorization/FineGrainedAuthorizationHandler.cs index a521d9c..8c87798 100644 --- a/src/Fga.Net.AspNetCore/Authorization/FineGrainedAuthorizationHandler.cs +++ b/src/Fga.Net.AspNetCore/Authorization/FineGrainedAuthorizationHandler.cs @@ -81,7 +81,7 @@ protected override async Task HandleRequirementAsync(AuthorizationHandlerContext } }, httpContext.RequestAborted); - if (!result.Allowed) + if (result.Allowed is false) { _logger.CheckFailureDebug(user, relation, @object); return; diff --git a/src/Fga.Net.AspNetCore/Controllers/FgaControllerBase.cs b/src/Fga.Net.AspNetCore/Controllers/FgaControllerBase.cs index acacfcd..d83f0d1 100644 --- a/src/Fga.Net.AspNetCore/Controllers/FgaControllerBase.cs +++ b/src/Fga.Net.AspNetCore/Controllers/FgaControllerBase.cs @@ -56,6 +56,6 @@ public async Task Check(string user, string relation, string @object, Canc Object = @object } }, ct); - return checkRes.Allowed; + return checkRes.Allowed.HasValue && checkRes.Allowed.Value; } } \ No newline at end of file diff --git a/src/Fga.Net.AspNetCore/Fga.Net.AspNetCore.csproj b/src/Fga.Net.AspNetCore/Fga.Net.AspNetCore.csproj index e4ea761..a5c6ab9 100644 --- a/src/Fga.Net.AspNetCore/Fga.Net.AspNetCore.csproj +++ b/src/Fga.Net.AspNetCore/Fga.Net.AspNetCore.csproj @@ -1,7 +1,7 @@  - net6.0 + net6.0;net7.0 enable enable diff --git a/src/Fga.Net.AspNetCore/ServiceCollectionExtensions.cs b/src/Fga.Net.AspNetCore/ServiceCollectionExtensions.cs index 1f591b2..5d34904 100644 --- a/src/Fga.Net.AspNetCore/ServiceCollectionExtensions.cs +++ b/src/Fga.Net.AspNetCore/ServiceCollectionExtensions.cs @@ -36,6 +36,7 @@ public static class ServiceCollectionExtensions /// The delegate for the that will be used to configure the /// The delegate for the that will be used to configure the underlying middleware /// The service collection + [Obsolete("Replace with AddOpenFgaClient & AddOpenFgaMiddleware")] public static IServiceCollection AddOpenFga(this IServiceCollection collection, Action clientConfig, Action? middlewareConfig = null) { ArgumentNullException.ThrowIfNull(clientConfig); @@ -47,6 +48,21 @@ public static IServiceCollection AddOpenFga(this IServiceCollection collection, return collection; } + /// + /// Adds and configures an + /// + /// The service collection + /// The delegate for the that will be used to configure the underlying middleware + /// The service collection + public static IServiceCollection AddOpenFgaMiddleware(this IServiceCollection collection, Action? middlewareConfig = null) + { + if (middlewareConfig != null) + collection.Configure(middlewareConfig); + collection.AddScoped(); + collection.AddScoped(); + return collection; + } + /// /// Adds a to the given policy. /// diff --git a/src/Fga.Net/Fga.Net.DependencyInjection.csproj b/src/Fga.Net/Fga.Net.DependencyInjection.csproj index f30ee6d..6ec6df4 100644 --- a/src/Fga.Net/Fga.Net.DependencyInjection.csproj +++ b/src/Fga.Net/Fga.Net.DependencyInjection.csproj @@ -1,6 +1,6 @@  - net6.0 + net6.0;net7.0 enable enable @@ -14,7 +14,7 @@ - + diff --git a/tests/Fga.Net.Tests/Client/EndpointTests.cs b/tests/Fga.Net.Tests/Client/EndpointTests.cs index da1cce7..c5f224a 100644 --- a/tests/Fga.Net.Tests/Client/EndpointTests.cs +++ b/tests/Fga.Net.Tests/Client/EndpointTests.cs @@ -1,4 +1,5 @@ -using System.Linq; +using System.Collections.Generic; +using System.Linq; using System.Threading.Tasks; using Alba; using Microsoft.Extensions.DependencyInjection; @@ -34,7 +35,7 @@ private async Task GetEndpoints_Return_200() var modelResponse = await client.ReadAuthorizationModel(modelId); Assert.NotNull(modelResponse); - Assert.NotNull(modelResponse.AuthorizationModel.Id); + Assert.NotNull(modelResponse.AuthorizationModel?.Id); var assertions = await client.ReadAssertions(modelId); @@ -42,7 +43,7 @@ private async Task GetEndpoints_Return_200() Assert.True(assertions.Assertions?.Count > 0); var assertion = assertions.Assertions!.First().TupleKey; - Assert.NotEmpty(assertion.Object!); + Assert.NotEmpty(assertion!.Object!); Assert.NotEmpty(assertion.Relation!); Assert.NotEmpty(assertion.User!); @@ -58,6 +59,7 @@ private async Task GetEndpoints_Return_200() var watch = await client.ReadChanges(); Assert.NotNull(watch); + } } diff --git a/tests/Fga.Net.Tests/Fga.Net.Tests.csproj b/tests/Fga.Net.Tests/Fga.Net.Tests.csproj index 6eded38..970d49e 100644 --- a/tests/Fga.Net.Tests/Fga.Net.Tests.csproj +++ b/tests/Fga.Net.Tests/Fga.Net.Tests.csproj @@ -8,9 +8,9 @@ - - - + + + diff --git a/tests/Fga.Net.Tests/Unit/ExtensionTests.cs b/tests/Fga.Net.Tests/Unit/ExtensionTests.cs index 4b41fa3..5a4260a 100644 --- a/tests/Fga.Net.Tests/Unit/ExtensionTests.cs +++ b/tests/Fga.Net.Tests/Unit/ExtensionTests.cs @@ -35,11 +35,13 @@ public void AspNetCoreServiceExtensions_RegisterCorrectly() { var collection = new ServiceCollection(); - collection.AddOpenFga(x => + collection.AddOpenFgaClient(x => { x.StoreId = Guid.NewGuid().ToString(); x.WithAuth0FgaDefaults(Guid.NewGuid().ToString(), Guid.NewGuid().ToString()); - }, x => + }); + + collection.AddOpenFgaMiddleware(x => { x.UserIdentityResolver = principal => principal.Identity!.Name!; });