Protect ASP.NET Core
ASP.NET Core allows you to built policies based on Microsoft.AspNetCore.Authorization.AuthorizationBuilder. Keycloak.AuthServices.Authorization
adds Microsoft.AspNetCore.Authorization.AuthorizationPolicyBuilder extension methods to work with protected resources and configure your polices.
AuthorizationPolicyBuilderExtensions
/// <summary>
/// Adds protected resource requirement to builder. Makes outgoing HTTP requests to Authorization Server.
/// </summary>
/// <param name="builder"></param>
/// <param name="resource"></param>
/// <param name="scope"></param>
/// <returns></returns>
public static AuthorizationPolicyBuilder RequireProtectedResource(
this AuthorizationPolicyBuilder builder,
string resource,
string scope
)
{
ArgumentNullException.ThrowIfNull(builder);
ArgumentNullException.ThrowIfNull(resource);
ArgumentNullException.ThrowIfNull(scope);
return builder.AddRequirements(new DecisionRequirement(resource, scope));
}
Add to your code
Here is how to use to use protected resource authorization.
services
.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
.AddKeycloakWebApi(context.Configuration);
services
.AddAuthorization()
.AddKeycloakAuthorization()
.AddAuthorizationBuilder()
.AddPolicy(
policyName,
policy =>
policy.RequireProtectedResource(
resource: "my-workspace",
scope: "workspace:delete"
)
);
services.AddAuthorizationServer(context.Configuration);
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
Here is an example of how to use registered policies:
var app = builder.Build();
app.UseAuthentication();
app.UseAuthorization();
app.MapGet("/", () => "Hello World!")
.RequireAuthorization(policyName);
app.Run();
Here are the assertions from the integration test for this scenario:
await host.Scenario(_ =>
{
_.Get.Url(RunPolicyByName(policyName));
_.UserAndPasswordIs(TestUsers.Admin.UserName, TestUsers.Admin.Password);
_.StatusCodeShouldBe(HttpStatusCode.OK);
});
await host.Scenario(_ =>
{
_.Get.Url(RunPolicyByName(policyName));
_.UserAndPasswordIs(TestUsers.Tester.UserName, TestUsers.Tester.Password);
_.StatusCodeShouldBe(HttpStatusCode.Forbidden);
});
Source code of integration test: tests/Keycloak.AuthServices.IntegrationTests/AuthorizationServerPolicyTests.cs
Validate Multiple Scopes
You can specify multiple scopes to validate against and control comparison by using ScopesValidationMode
.
Here is an example for ScopesValidationMode.AllOf
:
services
.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
.AddKeycloakWebApi(context.Configuration);
services
.AddAuthorization()
.AddKeycloakAuthorization()
.AddAuthorizationBuilder()
.AddPolicy(
policyName,
policy =>
policy.RequireProtectedResource(
resource: "my-workspace",
scopes: ["workspace:delete", "workspace:read"],
scopesValidationMode: ScopesValidationMode.AllOf
)
);
services.AddAuthorizationServer(context.Configuration);
Here is an example for ScopesValidationMode.AnyOf
:
services
.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
.AddKeycloakWebApi(context.Configuration);
services
.AddAuthorization()
.AddKeycloakAuthorization()
.AddAuthorizationBuilder()
.AddPolicy(
policyName,
policy =>
policy.RequireProtectedResource(
resource: "my-workspace",
scopes: ["workspace:delete", "workspace:read"],
scopesValidationMode: ScopesValidationMode.AnyOf
)
);
services.AddAuthorizationServer(context.Configuration);