Skip to content

Commit

Permalink
docs: Add Authentication docs (#73)
Browse files Browse the repository at this point in the history
* docs: Add Authentication docs
  • Loading branch information
NikiforovAll authored Apr 26, 2024
1 parent 8e0e0b5 commit 73cf9ca
Show file tree
Hide file tree
Showing 33 changed files with 802 additions and 439 deletions.
8 changes: 4 additions & 4 deletions .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ jobs:
runs-on: ${{matrix.os}}
strategy:
matrix:
os: [ubuntu-latest, windows-latest, macOS-latest]
os: [ubuntu-latest, windows-latest]
steps:
- name: "Checkout"
uses: actions/[email protected]
Expand All @@ -43,9 +43,9 @@ jobs:
- name: "Dotnet Cake Build"
run: dotnet cake --target=Build
shell: pwsh
- name: "Dotnet Cake Test"
run: dotnet cake --target=Test
shell: pwsh
# - name: "Dotnet Cake Test"
# run: dotnet cake --target=Test
# shell: pwsh
- name: "Dotnet Cake Pack"
run: dotnet cake --target=Pack
shell: pwsh
Expand Down
14 changes: 14 additions & 0 deletions KeycloakAuthorizationServicesDotNet.sln
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,10 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "AuthorizationGettingStarted
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "GettingStarted", "samples\GettingStarted\GettingStarted.csproj", "{671BA3B1-DBF2-4161-97B5-433B91A3730E}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Keycloak.AuthServices.IntegrationTests", "tests\Keycloak.AuthServices.IntegrationTests\Keycloak.AuthServices.IntegrationTests.csproj", "{7499F9F0-1132-46B4-AAA2-D60D9F113293}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "TestWebApi", "tests\TestWebApi\TestWebApi.csproj", "{0F40EFE2-8D17-46B2-A91B-EC4BCB93E77C}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Expand Down Expand Up @@ -130,6 +134,14 @@ Global
{671BA3B1-DBF2-4161-97B5-433B91A3730E}.Debug|Any CPU.Build.0 = Debug|Any CPU
{671BA3B1-DBF2-4161-97B5-433B91A3730E}.Release|Any CPU.ActiveCfg = Release|Any CPU
{671BA3B1-DBF2-4161-97B5-433B91A3730E}.Release|Any CPU.Build.0 = Release|Any CPU
{7499F9F0-1132-46B4-AAA2-D60D9F113293}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{7499F9F0-1132-46B4-AAA2-D60D9F113293}.Debug|Any CPU.Build.0 = Debug|Any CPU
{7499F9F0-1132-46B4-AAA2-D60D9F113293}.Release|Any CPU.ActiveCfg = Release|Any CPU
{7499F9F0-1132-46B4-AAA2-D60D9F113293}.Release|Any CPU.Build.0 = Release|Any CPU
{0F40EFE2-8D17-46B2-A91B-EC4BCB93E77C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{0F40EFE2-8D17-46B2-A91B-EC4BCB93E77C}.Debug|Any CPU.Build.0 = Debug|Any CPU
{0F40EFE2-8D17-46B2-A91B-EC4BCB93E77C}.Release|Any CPU.ActiveCfg = Release|Any CPU
{0F40EFE2-8D17-46B2-A91B-EC4BCB93E77C}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
Expand All @@ -151,6 +163,8 @@ Global
{82DB0FDE-316D-4741-B335-8B7B36DBE962} = {AEBE10B1-96B1-4060-B8C1-1F9BFA7A586C}
{D64B4098-165B-48AA-BE07-B9E9963E0CB5} = {AEBE10B1-96B1-4060-B8C1-1F9BFA7A586C}
{671BA3B1-DBF2-4161-97B5-433B91A3730E} = {AEBE10B1-96B1-4060-B8C1-1F9BFA7A586C}
{7499F9F0-1132-46B4-AAA2-D60D9F113293} = {96857509-627A-4FD2-AC82-34387619A7B1}
{0F40EFE2-8D17-46B2-A91B-EC4BCB93E77C} = {96857509-627A-4FD2-AC82-34387619A7B1}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {E1907BFD-C144-4B48-AA40-972F499D4E08}
Expand Down
3 changes: 3 additions & 0 deletions docs/admin-rest-api.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
# Admin REST HTTP API

🚧👋 Come back later
242 changes: 235 additions & 7 deletions docs/configuration/configuration-authentication.md
Original file line number Diff line number Diff line change
@@ -1,15 +1,243 @@
# Configure Authentication

🚧👋 Come back later
**Keycloak.AuthServices.Authentication** provides robust authentication mechanisms for both web APIs and web applications. For web APIs, it supports JWT Bearer token authentication, which allows clients to authenticate to the API by providing a JWT token in the Authorization header of their requests. For web applications, it supports OpenID Connect, a simple identity layer on top of the OAuth 2.0 protocol

## KeycloakWebApiAuthenticationBuilderExtensions
---

## KeycloakWebApiServiceCollectionExtensions
[[toc]]

## KeycloakWebAppAuthenticationBuilderExtensions
## Web API

## KeycloakWebAppServiceCollectionExtensions
Here is what library does for you:

## KeycloakConfigurationProvider
* Adds and configures `AddJwtBearer` based on provided configuration.
* Registers `IOptions<KeycloakAuthenticationOptions>` and `IOptions<JwtBearerOptions>`.
* Registers `KeycloakRolesClaimsTransformation` so special Keycloak role claims are added to `ClaimsPrincipal`. See [Keycloak Claims Transformation](#keycloak-claims-transformation)

## KeycloakRolesClaimsTransformation
### ServiceCollection Extensions

The **Keycloak.AuthServices.Authentication** library will automatically retrieve the configuration values under the "Keycloak" section. You can access these values in your code to configure the authentication process. This section is likely defined in your application's configuration file, such as *appsettings.json*

```json
{
"Keycloak": {
"realm": "Test",
"auth-server-url": "http://localhost:8080/",
"ssl-required": "none",
"resource": "test-client",
"verify-token-audience": false,
"credentials": {
"secret": ""
}
}
}
```

Simply add:

<<< @/../tests/Keycloak.AuthServices.IntegrationTests/AddKeycloakWebApiAuthenticationTests.cs#AddKeycloakWebApiAuthentication_FromConfiguration

This default assumption of the "Keycloak" section allows you to easily configure the library without explicitly specifying the section name every time. However, if you have a different section name or want to customize the configuration retrieval process, the library provides additional methods and options to handle that.

::: code-group
<<< @/../tests/Keycloak.AuthServices.IntegrationTests/AddKeycloakWebApiAuthenticationTests.cs#AddKeycloakWebApiAuthentication_FromConfigurationSection [specify configuration section]

<<< @/../tests/Keycloak.AuthServices.IntegrationTests/AddKeycloakWebApiAuthenticationTests.cs#AddKeycloakWebApiAuthentication_FromConfiguration2 [specify section name]

:::

Not everything you want to do can be configured with `KeycloakAuthenticationOptions`, for more fine-grained configuration use next method overload that takes `Action<JwtBearerOptions>`:

<<< @/../tests/Keycloak.AuthServices.IntegrationTests/AddKeycloakWebApiAuthenticationTests.cs#AddKeycloakWebApiAuthentication_FromConfigurationWithOverrides

### AuthenticationBuilder Extensions

For situations when you want to override *Authentication Scheme* or you just prefer more verbose way of defining your project's *Authentication* you can use `AuthenticationBuilder` extension methods:

<<< @/../tests/Keycloak.AuthServices.IntegrationTests/AddKeycloakWebApiTests.cs#AddKeycloakWebApiAuthentication_FromConfiguration

Use `IConfigurationSection`:

<<< @/../tests/Keycloak.AuthServices.IntegrationTests/AddKeycloakWebApiTests.cs#AddKeycloakWebApiAuthentication_FromConfigurationSection

Inline declaration:

<<< @/../tests/Keycloak.AuthServices.IntegrationTests/AddKeycloakWebApiTests.cs#AddKeycloakWebApiAuthentication_FromInline

Inline declaration with `JwtBearerOptions` overrides:

<<< @/../tests/Keycloak.AuthServices.IntegrationTests/AddKeycloakWebApiTests.cs#AddKeycloakWebApiAuthentication_FromInline2

## Web App

In the context of web development, a web application (web app) refers to a software application that runs on a web server and is accessed by users through a web browser.

OpenID Connect (OIDC) is a protocol that allows web applications to authenticate and authorize users. It is built on top of the OAuth 2.0 protocol, which is a widely used authorization framework. OIDC adds an identity layer to OAuth 2.0, enabling web apps to obtain information about the authenticated user.

Here is what library does for you:

* Adds and configures `OpenIdConnect` based on provided configuration.
* Registers `IOptions<KeycloakAuthenticationOptions>`, `IOptions<OpenIdConnectOptions>`, and `IOptions<CookieAuthenticationOptions>`.
* Registers `KeycloakRolesClaimsTransformation` so special Keycloak role claims are added to `ClaimsPrincipal`. See [Keycloak Claims Transformation](#keycloak-claims-transformation)

### ServiceCollection Extensions 🚧

From configuration:

```csharp
public static KeycloakWebAppAuthenticationBuilder AddKeycloakWebAppAuthentication(
this IServiceCollection services,
IConfiguration configuration,
string configSectionName = KeycloakAuthenticationOptions.Section,
string openIdConnectScheme = OpenIdConnectDefaults.AuthenticationScheme,
string cookieScheme = CookieAuthenticationDefaults.AuthenticationScheme,
string? displayName = null
)
```

### AuthenticationBuilder Extensions 🚧

From configuration:

```csharp
public static KeycloakWebAppAuthenticationBuilder AddKeycloakWebApp(
this AuthenticationBuilder builder,
IConfiguration configuration,
string configSectionName = KeycloakAuthenticationOptions.Section,
string openIdConnectScheme = OpenIdConnectDefaults.AuthenticationScheme,
string cookieScheme = CookieAuthenticationDefaults.AuthenticationScheme,
string? displayName = null
)
```

Inline:

```csharp
public static KeycloakWebAppAuthenticationBuilder AddKeycloakWebApp(
this AuthenticationBuilder builder,
Action<KeycloakAuthenticationOptions> configureKeycloakOptions,
Action<CookieAuthenticationOptions>? configureCookieAuthenticationOptions = null,
Action<OpenIdConnectOptions>? configureOpenIdConnectOptions = null,
string openIdConnectScheme = OpenIdConnectDefaults.AuthenticationScheme,
string? cookieScheme = CookieAuthenticationDefaults.AuthenticationScheme,
string? displayName = null
)
```

See [source code](https://github.com/NikiforovAll/keycloak-authorization-services-dotnet/blob/main/src/Keycloak.AuthServices.Authentication/WebAppExtensions/KeycloakWebAppAuthenticationBuilderExtensions.cs) for more details.

## Adapter File Configuration Provider

Using *appsettings.json* is a recommended and it is an idiomatic approach for .NET, but if you want a standalone "adapter" (installation) file - *keycloak.json*. You can use `ConfigureKeycloakConfigurationSource`. It adds dedicated configuration source.

```csharp
var builder = WebApplication.CreateBuilder(args);

builder.Host.ConfigureKeycloakConfigurationSource("keycloak.json"); // [!code focus]
builder.Services.AddKeycloakWebApiAuthentication(builder.Configuration);

var app = builder.Build();
app.UseAuthentication();
app.UseAuthorization();

app.MapGet("/", () => "Hello World!").RequireAuthorization();

app.Run();
```

Here is an example of **keycloak.json** adapter file:

```json
{
"realm": "Test",
"auth-server-url": "http://localhost:8088/",
"ssl-required": "external",
"resource": "test-client",
"verify-token-audience": true
}

```

## Keycloak Claims Transformation

Keycloak roles can be automatically transformed to [AspNetCore Roles](https://learn.microsoft.com/en-us/aspnet/core/security/authorization/roles). This feature is disabled by default.

There are three options to determine a source for the roles:

```csharp
public enum RolesClaimTransformationSource
{
/// <summary>
/// No Transformation. Default
/// </summary>
None,

/// <summary>
/// Use realm roles as source
/// </summary>
Realm,

/// <summary>
/// Use client roles as source
/// </summary>
ResourceAccess
}
```

Here is an example of decoded JWT token:

```json
{
"exp": 1714057504,
"iat": 1714057204,
"jti": "7250d2a9-e5a1-442f-9e76-5e6b78bb2760",
"iss": "http://localhost:8080/realms/Test",
"aud": [
"test-client",
"account"
],
"sub": "bf0b3371-ccdc-44f6-8861-ce25cbfcac39",
"typ": "Bearer",
"azp": "test-client",
"session_state": "563332d2-111a-4ef2-b6a0-ebc1d3ae9a1e",
"acr": "1",
"allowed-origins": [
"/*"
],
"realm_access": {
"roles": [
"default-roles-test",
"offline_access",
"uma_authorization"
]
},
"resource_access": {
"account": {
"roles": [
"manage-account",
"manage-account-links",
"view-profile"
]
}
},
"scope": "profile email",
"sid": "563332d2-111a-4ef2-b6a0-ebc1d3ae9a1e",
"email_verified": false,
"name": "Test Test",
"preferred_username": "test",
"given_name": "Test",
"family_name": "Test",
"email": "[email protected]"
}
```

If we specify `KeycloakAuthenticationOptions.RolesSource = RolesClaimTransformationSource.Realm` the roles are taken from $token.realm_access.roles.

Result = ["default-roles-test","offline_access","uma_authorization"]

If we specify `KeycloakAuthenticationOptions.RolesSource = RolesClaimTransformationSource.ResourceAccess` and `KeycloakAuthenticationOptions.RolesResource="account"` the roles are taken from $token.realm_access.account.roles.

Result = ["manage-account","manage-account-links","view-profile"]

The target claim can be configured `KeycloakAuthenticationOptions.RoleClaimType`, the default value is "role".
9 changes: 2 additions & 7 deletions docs/configuration/configuration-keycloak.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,8 @@

This section contains a general instruction of how to configure Keyclaok to be used for .NET applications.

- [Configure Keycloak](#configure-keycloak)
- [Create Realm](#create-realm)
- [Create User](#create-user)
- [Set Password](#set-password)
- [Create Client](#create-client)
- [Add Audience Mapper](#add-audience-mapper)
- [Download Adapter Config](#download-adapter-config)
*Table of Contents*:
[[toc]]

## Create Realm

Expand Down
Loading

0 comments on commit 73cf9ca

Please sign in to comment.