Skip to content

Commit

Permalink
v0.5 - Update Auth0.Fga, add debug logging. (#3)
Browse files Browse the repository at this point in the history
* Package updates

* Enable middleware tests again, add debug logging to middleware.
  • Loading branch information
Hawxy authored Jun 18, 2022
1 parent 6313dce commit 3a85f03
Show file tree
Hide file tree
Showing 18 changed files with 122 additions and 38 deletions.
2 changes: 1 addition & 1 deletion Package.Build.props
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
<Project>
<PropertyGroup>
<Version>0.4.0-alpha</Version>
<Version>0.5.0-alpha</Version>
<Authors>Hawxy</Authors>
<PackageRequireLicenseAcceptance>true</PackageRequireLicenseAcceptance>
<PackageLicenseExpression>Apache-2.0</PackageLicenseExpression>
Expand Down
7 changes: 7 additions & 0 deletions build.cmd
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
:; set -eo pipefail
:; SCRIPT_DIR=$(cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd)
:; ${SCRIPT_DIR}/build.sh "$@"
:; exit $?

@ECHO OFF
powershell -ExecutionPolicy ByPass -NoProfile -File "%~dp0build.ps1" %*
2 changes: 1 addition & 1 deletion build.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ else {
$env:DOTNET_EXE = "$DotNetDirectory\dotnet.exe"
}

Write-Output "Microsoft (R) .NET Core SDK version $(& $env:DOTNET_EXE --version)"
Write-Output "Microsoft (R) .NET SDK version $(& $env:DOTNET_EXE --version)"

ExecSafe { & $env:DOTNET_EXE build $BuildProjectFile /nodeReuse:false /p:UseSharedCompilation=false -nologo -clp:NoSummary --verbosity quiet }
ExecSafe { & $env:DOTNET_EXE run --project $BuildProjectFile --no-build -- $BuildArguments }
2 changes: 1 addition & 1 deletion build.sh
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ else
export DOTNET_EXE="$DOTNET_DIRECTORY/dotnet"
fi

echo "Microsoft (R) .NET Core SDK version $("$DOTNET_EXE" --version)"
echo "Microsoft (R) .NET SDK version $("$DOTNET_EXE" --version)"

"$DOTNET_EXE" build "$BUILD_PROJECT_FILE" /nodeReuse:false /p:UseSharedCompilation=false -nologo -clp:NoSummary --verbosity quiet
"$DOTNET_EXE" run --project "$BUILD_PROJECT_FILE" --no-build -- "$@"
1 change: 0 additions & 1 deletion build/Build.cs
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,6 @@
using static Nuke.Common.IO.PathConstruction;
using static Nuke.Common.Tools.DotNet.DotNetTasks;

[CheckBuildProjectConfigurations]
[ShutdownDotNetAfterServerBuild]
class Build : NukeBuild
{
Expand Down
2 changes: 1 addition & 1 deletion build/_build.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
</PropertyGroup>

<ItemGroup>
<PackageReference Include="Nuke.Common" Version="6.0.2" />
<PackageReference Include="Nuke.Common" Version="6.1.0" />
</ItemGroup>

</Project>
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
</PropertyGroup>

<ItemGroup>
<PackageReference Include="Microsoft.AspNetCore.Authentication.JwtBearer" Version="6.0.4" />
<PackageReference Include="Microsoft.AspNetCore.Authentication.JwtBearer" Version="6.0.6" />
</ItemGroup>

<ItemGroup>
Expand Down
43 changes: 43 additions & 0 deletions src/Fga.Net.AspNetCore/Authorization/FgaCheckDecorator.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
using Auth0.Fga.Api;
using Auth0.Fga.Model;

namespace Fga.Net.AspNetCore.Authorization;

/// <summary>
/// Temporary wrapper to allow for easier testing of middleware. Don't take a dependency on this.
/// </summary>
public class FgaCheckDecorator : IFgaCheckDecorator
{
private readonly Auth0FgaApi _auth0FgaApi;

/// <summary>
///
/// </summary>
/// <param name="auth0FgaApi"></param>
public FgaCheckDecorator(Auth0FgaApi auth0FgaApi)
{
_auth0FgaApi = auth0FgaApi;
}

/// <summary>
///
/// </summary>
/// <param name="request"></param>
/// <param name="ct"></param>
/// <returns></returns>
public virtual Task<CheckResponse> Check(CheckRequest request, CancellationToken ct) => _auth0FgaApi.Check(request, ct);
}

/// <summary>
/// Temporary wrapper to allow for easier testing of middleware. Don't take a dependency on this.
/// </summary>
public interface IFgaCheckDecorator
{
/// <summary>
///
/// </summary>
/// <param name="request"></param>
/// <param name="ct"></param>
/// <returns></returns>
Task<CheckResponse> Check(CheckRequest request, CancellationToken ct);
}
Original file line number Diff line number Diff line change
Expand Up @@ -16,24 +16,24 @@ limitations under the License.
*/
#endregion

using Auth0.Fga.Api;
using Auth0.Fga.Model;
using Fga.Net.AspNetCore.Authorization.Attributes;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.Logging;

namespace Fga.Net.AspNetCore.Authorization;

internal class FineGrainedAuthorizationHandler : AuthorizationHandler<FineGrainedAuthorizationRequirement>
{
private readonly Auth0FgaApi _client;
private readonly IFgaCheckDecorator _client;
private readonly ILogger<FineGrainedAuthorizationHandler> _logger;

public FineGrainedAuthorizationHandler(Auth0FgaApi client)
public FineGrainedAuthorizationHandler(IFgaCheckDecorator client, ILogger<FineGrainedAuthorizationHandler> logger)
{
_client = client;
_logger = logger;
}


protected override async Task HandleRequirementAsync(AuthorizationHandlerContext context, FineGrainedAuthorizationRequirement requirement)
{
if (context.Resource is HttpContext httpContext)
Expand All @@ -45,7 +45,6 @@ protected override async Task HandleRequirementAsync(AuthorizationHandlerContext
// The user is enforcing the fga policy but there's no attributes here.
if (attributes.Count == 0)
return;
var results = new List<bool>();
foreach (var attribute in attributes)
{
var user = await attribute.GetUser(httpContext);
Expand All @@ -55,7 +54,7 @@ protected override async Task HandleRequirementAsync(AuthorizationHandlerContext
if (string.IsNullOrEmpty(user) || string.IsNullOrEmpty(relation) || string.IsNullOrEmpty(@object))
return;

var result = await _client.Check(new CheckRequestParams()
var result = await _client.Check(new CheckRequest()
{
TupleKey = new TupleKey
{
Expand All @@ -65,13 +64,13 @@ protected override async Task HandleRequirementAsync(AuthorizationHandlerContext
}
}, httpContext.RequestAborted);

results.Add(result.Allowed);
if (!result.Allowed)
{
_logger.CheckFailureDebug(user, relation, @object);
return;
}
}

if(results.All(x => x))
context.Succeed(requirement);
context.Succeed(requirement);
}
}
}


Original file line number Diff line number Diff line change
Expand Up @@ -22,4 +22,7 @@ namespace Fga.Net.AspNetCore.Authorization;

internal class FineGrainedAuthorizationRequirement : IAuthorizationRequirement
{
public override string ToString() =>
$"{nameof(FineGrainedAuthorizationRequirement)}: Requires FGA Authorization checks to pass.";

}
27 changes: 27 additions & 0 deletions src/Fga.Net.AspNetCore/Authorization/Log.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
#region License
/*
Copyright 2021-2022 Hawxy
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
#endregion

using Microsoft.Extensions.Logging;

namespace Fga.Net.AspNetCore.Authorization;

internal static partial class Log
{
[LoggerMessage(0, LogLevel.Debug, "FGA Check failed for User: {user}, Relation: {relation}, Object: {object}")]
public static partial void CheckFailureDebug(this ILogger logger, string user, string relation, string @object);
}
2 changes: 1 addition & 1 deletion src/Fga.Net.AspNetCore/Controllers/FgaControllerBase.cs
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ public FgaControllerBase(Auth0FgaApi client)
/// <returns></returns>
public async Task<bool> Check(string user, string relation, string @object, CancellationToken ct)
{
var checkRes = await _client.Check(new CheckRequestParams()
var checkRes = await _client.Check(new CheckRequest()
{
TupleKey = new TupleKey
{
Expand Down
1 change: 1 addition & 0 deletions src/Fga.Net.AspNetCore/ServiceCollectionExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ public static IServiceCollection AddAuth0Fga(this IServiceCollection collection,
ArgumentNullException.ThrowIfNull(config);

collection.AddAuth0FgaClient(config);
collection.AddScoped<IFgaCheckDecorator, FgaCheckDecorator>();
collection.AddScoped<IAuthorizationHandler, FineGrainedAuthorizationHandler>();
return collection;
}
Expand Down
2 changes: 1 addition & 1 deletion src/Fga.Net/Fga.Net.DependencyInjection.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
</PropertyGroup>

<ItemGroup>
<PackageReference Include="Auth0.Fga" Version="0.2.4" />
<PackageReference Include="Auth0.Fga" Version="0.3.1" />
<PackageReference Include="Microsoft.Extensions.Http" Version="6.0.0" />
<PackageReference Include="DotNet.ReproducibleBuilds" Version="1.1.1" PrivateAssets="All" />
</ItemGroup>
Expand Down
19 changes: 12 additions & 7 deletions tests/Fga.Net.Tests/Client/EndpointTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -23,13 +23,19 @@ private async Task GetEndpoints_Return_200()
{
using var scope = _host.Services.CreateScope();
var client = scope.ServiceProvider.GetRequiredService<Auth0FgaApi>();
var modelIds = await client.ReadAuthorizationModels();
var modelsResponse = await client.ReadAuthorizationModels();

Assert.NotNull(modelIds);
Assert.NotNull(modelIds.AuthorizationModelIds);
Assert.True(modelIds.AuthorizationModelIds?.Count > 0);
Assert.NotNull(modelsResponse);
Assert.NotNull(modelsResponse.AuthorizationModels);
Assert.True(modelsResponse.AuthorizationModels?.Count > 0);

var modelId = modelsResponse.AuthorizationModels?.First().Id!;

var modelResponse = await client.ReadAuthorizationModel(modelId);

Assert.NotNull(modelResponse);
Assert.NotNull(modelResponse.AuthorizationModel.Id);

var modelId = modelIds.AuthorizationModelIds?.First()!;
var assertions = await client.ReadAssertions(modelId);

Assert.NotNull(assertions);
Expand All @@ -40,7 +46,7 @@ private async Task GetEndpoints_Return_200()
Assert.NotEmpty(assertion.Relation!);
Assert.NotEmpty(assertion.User!);

var graph = await client.Expand(new ExpandRequestParams()
var graph = await client.Expand(new ExpandRequest()
{
AuthorizationModelId = modelId,
TupleKey = assertion
Expand All @@ -51,7 +57,6 @@ private async Task GetEndpoints_Return_200()

var watch = await client.ReadChanges();
Assert.NotNull(watch);


}

Expand Down
6 changes: 3 additions & 3 deletions tests/Fga.Net.Tests/Fga.Net.Tests.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,10 @@

<ItemGroup>
<PackageReference Include="Alba" Version="6.1.0" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.1.0" />
<PackageReference Include="Moq" Version="4.17.2" />
<PackageReference Include="Moq" Version="4.18.1" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.2.0" />
<PackageReference Include="xunit" Version="2.4.1" />
<PackageReference Include="xunit.runner.visualstudio" Version="2.4.3">
<PackageReference Include="xunit.runner.visualstudio" Version="2.4.5">
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
<PrivateAssets>all</PrivateAssets>
</PackageReference>
Expand Down
4 changes: 2 additions & 2 deletions tests/Fga.Net.Tests/Middleware/MiddlewareTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ public MiddlewareTests(WebAppFixture fixture)
{
_alba = fixture.AlbaHost;
}
[Fact(Skip="Moq is broke")]
[Fact]
public async Task Authorization_HappyPath_Succeeds()
{
await _alba.Scenario(_ =>
Expand All @@ -28,7 +28,7 @@ await _alba.Scenario(_ =>
_.StatusCodeShouldBeOk();
});
}
[Fact(Skip = "Moq is broke")]
[Fact]
public async Task Authorization_UnhappyPath_Forbidden()
{
await _alba.Scenario(_ =>
Expand Down
10 changes: 5 additions & 5 deletions tests/Fga.Net.Tests/Middleware/WebAppFixture.cs
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
using System.Threading;
using System.Threading.Tasks;
using Alba;
using Auth0.Fga.Api;
using Auth0.Fga.Model;
using Fga.Net.AspNetCore.Authorization;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.DependencyInjection.Extensions;
using Moq;
Expand All @@ -16,12 +16,12 @@ public class WebAppFixture : IAsyncLifetime

public async Task InitializeAsync()
{
var authorizationClientMock = new Mock<Auth0FgaApi>();
var authorizationClientMock = new Mock<IFgaCheckDecorator>();

authorizationClientMock.Setup(c =>
c.Check(It.IsAny<CheckRequestParams>(),
c.Check(It.IsAny<CheckRequest>(),
It.IsAny<CancellationToken>()))
.ReturnsAsync((string _, CheckRequestParams res, CancellationToken _) =>
.ReturnsAsync((CheckRequest res, CancellationToken _) =>
res.TupleKey!.User == MockJwtConfiguration.DefaultUser
? new CheckResponse() { Allowed = true }
: new CheckResponse() { Allowed = false });
Expand All @@ -31,7 +31,7 @@ public async Task InitializeAsync()
{
builder.ConfigureServices(s =>
{
s.Replace(ServiceDescriptor.Scoped<Auth0FgaApi>(_ => authorizationClientMock.Object));
s.Replace(ServiceDescriptor.Scoped<IFgaCheckDecorator>(_ => authorizationClientMock.Object));
});

}, MockJwtConfiguration.GetDefaultStubConfiguration());
Expand Down

0 comments on commit 3a85f03

Please sign in to comment.