diff --git a/model/api/src/main/java/org/keycloak/models/utils/RepresentationToModel.java b/model/api/src/main/java/org/keycloak/models/utils/RepresentationToModel.java index dfa2e46190..87c13a3e08 100755 --- a/model/api/src/main/java/org/keycloak/models/utils/RepresentationToModel.java +++ b/model/api/src/main/java/org/keycloak/models/utils/RepresentationToModel.java @@ -1044,35 +1044,14 @@ public class RepresentationToModel { user.addRequiredAction(UserModel.RequiredAction.valueOf(requiredAction)); } } - if (userRep.getCredentials() != null) { - for (CredentialRepresentation cred : userRep.getCredentials()) { - updateCredential(user, cred); - } - } + createCredentials(userRep, user); if (userRep.getFederatedIdentities() != null) { for (FederatedIdentityRepresentation identity : userRep.getFederatedIdentities()) { FederatedIdentityModel mappingModel = new FederatedIdentityModel(identity.getIdentityProvider(), identity.getUserId(), identity.getUserName()); session.users().addFederatedIdentity(newRealm, user, mappingModel); } } - if (userRep.getRealmRoles() != null) { - for (String roleString : userRep.getRealmRoles()) { - RoleModel role = newRealm.getRole(roleString.trim()); - if (role == null) { - role = newRealm.addRole(roleString.trim()); - } - user.grantRole(role); - } - } - if (userRep.getClientRoles() != null) { - for (Map.Entry> entry : userRep.getClientRoles().entrySet()) { - ClientModel client = clientMap.get(entry.getKey()); - if (client == null) { - throw new RuntimeException("Unable to find client role mappings for client: " + entry.getKey()); - } - createClientRoleMappings(client, user, entry.getValue()); - } - } + createRoleMappings(userRep, user, newRealm); if (userRep.getClientConsents() != null) { for (UserConsentRepresentation consentRep : userRep.getClientConsents()) { UserConsentModel consentModel = toModel(newRealm, consentRep); @@ -1100,6 +1079,14 @@ public class RepresentationToModel { return user; } + public static void createCredentials(UserRepresentation userRep, UserModel user) { + if (userRep.getCredentials() != null) { + for (CredentialRepresentation cred : userRep.getCredentials()) { + updateCredential(user, cred); + } + } + } + // Detect if it is "plain-text" or "hashed" representation and update model according to it private static void updateCredential(UserModel user, CredentialRepresentation cred) { if (cred.getValue() != null) { @@ -1142,6 +1129,28 @@ public class RepresentationToModel { // Role mappings + public static void createRoleMappings(UserRepresentation userRep, UserModel user, RealmModel realm) { + if (userRep.getRealmRoles() != null) { + for (String roleString : userRep.getRealmRoles()) { + RoleModel role = realm.getRole(roleString.trim()); + if (role == null) { + role = realm.addRole(roleString.trim()); + } + user.grantRole(role); + } + } + if (userRep.getClientRoles() != null) { + Map clientMap = realm.getClientNameMap(); + for (Map.Entry> entry : userRep.getClientRoles().entrySet()) { + ClientModel client = clientMap.get(entry.getKey()); + if (client == null) { + throw new RuntimeException("Unable to find client role mappings for client: " + entry.getKey()); + } + createClientRoleMappings(client, user, entry.getValue()); + } + } + } + public static void createClientRoleMappings(ClientModel clientModel, UserModel user, List roleNames) { if (user == null) { throw new RuntimeException("User not found"); diff --git a/services/src/main/java/org/keycloak/services/resources/KeycloakApplication.java b/services/src/main/java/org/keycloak/services/resources/KeycloakApplication.java index c26e60c821..88569b6d2c 100755 --- a/services/src/main/java/org/keycloak/services/resources/KeycloakApplication.java +++ b/services/src/main/java/org/keycloak/services/resources/KeycloakApplication.java @@ -9,10 +9,7 @@ import org.jboss.resteasy.spi.ResteasyProviderFactory; import org.keycloak.Config; import org.keycloak.exportimport.ExportImportManager; import org.keycloak.migration.MigrationModelManager; -import org.keycloak.models.KeycloakSession; -import org.keycloak.models.KeycloakSessionFactory; -import org.keycloak.models.RealmModel; -import org.keycloak.models.UserModel; +import org.keycloak.models.*; import org.keycloak.models.utils.PostMigrationEvent; import org.keycloak.models.utils.RepresentationToModel; import org.keycloak.representations.idm.RealmRepresentation; @@ -263,32 +260,46 @@ public class KeycloakApplication extends Application { if (addUserFile.isFile()) { log.info("Importing users from '" + addUserFile + "'"); - KeycloakSession session = sessionFactory.create(); + List realms; try { - session.getTransaction().begin(); + realms = JsonSerialization.readValue(new FileInputStream(addUserFile), new TypeReference>() { + }); + } catch (IOException e) { + log.errorv("Failed to load 'keycloak-add-user.json': {0}", e.getMessage()); + return; + } - List realms = JsonSerialization.readValue(new FileInputStream(addUserFile), new TypeReference>() {}); - for (RealmRepresentation r : realms) { - RealmModel realm = session.realms().getRealmByName(r.getRealm()); - if (realm == null) { - throw new Exception("Realm '" + r.getRealm() + "' not found"); - } + for (RealmRepresentation realmRep : realms) { + for (UserRepresentation userRep : realmRep.getUsers()) { + KeycloakSession session = sessionFactory.create(); + try { + session.getTransaction().begin(); - for (UserRepresentation u : r.getUsers()) { - RepresentationToModel.createUser(session, realm, u, realm.getClientNameMap()); + RealmModel realm = session.realms().getRealmByName(realmRep.getRealm()); + if (realm == null) { + log.errorv("Failed to add user ''{0}'' to realm ''{1}'': realm not found", userRep.getUsername(), realmRep.getRealm()); + } else { + UserModel user = session.users().addUser(realm, userRep.getUsername()); + user.setEnabled(userRep.isEnabled()); + RepresentationToModel.createCredentials(userRep, user); + RepresentationToModel.createRoleMappings(userRep, user, realm); + } + + session.getTransaction().commit(); + log.infov("Added user ''{0}'' to realm ''{1}''", userRep.getUsername(), realmRep.getRealm()); + } catch (ModelDuplicateException e) { + log.errorv("Failed to add user ''{0}'' to realm ''{1}'': user with username exists", userRep.getUsername(), realmRep.getRealm()); + } catch (Throwable t) { + session.getTransaction().rollback(); + log.errorv("Failed to add user ''{0}'' to realm ''{1}'': {2}", userRep.getUsername(), realmRep.getRealm(), t.getMessage()); + } finally { + session.close(); } } + } - session.getTransaction().commit(); - - if (!addUserFile.delete()) { - log.error("Failed to delete '" + addUserFile + "'"); - } - } catch (Throwable t) { - session.getTransaction().rollback(); - log.error("Failed to import users from '" + addUserFile + "'", t); - } finally { - session.close(); + if (!addUserFile.delete()) { + log.errorv("Failed to delete '{0}'", addUserFile.getAbsolutePath()); } } } diff --git a/testsuite/integration/src/test/java/org/keycloak/testsuite/adduser/AddUserTest.java b/testsuite/integration/src/test/java/org/keycloak/testsuite/adduser/AddUserTest.java index 17fa17434c..dea6ebcd6e 100644 --- a/testsuite/integration/src/test/java/org/keycloak/testsuite/adduser/AddUserTest.java +++ b/testsuite/integration/src/test/java/org/keycloak/testsuite/adduser/AddUserTest.java @@ -1,15 +1,28 @@ package org.keycloak.testsuite.adduser; +import org.codehaus.jackson.type.TypeReference; import org.junit.*; import org.junit.rules.TemporaryFolder; import org.keycloak.admin.client.Keycloak; +import org.keycloak.admin.client.resource.RealmResource; +import org.keycloak.admin.client.resource.RoleMappingResource; +import org.keycloak.admin.client.resource.RoleScopeResource; +import org.keycloak.admin.client.resource.UserResource; +import org.keycloak.common.util.Base64Url; import org.keycloak.models.Constants; -import org.keycloak.representations.idm.RealmRepresentation; +import org.keycloak.models.utils.Pbkdf2PasswordEncoder; +import org.keycloak.representations.idm.*; import org.keycloak.testsuite.KeycloakServer; +import org.keycloak.util.JsonSerialization; import org.keycloak.wildfly.adduser.AddUser; import java.io.File; +import java.io.FileInputStream; import java.io.IOException; +import java.util.Collections; +import java.util.List; + +import static org.junit.Assert.*; /** * @author Stian Thorgersen @@ -37,7 +50,16 @@ public class AddUserTest { @Test public void addUserTest() throws Throwable { AddUser.main(new String[]{"-u", "addusertest-admin", "-p", "password"}); - Assert.assertEquals(1, dir.listFiles().length); + assertEquals(1, dir.listFiles().length); + + List realms = JsonSerialization.readValue(new FileInputStream(new File(dir, "keycloak-add-user.json")), new TypeReference>() {}); + assertEquals(1, realms.size()); + assertEquals(1, realms.get(0).getUsers().size()); + + UserRepresentation user = realms.get(0).getUsers().get(0); + assertEquals(new Integer(100000), user.getCredentials().get(0).getHashIterations()); + assertNull(user.getCredentials().get(0).getValue()); + assertEquals(new Pbkdf2PasswordEncoder(Base64Url.decode(user.getCredentials().get(0).getSalt()), 100000).encode("password"), user.getCredentials().get(0).getHashedSaltedValue()); KeycloakServer server = new KeycloakServer(); try { @@ -53,12 +75,54 @@ public class AddUserTest { keycloak.realms().create(testRealm); + RealmResource realm = keycloak.realm("master"); + + List users = realm.users().search("addusertest-admin", null, null, null, null, null); + assertEquals(1, users.size()); + + UserRepresentation created = users.get(0); + assertNotNull(created.getCreatedTimestamp()); + + UserResource userResource = realm.users().get(created.getId()); + + List realmRoles = userResource.roles().realmLevel().listAll(); + + assertRoles(realmRoles, "admin", "offline_access"); + + List clients = realm.clients().findAll(); + String accountId = null; + for (ClientRepresentation c : clients) { + if (c.getClientId().equals("account")) { + accountId = c.getId(); + } + } + + List accountRoles = userResource.roles().clientLevel(accountId).listAll(); + + assertRoles(accountRoles, "view-profile", "manage-account"); + keycloak.close(); - Assert.assertEquals(0, dir.listFiles().length); + assertEquals(0, dir.listFiles().length); } finally { server.stop(); } } + public static void assertRoles(List actual, String... expected) { + assertEquals(expected.length, actual.size()); + + for (String e : expected) { + boolean found = false; + for (RoleRepresentation r : actual) { + if (r.getName().equals(e)) { + found = true; + } + } + if (!found) { + fail("Role " + e + " not found"); + } + } + } + } diff --git a/wildfly/adduser/src/main/java/org/keycloak/wildfly/adduser/AddUser.java b/wildfly/adduser/src/main/java/org/keycloak/wildfly/adduser/AddUser.java index ff4cf35eed..7be53c6473 100644 --- a/wildfly/adduser/src/main/java/org/keycloak/wildfly/adduser/AddUser.java +++ b/wildfly/adduser/src/main/java/org/keycloak/wildfly/adduser/AddUser.java @@ -154,9 +154,9 @@ public class AddUser { roles = rolesString.split(","); } else { if (realmName.equals("master")) { - roles = new String[] { "admin", "account/manage-account" }; + roles = new String[] { "admin" }; } else { - roles = new String[] { "realm-management/realm-admin", "account/manage-account" }; + roles = new String[] { "realm-management/realm-admin" }; } }