[KEYCLOAK-10168] Handle microprofile-jwt client scope migration
This commit is contained in:
parent
68d7abac3a
commit
f1acdc000e
12 changed files with 154 additions and 11 deletions
|
@ -41,6 +41,7 @@ import org.keycloak.migration.migrators.MigrateTo3_4_2;
|
|||
import org.keycloak.migration.migrators.MigrateTo4_0_0;
|
||||
import org.keycloak.migration.migrators.MigrateTo4_2_0;
|
||||
import org.keycloak.migration.migrators.MigrateTo4_6_0;
|
||||
import org.keycloak.migration.migrators.MigrateTo6_0_0;
|
||||
import org.keycloak.migration.migrators.Migration;
|
||||
import org.keycloak.models.KeycloakSession;
|
||||
import org.keycloak.models.RealmModel;
|
||||
|
@ -76,7 +77,8 @@ public class MigrationModelManager {
|
|||
new MigrateTo3_4_2(),
|
||||
new MigrateTo4_0_0(),
|
||||
new MigrateTo4_2_0(),
|
||||
new MigrateTo4_6_0()
|
||||
new MigrateTo4_6_0(),
|
||||
new MigrateTo6_0_0()
|
||||
};
|
||||
|
||||
public static void migrate(KeycloakSession session) {
|
||||
|
|
|
@ -61,4 +61,12 @@ public interface MigrationProvider extends Provider {
|
|||
*/
|
||||
ClientScopeModel addOIDCWebOriginsClientScope(RealmModel realm);
|
||||
|
||||
/**
|
||||
* Adds the {@code microprofile-jwt} optional client scope to the realm and returns the created scope. If the scope
|
||||
* already exists in the realm then the existing scope is returned.
|
||||
*
|
||||
* @param realm the realm to which the scope is to be added.
|
||||
* @return a reference to the {@code microprofile-jwt} client scope that was either created or already exists in the realm.
|
||||
*/
|
||||
ClientScopeModel addOIDCMicroprofileJWTClientScope(RealmModel realm);
|
||||
}
|
||||
|
|
|
@ -0,0 +1,74 @@
|
|||
/*
|
||||
* Copyright 2019 Red Hat, Inc. and/or its affiliates
|
||||
* and other contributors as indicated by the @author tags.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.keycloak.migration.migrators;
|
||||
|
||||
import org.jboss.logging.Logger;
|
||||
import org.keycloak.migration.MigrationProvider;
|
||||
import org.keycloak.migration.ModelVersion;
|
||||
import org.keycloak.models.ClientModel;
|
||||
import org.keycloak.models.ClientScopeModel;
|
||||
import org.keycloak.models.KeycloakSession;
|
||||
import org.keycloak.models.RealmModel;
|
||||
import org.keycloak.representations.idm.RealmRepresentation;
|
||||
|
||||
/**
|
||||
* Implements the migration necessary for version 6.0.0.
|
||||
*
|
||||
* @author <a href="mailto:sguilhen@redhat.com">Stefan Guilhen</a>
|
||||
*/
|
||||
public class MigrateTo6_0_0 implements Migration {
|
||||
|
||||
public static final ModelVersion VERSION = new ModelVersion("6.0.0");
|
||||
|
||||
private static final Logger LOG = Logger.getLogger(MigrateTo6_0_0.class);
|
||||
|
||||
@Override
|
||||
public ModelVersion getVersion() {
|
||||
return VERSION;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void migrate(KeycloakSession session) {
|
||||
session.realms().getRealms().stream().forEach(r -> {
|
||||
migrateRealm(session, r, false);
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public void migrateImport(KeycloakSession session, RealmModel realm, RealmRepresentation rep, boolean skipUserDependent) {
|
||||
migrateRealm(session, realm, true);
|
||||
}
|
||||
|
||||
protected void migrateRealm(KeycloakSession session, RealmModel realm, boolean jsn) {
|
||||
MigrationProvider migrationProvider = session.getProvider(MigrationProvider.class);
|
||||
|
||||
// create 'microprofile-jwt' optional client scope in the realm.
|
||||
ClientScopeModel mpJWTScope = migrationProvider.addOIDCMicroprofileJWTClientScope(realm);
|
||||
|
||||
LOG.debugf("Added '%s' optional client scope", mpJWTScope.getName());
|
||||
|
||||
// assign 'microprofile-jwt' optional client scope to all the OIDC clients.
|
||||
for (ClientModel client : realm.getClients()) {
|
||||
if ((client.getProtocol() == null || "openid-connect".equals(client.getProtocol())) && (!client.isBearerOnly())) {
|
||||
client.addClientScope(mpJWTScope, false);
|
||||
}
|
||||
}
|
||||
|
||||
LOG.debugf("Client scope '%s' assigned to all the clients", mpJWTScope.getName());
|
||||
}
|
||||
}
|
|
@ -267,15 +267,7 @@ public class OIDCLoginProtocolFactory extends AbstractLoginProtocolFactory {
|
|||
|
||||
addRolesClientScope(newRealm);
|
||||
addWebOriginsClientScope(newRealm);
|
||||
|
||||
ClientScopeModel microprofileScope = newRealm.addClientScope(MICROPROFILE_JWT_SCOPE);
|
||||
microprofileScope.setDescription("Microprofile - JWT built-in scope");
|
||||
microprofileScope.setDisplayOnConsentScreen(false);
|
||||
microprofileScope.setIncludeInTokenScope(true);
|
||||
microprofileScope.setProtocol(getId());
|
||||
microprofileScope.addProtocolMapper(builtins.get(UPN));
|
||||
microprofileScope.addProtocolMapper(builtins.get(GROUPS));
|
||||
newRealm.addDefaultClientScope(microprofileScope, false);
|
||||
addMicroprofileJWTClientScope(newRealm);
|
||||
}
|
||||
|
||||
|
||||
|
@ -322,6 +314,31 @@ public class OIDCLoginProtocolFactory extends AbstractLoginProtocolFactory {
|
|||
return originsScope;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds the {@code microprofile-jwt} optional client scope to the specified realm. If a {@code microprofile-jwt} client scope
|
||||
* already exists in the realm then the existing scope is returned. Otherwise, a new scope is created and returned.
|
||||
*
|
||||
* @param newRealm the realm to which the {@code microprofile-jwt} scope is to be added.
|
||||
* @return a reference to the {@code microprofile-jwt} client scope that was either created or already exists in the realm.
|
||||
*/
|
||||
public static ClientScopeModel addMicroprofileJWTClientScope(RealmModel newRealm) {
|
||||
ClientScopeModel microprofileScope = KeycloakModelUtils.getClientScopeByName(newRealm, MICROPROFILE_JWT_SCOPE);
|
||||
if (microprofileScope == null) {
|
||||
microprofileScope = newRealm.addClientScope(MICROPROFILE_JWT_SCOPE);
|
||||
microprofileScope.setDescription("Microprofile - JWT built-in scope");
|
||||
microprofileScope.setDisplayOnConsentScreen(false);
|
||||
microprofileScope.setIncludeInTokenScope(true);
|
||||
microprofileScope.setProtocol(OIDCLoginProtocol.LOGIN_PROTOCOL);
|
||||
microprofileScope.addProtocolMapper(builtins.get(UPN));
|
||||
microprofileScope.addProtocolMapper(builtins.get(GROUPS));
|
||||
newRealm.addDefaultClientScope(microprofileScope, false);
|
||||
} else {
|
||||
logger.debugf("Client scope '%s' already exists in realm '%s'. Skip creating it.", MICROPROFILE_JWT_SCOPE, newRealm.getName());
|
||||
}
|
||||
|
||||
return microprofileScope;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void addDefaults(ClientModel client) {
|
||||
}
|
||||
|
|
|
@ -96,6 +96,10 @@ public class DefaultMigrationProvider implements MigrationProvider {
|
|||
return OIDCLoginProtocolFactory.addWebOriginsClientScope(realm);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ClientScopeModel addOIDCMicroprofileJWTClientScope(RealmModel realm) {
|
||||
return OIDCLoginProtocolFactory.addMicroprofileJWTClientScope(realm);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() {
|
||||
|
|
|
@ -680,6 +680,7 @@ public class ExportImportUtil {
|
|||
OAuth2Constants.OFFLINE_ACCESS,
|
||||
OIDCLoginProtocolFactory.ROLES_SCOPE,
|
||||
OIDCLoginProtocolFactory.WEB_ORIGINS_SCOPE,
|
||||
OIDCLoginProtocolFactory.MICROPROFILE_JWT_SCOPE,
|
||||
SamlProtocolFactory.SCOPE_ROLE_LIST
|
||||
));
|
||||
|
||||
|
@ -708,7 +709,8 @@ public class ExportImportUtil {
|
|||
assertThat(optionalClientScopes, Matchers.hasItems(
|
||||
OAuth2Constants.SCOPE_ADDRESS,
|
||||
OAuth2Constants.SCOPE_PHONE,
|
||||
OAuth2Constants.OFFLINE_ACCESS
|
||||
OAuth2Constants.OFFLINE_ACCESS,
|
||||
OIDCLoginProtocolFactory.MICROPROFILE_JWT_SCOPE
|
||||
));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -232,6 +232,13 @@ public abstract class AbstractMigrationTest extends AbstractKeycloakTest {
|
|||
testRolesAndWebOriginsScopesAddedToClient();
|
||||
}
|
||||
|
||||
protected void testMigrationTo6_0_0() {
|
||||
// check that all expected scopes exist in the migrated realm.
|
||||
testRealmDefaultClientScopes(migrationRealm);
|
||||
// check that the 'microprofile-jwt' scope was added to the migrated clients.
|
||||
testMicroprofileJWTScopeAddedToClient();
|
||||
}
|
||||
|
||||
private void testGroupPolicyTypeFineGrainedAdminPermission() {
|
||||
ClientsResource clients = migrationRealm.clients();
|
||||
ClientRepresentation clientRepresentation = clients.findByClientId("realm-management").get(0);
|
||||
|
@ -519,6 +526,23 @@ public abstract class AbstractMigrationTest extends AbstractKeycloakTest {
|
|||
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the {@code microprofile-jwt} optional client scope has been added to the clients.
|
||||
*/
|
||||
private void testMicroprofileJWTScopeAddedToClient() {
|
||||
log.infof("Testing microprofile-jwt optional scope present in realm %s for client migration-test-client", migrationRealm.toRepresentation().getRealm());
|
||||
|
||||
List<ClientScopeRepresentation> optionalClientScopes = ApiUtil.findClientByClientId(this.migrationRealm, "migration-test-client").getOptionalClientScopes();
|
||||
|
||||
Set<String> defaultClientScopeNames = optionalClientScopes.stream()
|
||||
.map(ClientScopeRepresentation::getName)
|
||||
.collect(Collectors.toSet());
|
||||
|
||||
if (!defaultClientScopeNames.contains(OIDCLoginProtocolFactory.MICROPROFILE_JWT_SCOPE)) {
|
||||
Assert.fail("Client scope 'microprofile-jwt' not found as optional scope of client migration-test-client");
|
||||
}
|
||||
}
|
||||
|
||||
private void testRequiredActionsPriority(RealmResource... realms) {
|
||||
log.info("testing required action's priority");
|
||||
for (RealmResource realm : realms) {
|
||||
|
@ -572,4 +596,8 @@ public abstract class AbstractMigrationTest extends AbstractKeycloakTest {
|
|||
protected void testMigrationTo5_x() {
|
||||
// so far nothing
|
||||
}
|
||||
|
||||
protected void testMigrationTo6_x() {
|
||||
testMigrationTo6_0_0();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -74,6 +74,7 @@ public class JsonFileImport198MigrationTest extends AbstractJsonFileImportMigrat
|
|||
testMigrationTo3_x();
|
||||
testMigrationTo4_x(false, false);
|
||||
testMigrationTo5_x();
|
||||
testMigrationTo6_x();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -67,6 +67,7 @@ public class JsonFileImport255MigrationTest extends AbstractJsonFileImportMigrat
|
|||
testMigrationTo3_x();
|
||||
testMigrationTo4_x(true, false);
|
||||
testMigrationTo5_x();
|
||||
testMigrationTo6_x();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -66,6 +66,7 @@ public class JsonFileImport343MigrationTest extends AbstractJsonFileImportMigrat
|
|||
checkRealmsImported();
|
||||
testMigrationTo4_x(true, false);
|
||||
testMigrationTo5_x();
|
||||
testMigrationTo6_x();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -60,6 +60,7 @@ public class JsonFileImport483MigrationTest extends AbstractJsonFileImportMigrat
|
|||
public void migration4_8_3Test() throws Exception {
|
||||
checkRealmsImported();
|
||||
testMigrationTo5_x();
|
||||
testMigrationTo6_x();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -70,6 +70,7 @@ public class MigrationTest extends AbstractMigrationTest {
|
|||
public void migration4_xTest() {
|
||||
testMigratedData();
|
||||
testMigrationTo5_x();
|
||||
testMigrationTo6_x();
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -78,6 +79,7 @@ public class MigrationTest extends AbstractMigrationTest {
|
|||
testMigratedData();
|
||||
testMigrationTo4_x();
|
||||
testMigrationTo5_x();
|
||||
testMigrationTo6_x();
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -87,6 +89,7 @@ public class MigrationTest extends AbstractMigrationTest {
|
|||
testMigrationTo3_x();
|
||||
testMigrationTo4_x();
|
||||
testMigrationTo5_x();
|
||||
testMigrationTo6_x();
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -97,6 +100,7 @@ public class MigrationTest extends AbstractMigrationTest {
|
|||
testMigrationTo3_x();
|
||||
testMigrationTo4_x(false, false);
|
||||
testMigrationTo5_x();
|
||||
testMigrationTo6_x();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue