Skip to content

Commit

Permalink
breaking: Upgrade Keycloak to version 23
Browse files Browse the repository at this point in the history
  • Loading branch information
anarsultanov committed Nov 30, 2023
1 parent 66cb6c2 commit d18bd19
Show file tree
Hide file tree
Showing 11 changed files with 32 additions and 57 deletions.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -96,7 +96,7 @@ the created users will be tenantless and asked to create a new tenant.
To address this issue, this extension introduces the concept of `tenant-specific IDPs` and an additional authenticator that facilitates the creation of required memberships.

To configure an IDP as tenant-specific, tenants' IDs should be added to the `multi-tenancy.tenants` configuration attribute of the IDP as a **comma-separated list**.
This can be achieved using the standard [Keycloak REST API](https://www.keycloak.org/docs-api/22.0.5/rest-api/index.html#_identity_providers).
This can be achieved using the standard [Keycloak REST API](https://www.keycloak.org/docs-api/23.0.1/rest-api/index.html#_identity_providers).

> **_Note_**
> - _With tenant-specific IDP configuration, the IDP limits access to only the tenants listed in the configuration.
Expand Down
2 changes: 1 addition & 1 deletion pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
</licenses>

<properties>
<keycloak.version>22.0.5</keycloak.version>
<keycloak.version>23.0.1</keycloak.version>
</properties>

<dependencies>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,11 @@
import jakarta.persistence.EntityManager;
import jakarta.ws.rs.NotAuthorizedException;
import jakarta.ws.rs.NotFoundException;
import jakarta.ws.rs.core.Context;
import jakarta.ws.rs.core.HttpHeaders;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import org.keycloak.Config;
import org.keycloak.common.ClientConnection;
import org.keycloak.connections.jpa.JpaConnectionProvider;
import org.keycloak.jose.jws.JWSInput;
import org.keycloak.jose.jws.JWSInputException;
Expand All @@ -29,13 +26,6 @@

public abstract class AbstractAdminResource<T extends AdminAuth> {

@Context
protected ClientConnection clientConnection;

@Context
private HttpHeaders headers;

@Context
protected KeycloakSession session;

protected final RealmModel realm;
Expand All @@ -47,18 +37,20 @@ public abstract class AbstractAdminResource<T extends AdminAuth> {
protected TenantProvider tenantProvider;


public AbstractAdminResource(RealmModel realm) {
this.realm = realm;
public AbstractAdminResource(KeycloakSession session) {
this.session = session;
this.realm = session.getContext().getRealm();
setup();
}

public void setup() {
private void setup() {
setupAuth();
setupEvents();
setupProvider();
}

private void setupAuth() {
String tokenString = AppAuthManager.extractAuthorizationHeaderToken(headers);
var tokenString = AppAuthManager.extractAuthorizationHeaderToken(session.getContext().getRequestHeaders());

if (tokenString == null) {
throw new NotAuthorizedException("Bearer");
Expand All @@ -73,9 +65,9 @@ private void setupAuth() {
throw new NotAuthorizedException("Bearer token format error");
}

String realmName = token.getIssuer().substring(token.getIssuer().lastIndexOf('/') + 1);
RealmManager realmManager = new RealmManager(session);
RealmModel realm = realmManager.getRealmByName(realmName);
var realmName = token.getIssuer().substring(token.getIssuer().lastIndexOf('/') + 1);
var realmManager = new RealmManager(session);
var realm = realmManager.getRealmByName(realmName);

if (realm == null) {
throw new NotAuthorizedException("Unknown realm in token");
Expand All @@ -84,8 +76,8 @@ private void setupAuth() {
var bearerTokenAuthenticator = new BearerTokenAuthenticator(session);
bearerTokenAuthenticator.setRealm(realm);
bearerTokenAuthenticator.setUriInfo(session.getContext().getUri());
bearerTokenAuthenticator.setConnection(clientConnection);
bearerTokenAuthenticator.setHeaders(headers);
bearerTokenAuthenticator.setConnection(session.getContext().getConnection());
bearerTokenAuthenticator.setHeaders(session.getContext().getRequestHeaders());
AuthenticationManager.AuthResult authResult = bearerTokenAuthenticator.authenticate();
if (authResult == null) {
throw new NotAuthorizedException("Bearer");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,16 +35,16 @@
import org.eclipse.microprofile.openapi.annotations.responses.APIResponse;
import org.keycloak.events.admin.OperationType;
import org.keycloak.models.Constants;
import org.keycloak.models.RealmModel;
import org.keycloak.models.KeycloakSession;
import org.keycloak.models.UserModel;
import org.keycloak.models.utils.KeycloakModelUtils;

public class TenantInvitationsResource extends AbstractAdminResource<TenantAdminAuth> {

private final TenantModel tenant;

public TenantInvitationsResource(RealmModel realm, TenantModel tenant) {
super(realm);
public TenantInvitationsResource(KeycloakSession session, TenantModel tenant) {
super(session);
this.tenant = tenant;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,14 +24,14 @@
import org.eclipse.microprofile.openapi.annotations.responses.APIResponse;
import org.keycloak.events.admin.OperationType;
import org.keycloak.models.Constants;
import org.keycloak.models.RealmModel;
import org.keycloak.models.KeycloakSession;

public class TenantMembershipsResource extends AbstractAdminResource<TenantAdminAuth> {

private final TenantModel tenant;

public TenantMembershipsResource(RealmModel realm, TenantModel tenant) {
super(realm);
public TenantMembershipsResource(KeycloakSession session, TenantModel tenant) {
super(session);
this.tenant = tenant;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,16 +8,15 @@
import jakarta.ws.rs.Produces;
import jakarta.ws.rs.core.MediaType;
import org.eclipse.microprofile.openapi.annotations.Operation;
import org.jboss.resteasy.spi.ResteasyProviderFactory;
import org.keycloak.events.admin.OperationType;
import org.keycloak.models.RealmModel;
import org.keycloak.models.KeycloakSession;

public class TenantResource extends AbstractAdminResource<TenantAdminAuth> {

private final TenantModel tenant;

public TenantResource(RealmModel realm, TenantModel tenant) {
super(realm);
public TenantResource(KeycloakSession session, TenantModel tenant) {
super(session);
this.tenant = tenant;
}

Expand All @@ -40,17 +39,11 @@ public void deleteTenant() {

@Path("invitations")
public TenantInvitationsResource invitations() {
TenantInvitationsResource resource = new TenantInvitationsResource(realm, tenant);
ResteasyProviderFactory.getInstance().injectProperties(resource);
resource.setup();
return resource;
return new TenantInvitationsResource(session, tenant);
}

@Path("memberships")
public TenantMembershipsResource memberships() {
TenantMembershipsResource resource = new TenantMembershipsResource(realm, tenant);
ResteasyProviderFactory.getInstance().injectProperties(resource);
resource.setup();
return resource;
return new TenantMembershipsResource(session, tenant);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -22,15 +22,14 @@
import org.eclipse.microprofile.openapi.annotations.parameters.Parameter;
import org.eclipse.microprofile.openapi.annotations.parameters.RequestBody;
import org.eclipse.microprofile.openapi.annotations.responses.APIResponse;
import org.jboss.resteasy.spi.ResteasyProviderFactory;
import org.keycloak.events.admin.OperationType;
import org.keycloak.models.Constants;
import org.keycloak.models.RealmModel;
import org.keycloak.models.KeycloakSession;

public class TenantsResource extends AbstractAdminResource<TenantAdminAuth> {

public TenantsResource(RealmModel realm) {
super(realm);
public TenantsResource(KeycloakSession session) {
super(session);
}

@POST
Expand Down Expand Up @@ -77,10 +76,7 @@ public TenantResource getTenantResource(@PathParam("tenantId") String tenantId)
if (!auth.isTenantAdmin(model)) {
throw new NotAuthorizedException(String.format("Insufficient permission to access %s", tenantId));
} else {
TenantResource resource = new TenantResource(realm, model);
ResteasyProviderFactory.getInstance().injectProperties(resource);
resource.setup();
return resource;
return new TenantResource(session, model);
}
}
}
Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
package dev.sultanov.keycloak.multitenancy.resource;

import org.jboss.resteasy.spi.ResteasyProviderFactory;
import org.keycloak.models.KeycloakSession;
import org.keycloak.models.RealmModel;
import org.keycloak.services.resource.RealmResourceProvider;

public class TenantsResourceProvider implements RealmResourceProvider {
Expand All @@ -15,11 +13,7 @@ public TenantsResourceProvider(KeycloakSession session) {

@Override
public Object getResource() {
RealmModel realm = session.getContext().getRealm();
TenantsResource resource = new TenantsResource(realm);
ResteasyProviderFactory.getInstance().injectProperties(resource);
resource.setup();
return resource;
return new TenantsResource(session);
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ public class BaseIntegrationTest {
private static final Integer MAILHOG_HTTP_PORT = 8025;

private static final Network network = Network.newNetwork();
private static final KeycloakContainer keycloak = new KeycloakContainer("quay.io/keycloak/keycloak:22.0.5")
private static final KeycloakContainer keycloak = new KeycloakContainer("quay.io/keycloak/keycloak:23.0.1")
.withRealmImportFiles("/realm-export.json", "/idp-realm-export.json")
.withProviderClassesFrom("target/classes")
.withNetwork(network)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
import static org.assertj.core.api.Assertions.assertThat;

import com.microsoft.playwright.Page;
import com.microsoft.playwright.Page.GetByLabelOptions;
import com.microsoft.playwright.options.AriaRole;

public class SignInPage extends AbstractPage {
Expand All @@ -24,7 +25,7 @@ public SelectLoginMethodPage tryAnotherWay() {

public SignInPage fillCredentials(String email, String password) {
page.getByLabel("Email").fill(email);
page.getByLabel("Password").fill(password);
page.getByLabel("Password", new GetByLabelOptions().setExact(true)).fill(password);
return this;
}

Expand Down
1 change: 0 additions & 1 deletion src/test/resources/idp-realm-export.json
Original file line number Diff line number Diff line change
Expand Up @@ -1794,7 +1794,6 @@
"cibaInterval" : "5",
"realmReusableOtpCode" : "false"
},
"keycloakVersion" : "22.0.5",
"userManagedAccessAllowed" : false,
"clientProfiles" : {
"profiles" : [ ]
Expand Down

0 comments on commit d18bd19

Please sign in to comment.