Run import within the context of the realm being imported
Closes #12289
This commit is contained in:
parent
74b2541d10
commit
ddcf0f45f9
3 changed files with 235 additions and 82 deletions
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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) {
|
||||
|
||||
|
|
|
@ -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"
|
||||
}
|
||||
}
|
Loading…
Reference in a new issue