Run import within the context of the realm being imported

Closes #12289
This commit is contained in:
Pedro Igor 2022-08-24 20:11:21 -03:00 committed by Marek Posolda
parent 74b2541d10
commit ddcf0f45f9
3 changed files with 235 additions and 82 deletions

View file

@ -507,101 +507,109 @@ public class RealmManager {
} else {
ReservedCharValidator.validate(id);
}
RealmModel realm = model.createRealm(id, rep.getRealm());
ReservedCharValidator.validate(rep.getRealm());
realm.setName(rep.getRealm());
RealmModel currentRealm = session.getContext().getRealm();
// setup defaults
try {
session.getContext().setRealm(realm);
ReservedCharValidator.validate(rep.getRealm());
realm.setName(rep.getRealm());
setupRealmDefaults(realm);
// setup defaults
if (rep.getDefaultRole() == null) {
KeycloakModelUtils.setupDefaultRole(realm, determineDefaultRoleName(rep));
} else {
realm.setDefaultRole(RepresentationToModel.createRole(realm, rep.getDefaultRole()));
}
setupRealmDefaults(realm);
boolean postponeMasterClientSetup = postponeMasterClientSetup(rep);
if (!postponeMasterClientSetup) {
setupMasterAdminManagement(realm);
}
if (rep.getDefaultRole() == null) {
KeycloakModelUtils.setupDefaultRole(realm, determineDefaultRoleName(rep));
} else {
realm.setDefaultRole(RepresentationToModel.createRole(realm, rep.getDefaultRole()));
}
if (!hasRealmAdminManagementClient(rep)) setupRealmAdminManagement(realm);
if (!hasAccountManagementClient(rep)) setupAccountManagement(realm);
boolean postponeMasterClientSetup = postponeMasterClientSetup(rep);
if (!postponeMasterClientSetup) {
setupMasterAdminManagement(realm);
}
boolean postponeImpersonationSetup = hasRealmAdminManagementClient(rep);
if (!postponeImpersonationSetup) {
setupImpersonationService(realm);
}
if (!hasRealmAdminManagementClient(rep)) setupRealmAdminManagement(realm);
if (!hasAccountManagementClient(rep)) setupAccountManagement(realm);
if (!hasBrokerClient(rep)) setupBrokerService(realm);
if (!hasAdminConsoleClient(rep)) setupAdminConsole(realm);
boolean postponeImpersonationSetup = hasRealmAdminManagementClient(rep);
if (!postponeImpersonationSetup) {
setupImpersonationService(realm);
}
boolean postponeAdminCliSetup = false;
if (!hasAdminCliClient(rep)) {
postponeAdminCliSetup = hasRealmAdminManagementClient(rep);
if(!postponeAdminCliSetup) {
if (!hasBrokerClient(rep)) setupBrokerService(realm);
if (!hasAdminConsoleClient(rep)) setupAdminConsole(realm);
boolean postponeAdminCliSetup = false;
if (!hasAdminCliClient(rep)) {
postponeAdminCliSetup = hasRealmAdminManagementClient(rep);
if(!postponeAdminCliSetup) {
setupAdminCli(realm);
}
}
if (!hasRealmRole(rep, Constants.OFFLINE_ACCESS_ROLE) || !hasClientScope(rep, Constants.OFFLINE_ACCESS_ROLE)) {
setupOfflineTokens(realm, rep);
}
if (rep.getClientScopes() == null) {
createDefaultClientScopes(realm);
}
RepresentationToModel.importRealm(session, rep, realm, skipUserDependent);
setupClientServiceAccountsAndAuthorizationOnImport(rep, skipUserDependent);
setupAdminConsoleLocaleMapper(realm);
if (postponeMasterClientSetup) {
setupMasterAdminManagement(realm);
}
if (rep.getRoles() != null || hasRealmAdminManagementClient(rep)) {
// Assert all admin roles are available once import took place. This is needed due to import from previous version where JSON file may not contain all admin roles
checkMasterAdminManagementRoles(realm);
checkRealmAdminManagementRoles(realm);
}
// Could happen when migrating from older version and I have exported JSON file, which contains "realm-management" client but not "impersonation" client
// I need to postpone impersonation because it needs "realm-management" client and its roles set
if (postponeImpersonationSetup) {
setupImpersonationService(realm);
}
if (postponeAdminCliSetup) {
setupAdminCli(realm);
}
setupAuthenticationFlows(realm);
setupRequiredActions(realm);
if (!hasRealmRole(rep, AccountRoles.DELETE_ACCOUNT)) {
KeycloakModelUtils.setupDeleteAccount(realm.getClientByClientId(Constants.ACCOUNT_MANAGEMENT_CLIENT_ID));
}
// Refresh periodic sync tasks for configured storageProviders
LegacyStoreSyncEvent.fire(session, realm, false);
setupAuthorizationServices(realm);
setupClientRegistrations(realm);
if (rep.getKeycloakVersion() != null) {
LegacyStoreMigrateRepresentationEvent.fire(session, realm, rep, skipUserDependent);
}
session.clientPolicy().updateRealmModelFromRepresentation(realm, rep);
fireRealmPostCreate(realm);
} finally {
session.getContext().setRealm(currentRealm);
}
if (!hasRealmRole(rep, Constants.OFFLINE_ACCESS_ROLE) || !hasClientScope(rep, Constants.OFFLINE_ACCESS_ROLE)) {
setupOfflineTokens(realm, rep);
}
if (rep.getClientScopes() == null) {
createDefaultClientScopes(realm);
}
RepresentationToModel.importRealm(session, rep, realm, skipUserDependent);
setupClientServiceAccountsAndAuthorizationOnImport(rep, skipUserDependent);
setupAdminConsoleLocaleMapper(realm);
if (postponeMasterClientSetup) {
setupMasterAdminManagement(realm);
}
if (rep.getRoles() != null || hasRealmAdminManagementClient(rep)) {
// Assert all admin roles are available once import took place. This is needed due to import from previous version where JSON file may not contain all admin roles
checkMasterAdminManagementRoles(realm);
checkRealmAdminManagementRoles(realm);
}
// Could happen when migrating from older version and I have exported JSON file, which contains "realm-management" client but not "impersonation" client
// I need to postpone impersonation because it needs "realm-management" client and its roles set
if (postponeImpersonationSetup) {
setupImpersonationService(realm);
}
if (postponeAdminCliSetup) {
setupAdminCli(realm);
}
setupAuthenticationFlows(realm);
setupRequiredActions(realm);
if (!hasRealmRole(rep, AccountRoles.DELETE_ACCOUNT)) {
KeycloakModelUtils.setupDeleteAccount(realm.getClientByClientId(Constants.ACCOUNT_MANAGEMENT_CLIENT_ID));
}
// Refresh periodic sync tasks for configured storageProviders
LegacyStoreSyncEvent.fire(session, realm, false);
setupAuthorizationServices(realm);
setupClientRegistrations(realm);
if (rep.getKeycloakVersion() != null) {
LegacyStoreMigrateRepresentationEvent.fire(session, realm, rep, skipUserDependent);
}
session.clientPolicy().updateRealmModelFromRepresentation(realm, rep);
fireRealmPostCreate(realm);
return realm;
}

View file

@ -25,6 +25,8 @@ import org.junit.runners.MethodSorters;
import org.keycloak.authorization.AuthorizationProvider;
import org.keycloak.authorization.model.ResourceServer;
import org.keycloak.common.Profile;
import org.keycloak.exportimport.Strategy;
import org.keycloak.exportimport.util.ImportUtils;
import org.keycloak.models.ClientModel;
import org.keycloak.models.Constants;
import org.keycloak.models.KeycloakSession;
@ -35,12 +37,22 @@ import org.keycloak.testsuite.AbstractTestRealmKeycloakTest;
import org.keycloak.testsuite.ProfileAssume;
import org.keycloak.testsuite.arquillian.annotation.AuthServerContainerExclude;
import org.keycloak.testsuite.arquillian.annotation.AuthServerContainerExclude.AuthServer;
import org.keycloak.testsuite.arquillian.annotation.EnableFeature;
import org.keycloak.testsuite.runonserver.RunOnServerException;
import org.keycloak.userprofile.UserProfileProvider;
import org.keycloak.userprofile.config.UPAttribute;
import org.keycloak.userprofile.config.UPAttributeSelector;
import org.keycloak.userprofile.config.UPConfig;
import org.keycloak.userprofile.config.UPConfigUtils;
import org.keycloak.util.JsonSerialization;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.util.Collection;
import java.util.Objects;
import java.util.concurrent.atomic.AtomicReference;
import java.util.stream.Collectors;
import static org.keycloak.testsuite.admin.AbstractAdminTest.loadJson;
@ -138,6 +150,38 @@ public class ImportTest extends AbstractTestRealmKeycloakTest {
});
}
@Test
@EnableFeature(Profile.Feature.DECLARATIVE_USER_PROFILE)
public void importUserProfile() throws Exception {
final String realmString = IOUtils.toString(getClass().getResourceAsStream("/model/import-userprofile.json"), StandardCharsets.UTF_8);
testingClient.server().run(session -> {
RealmRepresentation realmRep = JsonSerialization.readValue(realmString, RealmRepresentation.class);
// make sure the import happens within the context of the realm being imported
session.getContext().setRealm(null);
ImportUtils.importRealm(session, realmRep, Strategy.OVERWRITE_EXISTING, true);
RealmModel realm = session.realms().getRealmByName(realmRep.getRealm());
session.getContext().setRealm(realm);
UserProfileProvider provider = session.getProvider(UserProfileProvider.class);
UPConfig config = UPConfigUtils.readConfig(new ByteArrayInputStream(provider.getConfiguration().getBytes()));
Assert.assertTrue(config.getAttributes().stream().map(UPAttribute::getName).anyMatch("email"::equals));
Assert.assertTrue(config.getAttributes().stream().map(UPAttribute::getName).anyMatch("test"::equals));
Assert.assertTrue(config.getAttributes().stream().map(UPAttribute::getSelector)
.filter(Objects::nonNull)
.map(UPAttributeSelector::getScopes)
.filter(Objects::nonNull)
.flatMap(Collection::stream)
.collect(Collectors.toList())
.contains("microprofile-jwt")
);
});
}
@Override
public void configureTestRealm(RealmRepresentation testRealmParm) {

View file

@ -0,0 +1,101 @@
{
"realm": "user-profile",
"enabled": true,
"accessTokenLifespan": 3000,
"accessCodeLifespan": 10,
"accessCodeLifespanUserAction": 6000,
"sslRequired": "external",
"registrationAllowed": false,
"privateKey": "MIICXAIBAAKBgQCrVrCuTtArbgaZzL1hvh0xtL5mc7o0NqPVnYXkLvgcwiC3BjLGw1tGEGoJaXDuSaRllobm53JBhjx33UNv+5z/UMG4kytBWxheNVKnL6GgqlNabMaFfPLPCF8kAgKnsi79NMo+n6KnSY8YeUmec/p2vjO2NjsSAVcWEQMVhJ31LwIDAQABAoGAfmO8gVhyBxdqlxmIuglbz8bcjQbhXJLR2EoS8ngTXmN1bo2L90M0mUKSdc7qF10LgETBzqL8jYlQIbt+e6TH8fcEpKCjUlyq0Mf/vVbfZSNaVycY13nTzo27iPyWQHK5NLuJzn1xvxxrUeXI6A2WFpGEBLbHjwpx5WQG9A+2scECQQDvdn9NE75HPTVPxBqsEd2z10TKkl9CZxu10Qby3iQQmWLEJ9LNmy3acvKrE3gMiYNWb6xHPKiIqOR1as7L24aTAkEAtyvQOlCvr5kAjVqrEKXalj0Tzewjweuxc0pskvArTI2Oo070h65GpoIKLc9jf+UA69cRtquwP93aZKtW06U8dQJAF2Y44ks/mK5+eyDqik3koCI08qaC8HYq2wVl7G2QkJ6sbAaILtcvD92ToOvyGyeE0flvmDZxMYlvaZnaQ0lcSQJBAKZU6umJi3/xeEbkJqMfeLclD27XGEFoPeNrmdx0q10Azp4NfJAY+Z8KRyQCR2BEG+oNitBOZ+YXF9KCpH3cdmECQHEigJhYg+ykOvr1aiZUMFT72HU0jnmQe2FVekuG+LJUt2Tm7GtMjTFoGpf0JwrVuZN39fOYAlo+nTixgeW7X8Y=",
"publicKey": "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCrVrCuTtArbgaZzL1hvh0xtL5mc7o0NqPVnYXkLvgcwiC3BjLGw1tGEGoJaXDuSaRllobm53JBhjx33UNv+5z/UMG4kytBWxheNVKnL6GgqlNabMaFfPLPCF8kAgKnsi79NMo+n6KnSY8YeUmec/p2vjO2NjsSAVcWEQMVhJ31LwIDAQAB",
"requiredCredentials": [ "password" ],
"users" : [
{
"username" : "bburke@redhat.com",
"enabled": true,
"email" : "bburke@redhat.com",
"firstName": "Bill",
"lastName": "Burke",
"credentials" : [
{ "type" : "password",
"value" : "password" }
],
"realmRoles": ["user"],
"applicationRoles": {
"account": [ "manage-account" ]
}
}
],
"roles" : {
"realm" : [
{
"name": "user",
"description": "User privileges"
},
{
"name": "admin",
"description": "Administrator privileges"
}
]
},
"scopeMappings": [
{
"client": "third-party",
"roles": ["user"]
},
{
"client": "customer-portal",
"roles": ["user"]
},
{
"client": "product-portal",
"roles": ["user"]
}
],
"applications": [
{
"name": "customer-portal",
"enabled": true,
"adminUrl": "http://localhost:8080/customer-portal",
"redirectUris": [
"http://localhost:8080/customer-portal/*"
],
"secret": "password"
},
{
"name": "product-portal",
"enabled": true,
"adminUrl": "http://localhost:8080/product-portal",
"redirectUris": [
"http://localhost:8080/product-portal/*"
],
"secret": "password"
}
],
"oauthClients": [
{
"name": "third-party",
"enabled": true,
"redirectUris": [
"http://localhost:8080/oauth-client/*",
"http://localhost:8080/oauth-client-cdi/*"
],
"secret": "password"
}
],
"components": {
"org.keycloak.userprofile.UserProfileProvider" : [ {
"providerId" : "declarative-user-profile",
"subComponents" : { },
"config" : {
"config-pieces-count" : [ "1" ],
"config-piece-0" : [ "{\"attributes\":[{\"name\":\"username\",\"displayName\":\"${username}\",\"validations\":{\"length\":{\"min\":3,\"max\":255},\"username-prohibited-characters\":{}}},{\"name\":\"email\",\"displayName\":\"${email}\",\"validations\":{\"email\":{},\"length\":{\"max\":255}}},{\"name\":\"firstName\",\"displayName\":\"${firstName}\",\"permissions\":{\"view\":[\"user\",\"admin\"],\"edit\":[\"user\",\"admin\"]},\"validations\":{\"length\":{\"max\":255},\"person-name-prohibited-characters\":{}},\"selector\":{\"scopes\":[]},\"required\":{}},{\"name\":\"lastName\",\"displayName\":\"${lastName}\",\"permissions\":{\"view\":[\"user\",\"admin\"],\"edit\":[\"user\",\"admin\"]},\"validations\":{\"length\":{\"max\":255},\"person-name-prohibited-characters\":{}},\"selector\":{\"scopes\":[]}},{\"selector\":{\"scopes\":[\"microprofile-jwt\"]},\"permissions\":{\"view\":[],\"edit\":[]},\"name\":\"test\"}]}" ]
}
} ]
},
"attributes" : {
"userProfileEnabled" : "true"
}
}