Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Always set OIDC tenant id and document how to access it in Hibernate and Mongo resolvers #44547

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 10 additions & 4 deletions docs/src/main/asciidoc/hibernate-orm.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -1159,27 +1159,33 @@ From the implementation above, tenants are resolved from the request path so tha

[NOTE]
====
If you also use xref:security-openid-connect-multitenancy.adoc[OIDC multitenancy] and both OIDC and Hibernate ORM tenant IDs are the same and must be extracted from the Vert.x `RoutingContext` then you can pass the tenant id from the OIDC Tenant Resolver to the Hibernate ORM Tenant Resolver as a `RoutingContext` attribute, for example:
If you also use xref:security-openid-connect-multitenancy.adoc[OIDC multitenancy] and both OIDC and Hibernate ORM tenant IDs are the same,
you can get the OIDC tenant id from a `RoutingContext` attribute like in the example below:

[source,java]
----
import io.quarkus.hibernate.orm.runtime.tenant.TenantResolver;
import io.quarkus.oidc.runtime.OidcUtils;
import io.vertx.ext.web.RoutingContext;

@PersistenceUnitExtension
@RequestScoped
public class CustomTenantResolver implements TenantResolver {

@Inject
RoutingContext context;
RoutingContext context; <1>
...
@Override
public String resolveTenantId() {
// OIDC TenantResolver has already calculated the tenant id and saved it as a RoutingContext `tenantId` attribute:
return context.get("tenantId");
// OIDC has saved the tenant id as the RoutingContext attribute:
return context.get(OidcUtils.TENANT_ID_ATTRIBUTE);
}
}
----
<1> If the Hibernate `TenantResolver` also resolves tenants when there is no active HTTP request,
for example when you query database from a scheduler, the `RoutingContext` CDI bean will not be available.
Please inject the `io.quarkus.vertx.http.runtime.CurrentVertxRequest` CDI bean instead and get the `RoutingContext` from this bean.

====

=== Configuring the application
Expand Down
8 changes: 4 additions & 4 deletions docs/src/main/asciidoc/mongodb-panache.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -1275,12 +1275,12 @@ and then `quarkus.mongodb.database` property.
[NOTE]
====
If you also use xref:security-openid-connect-multitenancy.adoc[OIDC multitenancy], then if the OIDC tenantID and MongoDB
database are the same and must be extracted from the Vert.x `RoutingContext` you can pass the tenant id from the OIDC `TenantResolver`
to the MongoDB with Panache `MongoDatabaseResolver` as a `RoutingContext` attribute, for example:
database are the same, you can access the OIDC tenant id from a `RoutingContext` attribute like in the example below:

[source,java]
----
import io.quarkus.mongodb.panache.common.MongoDatabaseResolver;
import io.quarkus.oidc.runtime.OidcUtils;
import io.vertx.ext.web.RoutingContext;

@RequestScoped
Expand All @@ -1291,8 +1291,8 @@ public class CustomMongoDatabaseResolver implements MongoDatabaseResolver {
...
@Override
public String resolve() {
// OIDC TenantResolver has already calculated the tenant id and saved it as a RoutingContext `tenantId` attribute:
return context.get("tenantId");
// OIDC has saved the tenant id as the RoutingContext attribute:
return context.get(OidcUtils.TENANT_ID_ATTRIBUTE);
}
}
----
Expand Down
20 changes: 4 additions & 16 deletions docs/src/main/asciidoc/security-openid-connect-multitenancy.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -329,22 +329,10 @@ A similar technique can be used with `TenantConfigResolver`, where a `tenant-id`

[NOTE]
====
If you also use xref:hibernate-orm.adoc#multitenancy[Hibernate ORM multitenancy] or xref:mongodb-panache.adoc#multitenancy[MongoDB with Panache multitenancy] and both tenant ids are the same
and must be extracted from the Vert.x `RoutingContext`, you can pass the tenant id from the OIDC Tenant Resolver to the Hibernate ORM Tenant Resolver or MongoDB with Panache Mongo Database Resolver
as a `RoutingContext` attribute, for example:

