diff --git a/examples/as7-eap-demo/server/src/main/webapp/saas/admin/js/controllers.js b/examples/as7-eap-demo/server/src/main/webapp/saas/admin/js/controllers.js index 62bfc708a7..cbe254a1a4 100755 --- a/examples/as7-eap-demo/server/src/main/webapp/saas/admin/js/controllers.js +++ b/examples/as7-eap-demo/server/src/main/webapp/saas/admin/js/controllers.js @@ -184,30 +184,14 @@ module.controller('RealmDetailCtrl', function($scope, Current, Realm, realm, $ht module.controller('UserListCtrl', function($scope, realm, User) { $scope.realm = realm; $scope.users = []; - $scope.query = "*"; - $scope.attribute = {}; - var params = {}; + //$scope.search = "Search..."; - $scope.addAttribute = function() { - console.log('queryAttribute'); - params[$scope.attribute.name] = $scope.attribute.value; - for (var key in params) { - $scope.query = " " + key + "=" +params[key]; - } - }; - - $scope.executeQuery = function() { - console.log('executeQuery'); - var parameters = angular.copy(params); + $scope.searchQuery = function() { + console.log('search: ' + $scope.search); + var parameters = { search : $scope.search }; parameters["realm"] = realm.id; $scope.users = User.query(parameters); }; - - $scope.clearQuery = function() { - params = {}; - $scopre.query = "*"; - $scope.users = []; - }; }); module.controller('UserDetailCtrl', function($scope, realm, user, User, $location, Dialog, Notifications) { @@ -224,37 +208,32 @@ module.controller('UserDetailCtrl', function($scope, realm, user, User, $locatio }, true); $scope.save = function() { - if ($scope.userForm.$valid) { - if ($scope.create) { - User.save({ - realm: realm.id - }, $scope.user, function () { - $scope.changed = false; - user = angular.copy($scope.user); + if ($scope.create) { + User.save({ + realm: realm.id + }, $scope.user, function () { + $scope.changed = false; + user = angular.copy($scope.user); - $location.url("/realms/" + realm.id + "/users/" + $scope.user.username); - Notifications.success("Created user"); - }); - } else { - User.update({ - realm: realm.id, - userId: $scope.user.username - }, $scope.user, function () { - $scope.changed = false; - user = angular.copy($scope.user); - Notifications.success("Saved changes to user"); - }); - - } + $location.url("/realms/" + realm.id + "/users/" + $scope.user.username); + Notifications.success("Created user"); + }); } else { - $scope.userForm.showErrors = true; - } + User.update({ + realm: realm.id, + userId: $scope.user.username + }, $scope.user, function () { + $scope.changed = false; + user = angular.copy($scope.user); + Notifications.success("Saved changes to user"); + }); + + } }; $scope.reset = function() { $scope.user = angular.copy(user); $scope.changed = false; - $scope.userForm.showErrors = false; }; $scope.cancel = function() { diff --git a/examples/as7-eap-demo/server/src/main/webapp/saas/admin/partials/application-list.html b/examples/as7-eap-demo/server/src/main/webapp/saas/admin/partials/application-list.html index 390e9323f4..4128751ace 100755 --- a/examples/as7-eap-demo/server/src/main/webapp/saas/admin/partials/application-list.html +++ b/examples/as7-eap-demo/server/src/main/webapp/saas/admin/partials/application-list.html @@ -14,7 +14,7 @@ Table of realm applications - +
+
-
- - -
- -
+
+ + +
-
- - -
- - Invalid email -
-
- -
- - -
- -
-
- -
- - -
- -
-
- - -
- Attributes - - - - - - - - - - - - -
NameValue
-
- -
- - -
- -
- - - -
- - + +
+ \ No newline at end of file diff --git a/examples/as7-eap-demo/server/src/main/webapp/saas/admin/partials/user-list.html b/examples/as7-eap-demo/server/src/main/webapp/saas/admin/partials/user-list.html index 59dd555185..3e1e104288 100755 --- a/examples/as7-eap-demo/server/src/main/webapp/saas/admin/partials/user-list.html +++ b/examples/as7-eap-demo/server/src/main/webapp/saas/admin/partials/user-list.html @@ -1,60 +1,61 @@
- -
- - -
-
-
- - -
- - -
-
-
- -
-
-
- - -
- - - -
-
-
-
- - - - - - - - - - - - - - - -
UsernameFirstnameLastnameEmail
{{user.username}}{{user.firstName}}{{user.lastName}}{{user.email}}
+
+
+
+ +
+
+

Query Users

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Table of realm users
+
+ + +
+
UsernameLast NameFirst NameEmail
+ +
{{user.username}}{{user.lastName{{user.firstName{{user.email
+
diff --git a/services/src/main/java/org/keycloak/services/managers/RealmManager.java b/services/src/main/java/org/keycloak/services/managers/RealmManager.java index 6fd1ee54d0..f23b917b1d 100755 --- a/services/src/main/java/org/keycloak/services/managers/RealmManager.java +++ b/services/src/main/java/org/keycloak/services/managers/RealmManager.java @@ -8,10 +8,7 @@ import org.keycloak.services.models.UserModel.RequiredAction; import java.security.KeyPair; import java.security.KeyPairGenerator; import java.security.NoSuchAlgorithmException; -import java.util.HashMap; -import java.util.HashSet; -import java.util.List; -import java.util.Map; +import java.util.*; import java.util.concurrent.atomic.AtomicLong; /** @@ -234,6 +231,66 @@ public class RealmManager { return user; } + /** + * Query users based on a search string: + * + * "Bill Burke" first and last name + * "bburke@redhat.com" email + * "Burke" lastname or username + * + * @param searchString + * @param realmModel + * @return + */ + public List searchUsers(String searchString, RealmModel realmModel) { + if (searchString == null) { + return Collections.emptyList(); + } + + String search = searchString.trim(); + if (search.contains(" ")) { //first and last name + String[] split = search.split(" "); + if (split.length != 2) { + return Collections.emptyList(); + } + Map attributes = new HashMap(); + attributes.put(UserModel.FIRST_NAME, split[0]); + attributes.put(UserModel.LAST_NAME, split[1]); + return realmModel.searchForUserByAttributes(attributes); + } else if (search.contains("@")) { // email + Map attributes = new HashMap(); + attributes.put(UserModel.EMAIL, search); + return realmModel.searchForUserByAttributes(attributes); + } else { // username and lastname + Map attributes = new HashMap(); + attributes.put(UserModel.LOGIN_NAME, search); + List usernameQuery = realmModel.searchForUserByAttributes(attributes); + attributes.clear(); + attributes.put(UserModel.LAST_NAME, search); + List lastnameQuery = realmModel.searchForUserByAttributes(attributes); + if (usernameQuery.size() == 0) { + return lastnameQuery; + } else if (lastnameQuery.size() == 0) { + return usernameQuery; + } + List results = new ArrayList(); + results.addAll(usernameQuery); + for (UserModel lastnameUser : lastnameQuery) { + boolean found = false; + for (UserModel usernameUser : usernameQuery) { + if (usernameUser.getLoginName().equals(lastnameUser.getLoginName())) { + found = true; + break; + } + } + if (!found) { + results.add(lastnameUser); + } + } + return results; + } + } + public void addRequiredCredential(RealmModel newRealm, String requiredCred) { newRealm.addRequiredCredential(requiredCred); } @@ -254,6 +311,18 @@ public class RealmManager { } } + public UserRepresentation toRepresentation(UserModel user) { + UserRepresentation rep = new UserRepresentation(); + rep.setUsername(user.getLoginName()); + rep.setLastName(user.getLastName()); + rep.setFirstName(user.getFirstName()); + rep.setEmail(user.getEmail()); + Map attrs = new HashMap(); + attrs.putAll(user.getAttributes()); + rep.setAttributes(attrs); + return rep; + } + public RoleRepresentation toRepresentation(RoleModel role) { RoleRepresentation rep = new RoleRepresentation(); rep.setId(role.getId()); diff --git a/services/src/main/java/org/keycloak/services/models/RealmModel.java b/services/src/main/java/org/keycloak/services/models/RealmModel.java index 9eaf1f5a4d..5deed17b83 100755 --- a/services/src/main/java/org/keycloak/services/models/RealmModel.java +++ b/services/src/main/java/org/keycloak/services/models/RealmModel.java @@ -150,4 +150,6 @@ public interface RealmModel { public boolean isAutomaticRegistrationAfterSocialLogin(); public void setAutomaticRegistrationAfterSocialLogin(boolean automaticRegistrationAfterSocialLogin); + + List searchForUserByAttributes(Map attributes); } diff --git a/services/src/main/java/org/keycloak/services/models/UserModel.java b/services/src/main/java/org/keycloak/services/models/UserModel.java index e0813b74d0..bab26e0831 100755 --- a/services/src/main/java/org/keycloak/services/models/UserModel.java +++ b/services/src/main/java/org/keycloak/services/models/UserModel.java @@ -8,6 +8,11 @@ import java.util.Map; * @version $Revision: 1 $ */ public interface UserModel { + public static final String LOGIN_NAME = "username"; + public static final String LAST_NAME = "lastName"; + public static final String FIRST_NAME = "firstName"; + public static final String EMAIL = "email"; + String getLoginName(); boolean isEnabled(); diff --git a/services/src/main/java/org/keycloak/services/models/picketlink/RealmAdapter.java b/services/src/main/java/org/keycloak/services/models/picketlink/RealmAdapter.java index 718efe4fe7..4fd3aa86be 100755 --- a/services/src/main/java/org/keycloak/services/models/picketlink/RealmAdapter.java +++ b/services/src/main/java/org/keycloak/services/models/picketlink/RealmAdapter.java @@ -777,4 +777,28 @@ public class RealmAdapter implements RealmModel { getRelationshipManager().remove(relationship); } + + @Override + public List searchForUserByAttributes(Map attributes) { + IdentityQuery query = getIdm().createIdentityQuery(User.class); + for (Map.Entry entry : attributes.entrySet()) { + if (entry.getKey().equals(UserModel.LOGIN_NAME)) { + query.setParameter(User.LOGIN_NAME, entry.getValue()); + } else if (entry.getKey().equalsIgnoreCase(UserModel.FIRST_NAME)) { + query.setParameter(User.FIRST_NAME, entry.getValue()); + + } else if (entry.getKey().equalsIgnoreCase(UserModel.LAST_NAME)) { + query.setParameter(User.LAST_NAME, entry.getValue()); + + } else if (entry.getKey().equalsIgnoreCase(UserModel.EMAIL)) { + query.setParameter(User.EMAIL, entry.getValue()); + } + } + List users = query.getResultList(); + List userModels = new ArrayList(); + for (User user : users) { + userModels.add(new UserAdapter(user, idm)); + } + return userModels; + } } diff --git a/services/src/main/java/org/keycloak/services/resources/admin/RealmAdminResource.java b/services/src/main/java/org/keycloak/services/resources/admin/RealmAdminResource.java index 5ed6520407..524b9f839f 100755 --- a/services/src/main/java/org/keycloak/services/resources/admin/RealmAdminResource.java +++ b/services/src/main/java/org/keycloak/services/resources/admin/RealmAdminResource.java @@ -17,7 +17,9 @@ import javax.ws.rs.core.Context; import javax.ws.rs.core.Response; import javax.ws.rs.core.UriInfo; import java.util.ArrayList; +import java.util.HashMap; import java.util.List; +import java.util.Map; /** * @author Bill Burke @@ -117,16 +119,94 @@ public class RealmAdminResource { return Response.created(uriInfo.getAbsolutePathBuilder().path(role.getId()).build()).build(); } + @Path("users/{username}") + @PUT + @Consumes("application/json") + public void updateUser(final @PathParam("username") String username, final UserRepresentation rep) { + UserModel user = realm.getUser(username); + if (user == null) { + throw new NotFoundException(); + } + user.setEmail(rep.getEmail()); + user.setFirstName(rep.getFirstName()); + user.setLastName(rep.getLastName()); + for (Map.Entry attr : rep.getAttributes().entrySet()) { + user.setAttribute(attr.getKey(), attr.getValue()); + } + } + + @Path("users") + @POST + @Consumes("application/json") + public Response createUser(final @Context UriInfo uriInfo, final UserRepresentation rep) { + if (realm.getUser(rep.getUsername()) != null) { + throw new InternalServerErrorException(); // todo appropriate status here. + } + UserModel user = realm.addUser(rep.getUsername()); + if (user == null) { + throw new NotFoundException(); + } + user.setEmail(rep.getEmail()); + user.setFirstName(rep.getFirstName()); + user.setLastName(rep.getLastName()); + if (rep.getAttributes() != null) { + for (Map.Entry attr : rep.getAttributes().entrySet()) { + user.setAttribute(attr.getKey(), attr.getValue()); + } + } + return Response.created(uriInfo.getAbsolutePathBuilder().path(user.getLoginName()).build()).build(); + } + + @Path("users/{username}") + @GET + @NoCache + @Produces("application/json") + public UserRepresentation getUser(final @PathParam("username") String username) { + UserModel user = realm.getUser(username); + if (user == null) { + throw new NotFoundException(); + } + return new RealmManager(session).toRepresentation(user); + } @Path("users") @GET @NoCache @Produces("application/json") - public List getUsers() { - return null; + public List getUsers(@QueryParam("search") String search, + @QueryParam("lastName") String last, + @QueryParam("firstName") String first, + @QueryParam("email") String email, + @QueryParam("username") String username) { + RealmManager manager = new RealmManager(session); + List results = new ArrayList(); + if (search != null) { + List userModels = manager.searchUsers(search, realm); + for (UserModel user : userModels) { + results.add(manager.toRepresentation(user)); + } + } else { + Map attributes = new HashMap(); + if (last != null) { + attributes.put(UserModel.LAST_NAME, last); + } + if (first != null) { + attributes.put(UserModel.FIRST_NAME, first); + } + if (email != null) { + attributes.put(UserModel.EMAIL, email); + } + if (username != null) { + attributes.put(UserModel.LOGIN_NAME, username); + } + List userModels = realm.searchForUserByAttributes(attributes); + for (UserModel user : userModels) { + results.add(manager.toRepresentation(user)); + } + + } + return results; } - - } diff --git a/services/src/test/java/org/keycloak/test/AdapterTest.java b/services/src/test/java/org/keycloak/test/AdapterTest.java index c37abc5f9c..015caac7fd 100755 --- a/services/src/test/java/org/keycloak/test/AdapterTest.java +++ b/services/src/test/java/org/keycloak/test/AdapterTest.java @@ -115,8 +115,7 @@ public class AdapterTest { if (cred.getType().equals(CredentialRepresentation.PASSWORD)) { password = true; Assert.assertTrue(cred.isSecret()); - } - else if (cred.getType().equals(CredentialRepresentation.TOTP)) { + } else if (cred.getType().equals(CredentialRepresentation.TOTP)) { totp = true; Assert.assertFalse(cred.isSecret()); } @@ -136,6 +135,118 @@ public class AdapterTest { Assert.assertTrue(realmModel.validatePassword(user, "geheim")); } + @Test + public void testUserSearch() throws Exception { + test1CreateRealm(); + { + UserModel user = realmModel.addUser("bburke"); + user.setLastName("Burke"); + user.setFirstName("Bill"); + user.setEmail("bburke@redhat.com"); + } + + { + List userModels = adapter.searchUsers("total junk query", realmModel); + Assert.assertEquals(userModels.size(), 0); + } + + { + List userModels = adapter.searchUsers("Bill Burke", realmModel); + Assert.assertEquals(userModels.size(), 1); + UserModel bburke = userModels.get(0); + Assert.assertEquals(bburke.getFirstName(), "Bill"); + Assert.assertEquals(bburke.getLastName(), "Burke"); + Assert.assertEquals(bburke.getEmail(), "bburke@redhat.com"); + } + + + { + List userModels = adapter.searchUsers("bburke@redhat.com", realmModel); + Assert.assertEquals(userModels.size(), 1); + UserModel bburke = userModels.get(0); + Assert.assertEquals(bburke.getFirstName(), "Bill"); + Assert.assertEquals(bburke.getLastName(), "Burke"); + Assert.assertEquals(bburke.getEmail(), "bburke@redhat.com"); + } + + { + List userModels = adapter.searchUsers("bburke", realmModel); + Assert.assertEquals(userModels.size(), 1); + UserModel bburke = userModels.get(0); + Assert.assertEquals(bburke.getFirstName(), "Bill"); + Assert.assertEquals(bburke.getLastName(), "Burke"); + Assert.assertEquals(bburke.getEmail(), "bburke@redhat.com"); + } + + { + List userModels = adapter.searchUsers("Burke", realmModel); + Assert.assertEquals(userModels.size(), 1); + UserModel bburke = userModels.get(0); + Assert.assertEquals(bburke.getFirstName(), "Bill"); + Assert.assertEquals(bburke.getLastName(), "Burke"); + Assert.assertEquals(bburke.getEmail(), "bburke@redhat.com"); + } + + { + UserModel user = realmModel.addUser("mburke"); + user.setLastName("Burke"); + user.setFirstName("Monica"); + user.setEmail("mburke@redhat.com"); + } + + { + UserModel user = realmModel.addUser("thor"); + user.setLastName("Thorgersen"); + user.setFirstName("Stian"); + user.setEmail("thor@redhat.com"); + } + + { + List userModels = adapter.searchUsers("Monica Burke", realmModel); + Assert.assertEquals(userModels.size(), 1); + UserModel bburke = userModels.get(0); + Assert.assertEquals(bburke.getFirstName(), "Monica"); + Assert.assertEquals(bburke.getLastName(), "Burke"); + Assert.assertEquals(bburke.getEmail(), "mburke@redhat.com"); + } + + + { + List userModels = adapter.searchUsers("mburke@redhat.com", realmModel); + Assert.assertEquals(userModels.size(), 1); + UserModel bburke = userModels.get(0); + Assert.assertEquals(bburke.getFirstName(), "Monica"); + Assert.assertEquals(bburke.getLastName(), "Burke"); + Assert.assertEquals(bburke.getEmail(), "mburke@redhat.com"); + } + + { + List userModels = adapter.searchUsers("mburke", realmModel); + Assert.assertEquals(userModels.size(), 1); + UserModel bburke = userModels.get(0); + Assert.assertEquals(bburke.getFirstName(), "Monica"); + Assert.assertEquals(bburke.getLastName(), "Burke"); + Assert.assertEquals(bburke.getEmail(), "mburke@redhat.com"); + } + + { + List userModels = adapter.searchUsers("Burke", realmModel); + Assert.assertEquals(userModels.size(), 2); + UserModel first = userModels.get(0); + UserModel second = userModels.get(1); + if (!first.getEmail().equals("bburke@redhat.com") && !second.getEmail().equals("bburke@redhat.com")) { + Assert.fail(); + } + if (!first.getEmail().equals("mburke@redhat.com") && !second.getEmail().equals("mburke@redhat.com")) { + Assert.fail(); + } + } + + + + } + + @Test public void testRoles() throws Exception { test1CreateRealm();