From e61833aa43324e1d01ee258122389feb55d3d602 Mon Sep 17 00:00:00 2001 From: Bill Burke Date: Thu, 19 Sep 2013 17:22:47 -0400 Subject: [PATCH] User screens --- .../main/webapp/saas/admin/js/controllers.js | 67 +++---- .../saas/admin/partials/application-list.html | 2 +- .../saas/admin/partials/realm-menu.html | 2 +- .../saas/admin/partials/user-detail.html | 179 +++++++++--------- .../webapp/saas/admin/partials/user-list.html | 113 +++++------ .../services/managers/RealmManager.java | 78 +++++++- .../keycloak/services/models/RealmModel.java | 2 + .../keycloak/services/models/UserModel.java | 1 + .../models/picketlink/RealmAdapter.java | 24 +++ .../resources/admin/RealmAdminResource.java | 90 ++++++++- .../java/org/keycloak/test/AdapterTest.java | 115 ++++++++++- 11 files changed, 468 insertions(+), 205 deletions(-) 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..79179ee73d 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,63 @@
- -
- - -
-
-
- - -
- - -
-
-
- -
-
-
- - -
- - - -
-
-
-
- - - - - - - - - - - - - - - -
UsernameFirstnameLastnameEmail
{{user.username}}{{user.firstName}}{{user.lastName}}{{user.email}}
+
+
+
+ +
+
+

Users

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Table of realm users
+
+ + +
+
EnabledUsernameLast NameFirst NameEmail
+ +
{{user.enabled}}{{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 cdbed7f54f..1e806b9f42 100755 --- a/services/src/main/java/org/keycloak/services/managers/RealmManager.java +++ b/services/src/main/java/org/keycloak/services/managers/RealmManager.java @@ -7,10 +7,7 @@ import org.keycloak.services.models.*; 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; /** @@ -223,6 +220,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); } @@ -243,6 +300,19 @@ 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()); + rep.setEnabled(user.isEnabled()); + 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 9a1f3e5c8e..b62b8a01ab 100755 --- a/services/src/main/java/org/keycloak/services/models/RealmModel.java +++ b/services/src/main/java/org/keycloak/services/models/RealmModel.java @@ -142,4 +142,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 83585debd2..b62cb2e5a0 100755 --- a/services/src/main/java/org/keycloak/services/models/UserModel.java +++ b/services/src/main/java/org/keycloak/services/models/UserModel.java @@ -7,6 +7,7 @@ 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"; 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 4641f0923b..a70dd41c07 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 @@ -755,4 +755,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..079f2af1cc 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,96 @@ 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.setEnabled(rep.isEnabled()); + 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.setEnabled(rep.isEnabled()); + 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 aad9785d21..8428555113 100755 --- a/services/src/test/java/org/keycloak/test/AdapterTest.java +++ b/services/src/test/java/org/keycloak/test/AdapterTest.java @@ -112,8 +112,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()); } @@ -133,6 +132,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();