[source,java]
----
public class CustomTenantResolver implements TenantResolver {

@Override
public String resolve(RoutingContext context) {
String tenantId = extractTenantId(context);
context.put("tenantId", tenantId);
return tenantId;
}
}
----
If you also use Hibernate ORM multitenancy or MongoDB with Panache multitenancy and both tenant ids are the same,
you can get the tenant id from the `RoutingContext` attribute with `tenant-id`. You can find more information here:
* xref:hibernate-orm.adoc#multitenancy[Hibernate ORM multitenancy]
* xref:mongodb-panache.adoc#multitenancy[MongoDB with Panache multitenancy]
====

== Starting and configuring the Keycloak server
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -84,8 +84,12 @@ public OidcTenantConfig apply(OidcTenantConfig oidcTenantConfig) {
if (oidcTenantConfig == null) {
throw new OIDCException("Tenant configuration has not been resolved");
}
LOG.debugf("Resolved OIDC tenant id: %s", oidcTenantConfig.tenantId.orElse(OidcUtils.DEFAULT_TENANT_ID));
final String tenantId = oidcTenantConfig.tenantId.orElse(OidcUtils.DEFAULT_TENANT_ID);
LOG.debugf("Resolved OIDC tenant id: %s", tenantId);
context.put(OidcTenantConfig.class.getName(), oidcTenantConfig);
if (context.get(OidcUtils.TENANT_ID_ATTRIBUTE) == null) {
context.put(OidcUtils.TENANT_ID_ATTRIBUTE, tenantId);
}
return oidcTenantConfig;
};
});
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,7 @@ private String getTenant() {
return OidcUtils.TENANT_ID_ATTRIBUTE + "=" + routingContext.get(OidcUtils.TENANT_ID_ATTRIBUTE)
+ ", static.tenant.id=" + routingContext.get("static.tenant.id")
+ ", name=" + identity.getPrincipal().getName()
+ ", " + OidcUtils.TENANT_ID_SET_BY_ANNOTATION + "=" + routingContext.get(OidcUtils.TENANT_ID_ATTRIBUTE);
+ ", " + OidcUtils.TENANT_ID_SET_BY_ANNOTATION + "="
+ routingContext.get(OidcUtils.TENANT_ID_SET_BY_ANNOTATION);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,7 @@ private String getTenantInternal() {
return OidcUtils.TENANT_ID_ATTRIBUTE + "=" + routingContext.get(OidcUtils.TENANT_ID_ATTRIBUTE)
+ ", static.tenant.id=" + routingContext.get("static.tenant.id")
+ ", name=" + identity.getPrincipal().getName()
+ ", " + OidcUtils.TENANT_ID_SET_BY_ANNOTATION + "=" + routingContext.get(OidcUtils.TENANT_ID_ATTRIBUTE);
+ ", " + OidcUtils.TENANT_ID_SET_BY_ANNOTATION + "="
+ routingContext.get(OidcUtils.TENANT_ID_SET_BY_ANNOTATION);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -156,7 +156,7 @@ public void testMethodLevelAnnotation() {
RestAssured.given().auth().oauth2(token)
.when().get("/api/tenant-echo2/default")
.then().statusCode(200)
.body(Matchers.equalTo(("tenant-id=null, static.tenant.id=null, name=alice, "
.body(Matchers.equalTo(("tenant-id=Default, static.tenant.id=null, name=alice, "
+ OidcUtils.TENANT_ID_SET_BY_ANNOTATION + "=null")));
} finally {
server.stop();
Expand Down Expand Up @@ -388,7 +388,7 @@ public void testPolicyAppliedBeforeTenantAnnotationMatched() {
.when().get("/api/tenant-echo/http-security-policy-applies-all-same")
.then().statusCode(200)
.body(Matchers
.equalTo("tenant-id=null, static.tenant.id=hr, name=alice, tenant-id-set-by-annotation=null"));
.equalTo("tenant-id=hr, static.tenant.id=hr, name=alice, tenant-id-set-by-annotation=null"));
} finally {
server.stop();
}
Expand Down
Loading