Skip to content

Commit

Permalink
docs: Add Authorization Server docs (#80)
Browse files Browse the repository at this point in the history
* docs: Add Authorization Server docs

* Add code to example

* feat: Add multiple resources support
  • Loading branch information
NikiforovAll authored May 2, 2024
1 parent 591063f commit 8beb35c
Show file tree
Hide file tree
Showing 24 changed files with 757 additions and 65 deletions.
13 changes: 9 additions & 4 deletions docs/.vitepress/config.mts
Original file line number Diff line number Diff line change
@@ -1,19 +1,20 @@
import { defineConfig } from 'vitepress'
import { withMermaid } from "vitepress-plugin-mermaid";

// https://vitepress.dev/reference/site-config
export default defineConfig({
export default withMermaid({
title: "Keycloak.AuthServices",
description: "",
base: '/keycloak-authorization-services-dotnet/',
themeConfig: {
logo: '/logo.svg',
// https://vitepress.dev/reference/default-theme-config
nav: [
{ text: 'Home', link: '/' },
{ text: 'Getting Started', link: '/introduction' },
{ text: 'Migration', link: '/migration' },
{ text: 'Examples', link: 'examples/auth-getting-started' }
],

sidebar: {
'/': [
{
Expand All @@ -38,6 +39,7 @@ export default defineConfig({
collapsed: false,
items: [
{ text: 'Authorization Server', link: '/authorization/authorization-server' },
{ text: 'Protected Resources ✨', link: '/authorization/resources' },
]
},
{
Expand All @@ -54,6 +56,9 @@ export default defineConfig({
},
socialLinks: [
{ icon: 'github', link: 'https://github.com/NikiforovAll/keycloak-authorization-services-dotnet' }
]
],
editLink: {
pattern: 'https://github.com/NikiforovAll/keycloak-authorization-services-dotnet/edit/main/docs/:path'
}
}
})
});
20 changes: 17 additions & 3 deletions docs/authorization/authorization-server.md
Original file line number Diff line number Diff line change
@@ -1,18 +1,32 @@
# Authorization Server

Keycloak is an open-source Identity and Access Management solution that provides an Authorization Server. The Authorization Server is responsible for access to clients after successfully authenticating and authorizing the users.
Keycloak is an open-source Identity and Access Management solution that provides an Authorization Server. The Authorization Server is responsible for access to resources.

In addition to the Authorization Server, Keycloak also supports a *Policy Enforcement Point* (PEP). The PEP is responsible for enforcing access control policies and protecting resources. It intercepts requests from clients and verifies the access token before allowing or denying access to the requested resource.
> [!TIP]
> See Keycloak's documentation - [Authorization Services Guide](https://www.keycloak.org/docs/latest/authorization_services) for more details.
This functionality is based on a *Policy Enforcement Point* (**PEP**). The PEP is responsible for enforcing access control policies and protecting resources. It intercepts requests from clients (users) and verifies the access token before allowing or denying access to the requested resource.

By integrating Keycloak's Authorization Server and PEP into your application, you can implement fine-grained access control and secure your resources based on user roles, permissions, and other attributes.

The PEP works together with the Policy Decision Point (**PDP**), which is the component that actually makes the decision whether access should be granted based on the policies defined in Keycloak.

When a request to access a resource is made, the PEP intercepts the request and sends a request to the PDP to evaluate the policies associated with the requested resource. The PDP evaluates the policies and returns a decision (permit or deny) back to the PEP. The PEP then enforces this decision.

Remember that to use the PEP endpoint and the Keycloak Authorization Services, you need to enable authorization for your client in the Keycloak admin console.

![authz-arch-overview](/images/authz-arch-overview.png)

> [!TIP]
> See Keycloak's documentation - [Authorization Server Architecture](https://www.keycloak.org/docs/latest/authorization_services/index.html#_overview_architecture) for more details.
## Evaluate Permissions

Assume we have a default resource with Name *"urn:test-client:resources:default"*.

We want to check if a given user has access to it. It is accomplished based on permissions. In our case default permission is applied to default resource type. *"Default Permission"* is based on policy named - *"Require Admin Role"*. This policy checks if a user has *"Admin"* realm role.

Here is how to do it from code:
Here is how to use `AuthorizationBuilder` to define policy for a protected resource:

<<< @/../tests/Keycloak.AuthServices.IntegrationTests/AuthorizationServerPolicyTests.cs#RequireProtectedResource_DefaultResource_Verified

Expand Down
88 changes: 88 additions & 0 deletions docs/authorization/resources.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
# Protected Resources

*Keycloak Authorization Server* is a powerful tool that provides fine-grained access control to your services and applications. It enables developers to manage **permissions** and **policies** *centrally*, providing a standardized way to secure applications regardless of the platform they are built on.

*Table of Contents*:
[[toc]]

## Example

Let's say we have a workspace management functionality, that allows users to create and manage workspaces.

In this example, we have:

1. An entity named workspace. The entity (aka **resource**) *"my-workspace"* represents a specific workspace in an application.
2. The available actions on the workspace are reading and writing, represented by the **scopes** *"workspace:read"* and *"workspace:write"*.
3. The **permissions** associated with these scopes are *"Read Workspace"* and *"Delete Workspace"*.

The Authorization Server evaluates these permissions to determine whether a user has access to a workspace based on their role and the requested action.

```mermaid
graph LR
A -- has --> C[Scope: workspace:write]
D[Permission: Read Workspace] -- assigned to --> B
E[Permission: Delete Workspace] -- assigned to --> C
F[Policy: Require Reader Role] -- applies to --> D
G[Policy: Require Admin Role] -- applies to --> E
G[Policy: Require Admin Role] -- applies to --> D
A[Resource: my-workspace] -- has --> B[Scope: workspace:read]
```

In Keycloak, you can define **resources**, which are the entities that you want to protect. For instance, in the given example, we have a resource named *"my-workspace"* with a type of *"urn:workspaces"*. This resource could represent a workspace in an application that users can access and manipulate.

Keycloak allows you to define **scopes**, which are the actions that can be performed on a resource. In our example, we have two scopes defined: *"workspace:read"* and *"workspace:write"*. These scopes represent the ability to read and write to the workspace.

Keycloak also allows you to define **permissions**, which are the rules that determine who can perform which actions on a resource. In our example, we have two permissions: *"Delete Workspace"* and *"Read Workspace"*. These permissions are linked to specific scopes and are based on policies.

Policies in Keycloak are the conditions that a user must meet to be granted a permission. They can be based on various attributes, including the role of the user, time, and location.

In our example, we have two policies: *"Require Admin Role"* and *"Require Reader Role"*. These policies are based on realm roles, which are roles that apply to the entire Keycloak realm.

To delete a workspace, a user must have the Admin role, as defined by the "Require Admin Role" policy. To read a workspace, a user can have either the Admin role or the Reader role, as defined by the "Require Reader Role" policy.

The *Keycloak Authorization Server* evaluates these policies whenever a user attempts to access a resource. If the user meets the conditions of the policy, the server grants the permission and the user can perform the action on the resource. This allows for powerful, fine-grained access control that can be easily managed and updated as your application evolves.

## Configure Keycloak

> [!NOTE]
> In this section, I'm not going to show you how to setup full example, but rather provide some example, for the full configuration I suggest you looking at the source code. It contains import files that Keycloak allows you to use manually or via CLI.
>
> * [tests/Keycloak.AuthServices.IntegrationTests/KeycloakConfiguration](https://github.com/NikiforovAll/keycloak-authorization-services-dotnet/tree/main/tests/Keycloak.AuthServices.IntegrationTests/KeycloakConfiguration)
> * [tests/Keycloak.AuthServices.IntegrationTests/docker-compose.yml](https://github.com/NikiforovAll/keycloak-authorization-services-dotnet/tree/main/tests/Keycloak.AuthServices.IntegrationTests/docker-compose.yml)
> * <https://www.keycloak.org/server/importExport>
💡 Here an example of how to create a permission for scopes:

![permission](/images/read-workspace-permission.png)

💡 Here is an example of how to create a resource and associate a scopes with it:

![permission](/images/my-workspace-resource.png)

💡 Keycloak provides a UI to evaluate permissions for a given resource, user, scopes, etc. This feature enables you to prototype and troubleshoot more easily. Here is an example of how to evaluate permissions for an admin user:

![permission](/images/evaluate-permissions-for-admin.png)

## Add to your code

Here is how to use to use protected resource authorization.

<<< @/../tests/Keycloak.AuthServices.IntegrationTests/AuthorizationServerPolicyTests.cs#RequireProtectedResource_Scopes_Verified

Here are the assertions from the integration test for this scenario:

<<< @/../tests/Keycloak.AuthServices.IntegrationTests/AuthorizationServerPolicyTests.cs#RequireProtectedResource_Scopes_Verified_Assertion

Source code of integration test: [tests/Keycloak.AuthServices.IntegrationTests/AuthorizationServerPolicyTests.cs](https://github.com/NikiforovAll/keycloak-authorization-services-dotnet/blob/main/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`:

<<< @/../tests/Keycloak.AuthServices.IntegrationTests/AuthorizationServerPolicyTests.cs#RequireProtectedResource_MultipleScopesAllOf_Verified

Here is an example for `ScopesValidationMode.AnyOf`:

<<< @/../tests/Keycloak.AuthServices.IntegrationTests/AuthorizationServerPolicyTests.cs#RequireProtectedResource_MultipleScopesAnyOf_Verified
3 changes: 2 additions & 1 deletion docs/configuration/configuration-authentication.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

---

*Table of Contents*:
[[toc]]

## Web API
Expand Down Expand Up @@ -108,7 +109,7 @@ Inline declaration with `JwtBearerOptions` overrides:

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

## Web App
## Web App <Badge type="warning" text="beta" />

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.

Expand Down
1 change: 1 addition & 0 deletions docs/configuration/configuration-authorization.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

With Keycloak, you can configure roles by defining realm roles and resource roles. Realm roles are global roles that apply to the entire realm, while resource roles are specific to a particular client or resource.

*Table of Contents*:
[[toc]]

## Require Realm Roles
Expand Down
3 changes: 3 additions & 0 deletions docs/images/authz-arch-overview.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
3 changes: 3 additions & 0 deletions docs/images/evaluate-permissions-for-admin.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
3 changes: 3 additions & 0 deletions docs/images/my-workspace-resource.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
3 changes: 3 additions & 0 deletions docs/images/read-workspace-permission.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
2 changes: 1 addition & 1 deletion docs/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ hero:
link: /configuration/configuration-authentication
- theme: alt
text: Authorization
link: /configuration/configuration-authorization
link: /authorization/authorization-server
- theme: alt
text: HTTP REST Admin API
link: /admin-rest-api
Expand Down
3 changes: 3 additions & 0 deletions docs/public/logo.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,22 @@ public interface IKeycloakProtectionClient
Task<bool> VerifyAccessToResource(
string resource,
string scope,
CancellationToken cancellationToken
CancellationToken cancellationToken = default
) =>
this.VerifyAccessToResource(resource, scope, ScopesValidationMode.AllOf, cancellationToken);

/// <summary>
/// Verifies access to the protected resource. Sends decision request to token endpoint {resource}#{scope}
/// </summary>
/// <param name="resource"></param>
/// <param name="scope"></param>
/// <param name="scopesValidationMode"></param>
/// <param name="cancellationToken"></param>
/// <returns></returns>
Task<bool> VerifyAccessToResource(
string resource,
string scope,
ScopesValidationMode? scopesValidationMode = default,
CancellationToken cancellationToken = default
);
}
Loading

0 comments on commit 8beb35c

Please sign in to comment.