Skip to content

Commit

Permalink
Merge pull request quarkusio#37252 from sberyozkin/better_oidc_defaul…
Browse files Browse the repository at this point in the history
…t_resolver_support

Use the default tenant resolver if the custom one does not resolve a tenant
  • Loading branch information
sberyozkin authored Nov 24, 2023
2 parents 38ac518 + 21fbe9d commit 72424a7
Show file tree
Hide file tree
Showing 3 changed files with 49 additions and 85 deletions.
83 changes: 44 additions & 39 deletions docs/src/main/asciidoc/security-openid-connect-multitenancy.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -586,48 +586,12 @@ user `alice` exists in both tenants, for the application they are distinct users
When you set multiple tenant configurations in the `application.properties` file, you only need to specify how the tenant identifier gets resolved.
To configure the resolution of the tenant identifier, use one of the following options:

* <<default-tenant-resolver>>
* <<tenant-resolver>>
* <<default-tenant-resolver>>
* <<annotations-tenant-resolver>>

[[default-tenant-resolver]]
=== Default resolution

The default resolution for a tenant identifier is convention based, whereby the authentication request must include the tenant identifier in the last segment of the request path.

The following `application.properties` example shows how you can configure two tenants named `google` and `github`:

[source,properties]
----
# Tenant 'google' configuration
quarkus.oidc.google.provider=google
quarkus.oidc.google.client-id=${google-client-id}
quarkus.oidc.google.credentials.secret=${google-client-secret}
quarkus.oidc.google.authentication.redirect-path=/signed-in
# Tenant 'github' configuration
quarkus.oidc.github.provider=google
quarkus.oidc.github.client-id=${github-client-id}
quarkus.oidc.github.credentials.secret=${github-client-secret}
quarkus.oidc.github.authentication.redirect-path=/signed-in
----

In this example, both tenants configure OIDC `web-app` applications to use an authorization code flow to authenticate users and also require session cookies to get generated after the authentication has taken place.
After either Google or GitHub authenticates the current user, the user gets returned to the `/signed-in` area for authenticated users, for example, a secured resource path on the JAX-RS endpoint.

Finally, to complete the default tenant resolution, set the following configuration property:

[source,properties]
----
quarkus.http.auth.permission.login.paths=/google,/github
quarkus.http.auth.permission.login.policy=authenticated
----

If the endpoint is running on `http://localhost:8080`, you can also provide UI options for users to log in to either `http://localhost:8080/google` or `http://localhost:8080/github`, without having to add specific`/google` or `/github` JAX-RS resource paths.
Tenant identifiers are also recorded in the session cookie names after the authentication is completed.
Therefore, authenticated users can access the secured application area without requiring either the `google` or `github` path values to be included in the secured URL.

Default resolution can also work for Bearer token authentication but it might be less practical in this case because a tenant identifier will always need to be set as the last path segment value.
These tenant resolution options will be tried in turn, in the order they are listed, until the tenant id gets resolved.
If the tenant id remains unresolved (`null`) in the end then the default (unnamed) tenant configuration will be selected.

