MigrateTo25_0_0 does not complete within default transaction timeout
closes #29756 Signed-off-by: mposolda <mposolda@gmail.com>
This commit is contained in:
parent
f34a7c2af4
commit
ea1cdc10bd
7 changed files with 84 additions and 5 deletions
|
@ -1455,6 +1455,16 @@ public class RealmCacheSession implements CacheRealmProvider {
|
||||||
return assignedScopes;
|
return assignedScopes;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void addClientScopeToAllClients(RealmModel realm, ClientScopeModel clientScope, boolean defaultClientScope) {
|
||||||
|
getClientDelegate().addClientScopeToAllClients(realm, clientScope, defaultClientScope);
|
||||||
|
|
||||||
|
// This will make sure to all invalidate all clients dependent on clientScope
|
||||||
|
listInvalidations.add(realm.getId());
|
||||||
|
cache.clientScopeRemoval(realm.getId(), invalidations);
|
||||||
|
invalidationEvents.add(ClientScopeRemovedEvent.create(clientScope.getId(), realm.getId()));
|
||||||
|
}
|
||||||
|
|
||||||
// Don't cache ClientInitialAccessModel for now
|
// Don't cache ClientInitialAccessModel for now
|
||||||
@Override
|
@Override
|
||||||
public ClientInitialAccessModel createClientInitialAccessModel(RealmModel realm, int expiration, int count) {
|
public ClientInitialAccessModel createClientInitialAccessModel(RealmModel realm, int expiration, int count) {
|
||||||
|
|
|
@ -1093,6 +1093,18 @@ public class JpaRealmProvider implements RealmProvider, ClientProvider, ClientSc
|
||||||
em.flush();
|
em.flush();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void addClientScopeToAllClients(RealmModel realm, ClientScopeModel clientScope, boolean defaultClientScope) {
|
||||||
|
if (realm.equals(clientScope.getRealm())) {
|
||||||
|
em.createNamedQuery("addClientScopeToAllClients")
|
||||||
|
.setParameter("realmId", realm.getId())
|
||||||
|
.setParameter("clientScopeId", clientScope.getId())
|
||||||
|
.setParameter("clientProtocol", clientScope.getProtocol())
|
||||||
|
.setParameter("defaultScope", defaultClientScope)
|
||||||
|
.executeUpdate();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Map<String, ClientScopeModel> getClientScopes(RealmModel realm, ClientModel client, boolean defaultScope) {
|
public Map<String, ClientScopeModel> getClientScopes(RealmModel realm, ClientModel client, boolean defaultScope) {
|
||||||
// Defaults to openid-connect
|
// Defaults to openid-connect
|
||||||
|
|
|
@ -36,7 +36,8 @@ import jakarta.persistence.Table;
|
||||||
@NamedQuery(name="clientScopeClientMappingIdsByClient", query="select m.clientScopeId from ClientScopeClientMappingEntity m where m.clientId = :clientId and m.defaultScope = :defaultScope"),
|
@NamedQuery(name="clientScopeClientMappingIdsByClient", query="select m.clientScopeId from ClientScopeClientMappingEntity m where m.clientId = :clientId and m.defaultScope = :defaultScope"),
|
||||||
@NamedQuery(name="deleteClientScopeClientMapping", query="delete from ClientScopeClientMappingEntity where clientId = :clientId and clientScopeId = :clientScopeId"),
|
@NamedQuery(name="deleteClientScopeClientMapping", query="delete from ClientScopeClientMappingEntity where clientId = :clientId and clientScopeId = :clientScopeId"),
|
||||||
@NamedQuery(name="deleteClientScopeClientMappingByClient", query="delete from ClientScopeClientMappingEntity where clientId = :clientId"),
|
@NamedQuery(name="deleteClientScopeClientMappingByClient", query="delete from ClientScopeClientMappingEntity where clientId = :clientId"),
|
||||||
@NamedQuery(name="deleteClientScopeClientMappingByClientScope", query="delete from ClientScopeClientMappingEntity where clientScopeId = :clientScopeId")
|
@NamedQuery(name="deleteClientScopeClientMappingByClientScope", query="delete from ClientScopeClientMappingEntity where clientScopeId = :clientScopeId"),
|
||||||
|
@NamedQuery(name="addClientScopeToAllClients", query="insert into ClientScopeClientMappingEntity (clientScopeId, defaultScope, clientId) select :clientScopeId, :defaultScope, client.id from ClientEntity client where client.realmId = :realmId and client.bearerOnly <> true and client.protocol = :clientProtocol")
|
||||||
})
|
})
|
||||||
@Entity
|
@Entity
|
||||||
@Table(name="CLIENT_SCOPE_CLIENT")
|
@Table(name="CLIENT_SCOPE_CLIENT")
|
||||||
|
|
|
@ -56,11 +56,14 @@ public class MigrateTo25_0_0 implements Migration {
|
||||||
protected void migrateRealm(KeycloakSession session, RealmModel realm) {
|
protected void migrateRealm(KeycloakSession session, RealmModel realm) {
|
||||||
MigrationProvider migrationProvider = session.getProvider(MigrationProvider.class);
|
MigrationProvider migrationProvider = session.getProvider(MigrationProvider.class);
|
||||||
|
|
||||||
// create 'basic' client scope in the realm.
|
ClientScopeModel basicScope = KeycloakModelUtils.getClientScopeByName(realm, "basic");
|
||||||
ClientScopeModel basicScope = migrationProvider.addOIDCBasicClientScope(realm);
|
if (basicScope == null) {
|
||||||
|
// create 'basic' client scope in the realm.
|
||||||
|
basicScope = migrationProvider.addOIDCBasicClientScope(realm);
|
||||||
|
|
||||||
//add basic scope to existing clients
|
//add basic scope to all existing OIDC clients
|
||||||
realm.getClientsStream().forEach(c-> c.addClientScope(basicScope, true));
|
session.clients().addClientScopeToAllClients(realm, basicScope, true);
|
||||||
|
}
|
||||||
|
|
||||||
// offer a migration for persistent user sessions which was added in KC25
|
// offer a migration for persistent user sessions which was added in KC25
|
||||||
session.sessions().migrate(VERSION.toString());
|
session.sessions().migrate(VERSION.toString());
|
||||||
|
|
|
@ -273,6 +273,11 @@ public class ClientStorageManager implements ClientProvider {
|
||||||
localStorage().removeClientScope(realm, client, clientScope);
|
localStorage().removeClientScope(realm, client, clientScope);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void addClientScopeToAllClients(RealmModel realm, ClientScopeModel clientScope, boolean defaultClientScope) {
|
||||||
|
localStorage().addClientScopeToAllClients(realm, clientScope, defaultClientScope);
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Map<ClientModel, Set<String>> getAllRedirectUrisOfEnabledClients(RealmModel realm) {
|
public Map<ClientModel, Set<String>> getAllRedirectUrisOfEnabledClients(RealmModel realm) {
|
||||||
return localStorage().getAllRedirectUrisOfEnabledClients(realm);
|
return localStorage().getAllRedirectUrisOfEnabledClients(realm);
|
||||||
|
|
|
@ -124,6 +124,15 @@ public interface ClientProvider extends ClientLookupProvider, Provider {
|
||||||
*/
|
*/
|
||||||
void removeClientScope(RealmModel realm, ClientModel client, ClientScopeModel clientScope);
|
void removeClientScope(RealmModel realm, ClientModel client, ClientScopeModel clientScope);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add specified client scope to all non bearer-only clients in the realm, which have same protocol as specified client scope
|
||||||
|
*
|
||||||
|
* @param realm Realm
|
||||||
|
* @param clientScope client scope from the specified realm, which would be added to all clients
|
||||||
|
* @param defaultClientScope If true, then it will be added as "default" client scope. If false, then it will be added as "optional" client scope
|
||||||
|
*/
|
||||||
|
void addClientScopeToAllClients(RealmModel realm, ClientScopeModel clientScope, boolean defaultClientScope);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns a map of (rootUrl, {validRedirectUris}) for all enabled clients.
|
* Returns a map of (rootUrl, {validRedirectUris}) for all enabled clients.
|
||||||
* @param realm
|
* @param realm
|
||||||
|
|
|
@ -18,6 +18,7 @@ package org.keycloak.testsuite.migration;
|
||||||
|
|
||||||
import org.apache.http.impl.client.CloseableHttpClient;
|
import org.apache.http.impl.client.CloseableHttpClient;
|
||||||
import org.apache.http.impl.client.HttpClientBuilder;
|
import org.apache.http.impl.client.HttpClientBuilder;
|
||||||
|
import org.hamcrest.Matchers;
|
||||||
import org.keycloak.OAuth2Constants;
|
import org.keycloak.OAuth2Constants;
|
||||||
import org.keycloak.admin.client.resource.ClientResource;
|
import org.keycloak.admin.client.resource.ClientResource;
|
||||||
import org.keycloak.admin.client.resource.ClientsResource;
|
import org.keycloak.admin.client.resource.ClientsResource;
|
||||||
|
@ -47,6 +48,7 @@ import org.keycloak.models.utils.TimeBasedOTP;
|
||||||
import org.keycloak.protocol.oidc.OIDCConfigAttributes;
|
import org.keycloak.protocol.oidc.OIDCConfigAttributes;
|
||||||
import org.keycloak.protocol.oidc.OIDCLoginProtocolFactory;
|
import org.keycloak.protocol.oidc.OIDCLoginProtocolFactory;
|
||||||
import org.keycloak.protocol.saml.SamlConfigAttributes;
|
import org.keycloak.protocol.saml.SamlConfigAttributes;
|
||||||
|
import org.keycloak.protocol.saml.SamlProtocolFactory;
|
||||||
import org.keycloak.protocol.saml.util.ArtifactBindingUtils;
|
import org.keycloak.protocol.saml.util.ArtifactBindingUtils;
|
||||||
import org.keycloak.representations.AccessToken;
|
import org.keycloak.representations.AccessToken;
|
||||||
import org.keycloak.representations.RefreshToken;
|
import org.keycloak.representations.RefreshToken;
|
||||||
|
@ -422,6 +424,43 @@ public abstract class AbstractMigrationTest extends AbstractKeycloakTest {
|
||||||
protected void testMigrationTo25_0_0() {
|
protected void testMigrationTo25_0_0() {
|
||||||
// check that all expected scopes exist in the migrated realm.
|
// check that all expected scopes exist in the migrated realm.
|
||||||
testRealmDefaultClientScopes(migrationRealm);
|
testRealmDefaultClientScopes(migrationRealm);
|
||||||
|
testClientContainsExpectedClientScopes();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private void testClientContainsExpectedClientScopes() {
|
||||||
|
// Test OIDC client contains expected client scopes
|
||||||
|
ClientResource migrationTestOIDCClient = ApiUtil.findClientByClientId(migrationRealm, "migration-test-client");
|
||||||
|
List<String> defaultClientScopes = migrationTestOIDCClient.getDefaultClientScopes().stream()
|
||||||
|
.map(ClientScopeRepresentation::getName)
|
||||||
|
.collect(Collectors.toList());
|
||||||
|
List<String> optionalClientScopes = migrationTestOIDCClient.getOptionalClientScopes().stream()
|
||||||
|
.map(ClientScopeRepresentation::getName)
|
||||||
|
.collect(Collectors.toList());
|
||||||
|
|
||||||
|
assertThat(defaultClientScopes, Matchers.hasItems(
|
||||||
|
OIDCLoginProtocolFactory.BASIC_SCOPE,
|
||||||
|
OAuth2Constants.SCOPE_PROFILE,
|
||||||
|
OAuth2Constants.SCOPE_EMAIL
|
||||||
|
));
|
||||||
|
assertThat(optionalClientScopes, Matchers.hasItems(
|
||||||
|
OAuth2Constants.SCOPE_ADDRESS,
|
||||||
|
OAuth2Constants.OFFLINE_ACCESS,
|
||||||
|
OAuth2Constants.SCOPE_PHONE
|
||||||
|
));
|
||||||
|
|
||||||
|
// Test SAML client
|
||||||
|
ClientResource migrationTestSAMLClient = ApiUtil.findClientByClientId(migrationRealm, "migration-saml-client");
|
||||||
|
defaultClientScopes = migrationTestSAMLClient.getDefaultClientScopes().stream()
|
||||||
|
.map(ClientScopeRepresentation::getName)
|
||||||
|
.collect(Collectors.toList());
|
||||||
|
optionalClientScopes = migrationTestSAMLClient.getOptionalClientScopes().stream()
|
||||||
|
.map(ClientScopeRepresentation::getName)
|
||||||
|
.collect(Collectors.toList());
|
||||||
|
assertThat(defaultClientScopes, Matchers.hasItems(
|
||||||
|
SamlProtocolFactory.SCOPE_ROLE_LIST
|
||||||
|
));
|
||||||
|
Assert.assertTrue(optionalClientScopes.isEmpty());
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void testDeleteAccount(RealmResource realm) {
|
protected void testDeleteAccount(RealmResource realm) {
|
||||||
|
|
Loading…
Reference in a new issue