Details
diff --git a/model/api/src/main/java/org/keycloak/models/RealmModel.java b/model/api/src/main/java/org/keycloak/models/RealmModel.java
index 3b0b149..724d3b5 100755
--- a/model/api/src/main/java/org/keycloak/models/RealmModel.java
+++ b/model/api/src/main/java/org/keycloak/models/RealmModel.java
@@ -84,6 +84,8 @@ public interface RealmModel extends RoleContainerModel, RoleMapperModel, ScopeMa
UserModel addUser(String username);
+ boolean deleteUser(String name);
+
List<String> getDefaultRoles();
void addDefaultRole(String name);
diff --git a/model/jpa/src/main/java/org/keycloak/models/jpa/entities/UserEntity.java b/model/jpa/src/main/java/org/keycloak/models/jpa/entities/UserEntity.java
index d9c3a68..90d3341 100755
--- a/model/jpa/src/main/java/org/keycloak/models/jpa/entities/UserEntity.java
+++ b/model/jpa/src/main/java/org/keycloak/models/jpa/entities/UserEntity.java
@@ -2,6 +2,7 @@ package org.keycloak.models.jpa.entities;
import org.keycloak.models.UserModel;
+import javax.persistence.CascadeType;
import javax.persistence.CollectionTable;
import javax.persistence.Column;
import javax.persistence.ElementCollection;
@@ -33,6 +34,9 @@ import java.util.Set;
})
@Entity
public class UserEntity {
+
+ public static final Class[] RELATIONSHIPS = new Class[] { ApplicationUserRoleMappingEntity.class, RealmUserRoleMappingEntity.class, SocialLinkEntity.class };
+
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
protected String id;
@@ -66,7 +70,7 @@ public class UserEntity {
@CollectionTable
protected Set<String> redirectUris = new HashSet<String>();
- @OneToMany
+ @OneToMany(cascade = CascadeType.REMOVE, orphanRemoval = true)
protected Collection<CredentialEntity> credentials = new ArrayList<CredentialEntity>();
public String getId() {
diff --git a/model/jpa/src/main/java/org/keycloak/models/jpa/RealmAdapter.java b/model/jpa/src/main/java/org/keycloak/models/jpa/RealmAdapter.java
index 416d5eb..0d4813a 100755
--- a/model/jpa/src/main/java/org/keycloak/models/jpa/RealmAdapter.java
+++ b/model/jpa/src/main/java/org/keycloak/models/jpa/RealmAdapter.java
@@ -11,6 +11,7 @@ import org.keycloak.models.SocialLinkModel;
import org.keycloak.models.UserCredentialModel;
import org.keycloak.models.UserModel;
import org.keycloak.models.jpa.entities.ApplicationEntity;
+import org.keycloak.models.jpa.entities.ApplicationUserRoleMappingEntity;
import org.keycloak.models.jpa.entities.CredentialEntity;
import org.keycloak.models.jpa.entities.OAuthClientEntity;
import org.keycloak.models.jpa.entities.RealmEntity;
@@ -457,6 +458,25 @@ public class RealmAdapter implements RealmModel {
}
@Override
+ public boolean deleteUser(String name) {
+ TypedQuery<UserEntity> query = em.createNamedQuery("getRealmUserByLoginName", UserEntity.class);
+ query.setParameter("loginName", name);
+ query.setParameter("realm", realm);
+ List<UserEntity> results = query.getResultList();
+ if (results.size() == 0) return false;
+
+ UserEntity user = results.get(0);
+
+ for (Class r : UserEntity.RELATIONSHIPS) {
+ em.createQuery("delete from " + r.getSimpleName() + " where user = :user").setParameter("user", user).executeUpdate();
+ }
+
+ em.remove(user);
+
+ return true;
+ }
+
+ @Override
public List<String> getDefaultRoles() {
Collection<RoleEntity> entities = realm.getDefaultRoles();
List<String> roles = new ArrayList<String>();
diff --git a/model/picketlink/src/main/java/org/keycloak/models/picketlink/RealmAdapter.java b/model/picketlink/src/main/java/org/keycloak/models/picketlink/RealmAdapter.java
index 3279abf..83a6047 100755
--- a/model/picketlink/src/main/java/org/keycloak/models/picketlink/RealmAdapter.java
+++ b/model/picketlink/src/main/java/org/keycloak/models/picketlink/RealmAdapter.java
@@ -519,6 +519,16 @@ public class RealmAdapter implements RealmModel {
}
@Override
+ public boolean deleteUser(String name) {
+ User user = findPicketlinkUser(name);
+ if (user == null) {
+ return false;
+ }
+ getIdm().remove(user);
+ return true;
+ }
+
+ @Override
public RoleAdapter getRole(String name) {
Role role = SampleModel.getRole(getIdm(), name);
if (role == null) return null;
diff --git a/services/src/main/java/org/keycloak/services/resources/admin/UsersResource.java b/services/src/main/java/org/keycloak/services/resources/admin/UsersResource.java
index 830fef1..2f506b1 100755
--- a/services/src/main/java/org/keycloak/services/resources/admin/UsersResource.java
+++ b/services/src/main/java/org/keycloak/services/resources/admin/UsersResource.java
@@ -107,6 +107,13 @@ public class UsersResource {
return new RealmManager(session).toRepresentation(user);
}
+ @Path("{username}")
+ @DELETE
+ @NoCache
+ public void deleteUser(final @PathParam("username") String username) {
+ realm.deleteUser(username);
+ }
+
@GET
@NoCache
@Produces("application/json")
diff --git a/services/src/test/java/org/keycloak/test/AdapterTest.java b/services/src/test/java/org/keycloak/test/AdapterTest.java
index 4810aa2..ce44f4c 100755
--- a/services/src/test/java/org/keycloak/test/AdapterTest.java
+++ b/services/src/test/java/org/keycloak/test/AdapterTest.java
@@ -4,11 +4,13 @@ import org.junit.Assert;
import org.junit.FixMethodOrder;
import org.junit.Test;
import org.junit.runners.MethodSorters;
+import org.keycloak.models.ApplicationModel;
import org.keycloak.models.Constants;
import org.keycloak.models.OAuthClientModel;
import org.keycloak.models.RealmModel;
import org.keycloak.models.RequiredCredentialModel;
import org.keycloak.models.RoleModel;
+import org.keycloak.models.SocialLinkModel;
import org.keycloak.models.UserCredentialModel;
import org.keycloak.models.UserModel;
import org.keycloak.representations.idm.CredentialRepresentation;
@@ -174,6 +176,34 @@ public class AdapterTest extends AbstractKeycloakTest {
}
@Test
+ public void deleteUser() throws Exception {
+ test1CreateRealm();
+
+ UserModel user = realmModel.addUser("bburke");
+ user.setAttribute("attr1", "val1");
+ user.addRequiredAction(UserModel.RequiredAction.UPDATE_PASSWORD);
+
+ RoleModel testRole = realmModel.addRole("test");
+ realmModel.grantRole(user, testRole);
+
+ ApplicationModel app = realmModel.addApplication("test-app");
+ RoleModel appRole = app.addRole("test");
+ app.grantRole(user, appRole);
+
+ SocialLinkModel socialLink = new SocialLinkModel("google", user.getLoginName());
+ realmModel.addSocialLink(user, socialLink);
+
+ UserCredentialModel cred = new UserCredentialModel();
+ cred.setType(CredentialRepresentation.PASSWORD);
+ cred.setValue("password");
+ realmModel.updateCredential(user, cred);
+
+ Assert.assertTrue(realmModel.deleteUser("bburke"));
+ Assert.assertFalse(realmModel.deleteUser("bburke"));
+ Assert.assertNull(realmModel.getUser("bburke"));
+ }
+
+ @Test
public void testUserSearch() throws Exception {
test1CreateRealm();
{