[[tenant-resolver]]
=== Resolve with `TenantResolver`
Expand Down Expand Up @@ -672,6 +636,45 @@ public class CustomTenantResolver implements TenantResolver {

In this example, the value of the last request path segment is a tenant ID, but if required, you can implement a more complex tenant identifier resolution logic.

[[default-tenant-resolver]]
=== Default resolution

The default resolution for a tenant identifier is convention based, whereby the authentication request must include the tenant identifier in the last segment of the request path.

The following `application.properties` example shows how you can configure two tenants named `google` and `github`:

[source,properties]
----
# Tenant 'google' configuration
quarkus.oidc.google.provider=google
quarkus.oidc.google.client-id=${google-client-id}
quarkus.oidc.google.credentials.secret=${google-client-secret}
quarkus.oidc.google.authentication.redirect-path=/signed-in
# Tenant 'github' configuration
quarkus.oidc.github.provider=google
quarkus.oidc.github.client-id=${github-client-id}
quarkus.oidc.github.credentials.secret=${github-client-secret}
quarkus.oidc.github.authentication.redirect-path=/signed-in
----

In this example, both tenants configure OIDC `web-app` applications to use an authorization code flow to authenticate users and also require session cookies to get generated after the authentication has taken place.
After either Google or GitHub authenticates the current user, the user gets returned to the `/signed-in` area for authenticated users, for example, a secured resource path on the JAX-RS endpoint.

Finally, to complete the default tenant resolution, set the following configuration property:

[source,properties]
----
quarkus.http.auth.permission.login.paths=/google,/github
quarkus.http.auth.permission.login.policy=authenticated
----

If the endpoint is running on `http://localhost:8080`, you can also provide UI options for users to log in to either `http://localhost:8080/google` or `http://localhost:8080/github`, without having to add specific`/google` or `/github` JAX-RS resource paths.
Tenant identifiers are also recorded in the session cookie names after the authentication is completed.
Therefore, authenticated users can access the secured application area without requiring either the `google` or `github` path values to be included in the secured URL.

Default resolution can also work for Bearer token authentication but it might be less practical in this case because a tenant identifier will always need to be set as the last path segment value.

[[annotations-tenant-resolver]]
=== Resolve with annotations

Expand Down Expand Up @@ -775,6 +778,8 @@ public class CustomTenantConfigResolver implements TenantConfigResolver {

The `OidcTenantConfig` returned from this method is the same used to parse the `oidc` namespace configuration from the `application.properties`. You can populate it using any of the settings supported by the `quarkus-oidc` extension.

If the dynamic tenant resolver returns `null` then a <<static-tenant-resolution>> will be attempted next.

=== Tenant resolution for OIDC `web-app` applications

The simplest option for resolving OIDC `web-app` application configuration is to follow the steps described in the <<default-tenant-resolver>> section.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -152,9 +152,12 @@ private TenantConfigContext getStaticTenantContext(RoutingContext context) {
if (tenantId == null && context.get(CURRENT_STATIC_TENANT_ID_NULL) == null) {
if (tenantResolver.isResolvable()) {
tenantId = tenantResolver.get().resolve(context);
} else if (tenantConfigBean.getStaticTenantsConfig().size() > 0) {
}

if (tenantId == null && tenantConfigBean.getStaticTenantsConfig().size() > 0) {
tenantId = defaultStaticTenantResolver.resolve(context);
}

if (tenantId == null) {
tenantId = context.get(OidcUtils.TENANT_ID_ATTRIBUTE);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,54 +17,10 @@ public String resolve(RoutingContext context) {
if (path.endsWith("code-flow") || path.endsWith("code-flow/logout")) {
return "code-flow";
}
if (path.endsWith("code-flow-encrypted-id-token-jwk")) {
return "code-flow-encrypted-id-token-jwk";
}
if (path.endsWith("code-flow-encrypted-id-token-pem")) {
return "code-flow-encrypted-id-token-pem";
}
if (path.endsWith("code-flow-form-post") || path.endsWith("code-flow-form-post/front-channel-logout")) {
return "code-flow-form-post";
}
if (path.endsWith("code-flow-user-info-only")) {
return "code-flow-user-info-only";
}
if (path.endsWith("code-flow-user-info-github")) {
return "code-flow-user-info-github";
}
if (path.endsWith("bearer-user-info-github-service")) {
return "bearer-user-info-github-service";
}
if (path.endsWith("code-flow-user-info-github-cached-in-idtoken")) {
return "code-flow-user-info-github-cached-in-idtoken";
}
if (path.endsWith("code-flow-token-introspection")) {
return "code-flow-token-introspection";
}
if (path.endsWith("bearer")) {
return "bearer";
}
if (path.endsWith("bearer-id")) {
return "bearer-id";
}
if (path.endsWith("bearer-required-algorithm")) {
return "bearer-required-algorithm";
}
if (path.endsWith("bearer-azure")) {
return "bearer-azure";
}
if (path.endsWith("bearer-no-introspection")) {
return "bearer-no-introspection";
}
if (path.endsWith("bearer-role-claim-path")) {
return "bearer-role-claim-path";
}
if (path.endsWith("bearer-key-without-kid-thumbprint")) {
return "bearer-key-without-kid-thumbprint";
}
if (path.endsWith("bearer-wrong-role-path")) {
return "bearer-wrong-role-path";
}

return null;
}
}

0 comments on commit 72424a7

Please sign in to comment.