keycloak-memoizeit

Details

diff --git a/core/src/main/java/org/keycloak/representations/idm/AllRoleMappingsRepresentation.java b/core/src/main/java/org/keycloak/representations/idm/AllRoleMappingsRepresentation.java
new file mode 100755
index 0000000..1d39896
--- /dev/null
+++ b/core/src/main/java/org/keycloak/representations/idm/AllRoleMappingsRepresentation.java
@@ -0,0 +1,57 @@
+package org.keycloak.representations.idm;
+
+import java.util.List;
+import java.util.Map;
+
+/**
+ * @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
+ * @version $Revision: 1 $
+ */
+public class AllRoleMappingsRepresentation {
+    protected String realmId;
+    protected String realmName;
+    protected String username;
+
+    protected List<RoleRepresentation> realmMappings;
+    protected Map<String, ApplicationRoleMappings> applicationMappings;
+
+    public String getRealmId() {
+        return realmId;
+    }
+
+    public void setRealmId(String realmId) {
+        this.realmId = realmId;
+    }
+
+    public String getRealmName() {
+        return realmName;
+    }
+
+    public void setRealmName(String realmName) {
+        this.realmName = realmName;
+    }
+
+    public String getUsername() {
+        return username;
+    }
+
+    public void setUsername(String username) {
+        this.username = username;
+    }
+
+    public List<RoleRepresentation> getRealmMappings() {
+        return realmMappings;
+    }
+
+    public void setRealmMappings(List<RoleRepresentation> realmMappings) {
+        this.realmMappings = realmMappings;
+    }
+
+    public Map<String,ApplicationRoleMappings> getApplicationMappings() {
+        return applicationMappings;
+    }
+
+    public void setApplicationMappings(Map<String, ApplicationRoleMappings> applicationMappings) {
+        this.applicationMappings = applicationMappings;
+    }
+}
diff --git a/core/src/main/java/org/keycloak/representations/idm/ApplicationRoleMappings.java b/core/src/main/java/org/keycloak/representations/idm/ApplicationRoleMappings.java
new file mode 100755
index 0000000..d4cb445
--- /dev/null
+++ b/core/src/main/java/org/keycloak/representations/idm/ApplicationRoleMappings.java
@@ -0,0 +1,47 @@
+package org.keycloak.representations.idm;
+
+import java.util.List;
+
+/**
+ * @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
+ * @version $Revision: 1 $
+ */
+public class ApplicationRoleMappings {
+    protected String applicationId;
+    protected String application;
+    protected String username;
+
+    protected List<RoleRepresentation> mappings;
+
+    public String getApplicationId() {
+        return applicationId;
+    }
+
+    public void setApplicationId(String applicationId) {
+        this.applicationId = applicationId;
+    }
+
+    public String getApplication() {
+        return application;
+    }
+
+    public void setApplication(String application) {
+        this.application = application;
+    }
+
+    public String getUsername() {
+        return username;
+    }
+
+    public void setUsername(String username) {
+        this.username = username;
+    }
+
+    public List<RoleRepresentation> getMappings() {
+        return mappings;
+    }
+
+    public void setMappings(List<RoleRepresentation> mappings) {
+        this.mappings = mappings;
+    }
+}
diff --git a/core/src/main/java/org/keycloak/representations/idm/RealmRoleMappingsRepresentation.java b/core/src/main/java/org/keycloak/representations/idm/RealmRoleMappingsRepresentation.java
new file mode 100755
index 0000000..dcca6f8
--- /dev/null
+++ b/core/src/main/java/org/keycloak/representations/idm/RealmRoleMappingsRepresentation.java
@@ -0,0 +1,47 @@
+package org.keycloak.representations.idm;
+
+import java.util.List;
+
+/**
+ * @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
+ * @version $Revision: 1 $
+ */
+public class RealmRoleMappingsRepresentation {
+    protected String realmId;
+    protected String realm;
+    protected String username;
+
+    protected List<RoleRepresentation> mappings;
+
+    public String getRealmId() {
+        return realmId;
+    }
+
+    public void setRealmId(String realmId) {
+        this.realmId = realmId;
+    }
+
+    public String getRealm() {
+        return realm;
+    }
+
+    public void setRealm(String realm) {
+        this.realm = realm;
+    }
+
+    public String getUsername() {
+        return username;
+    }
+
+    public void setUsername(String username) {
+        this.username = username;
+    }
+
+    public List<RoleRepresentation> getMappings() {
+        return mappings;
+    }
+
+    public void setMappings(List<RoleRepresentation> mappings) {
+        this.mappings = mappings;
+    }
+}
diff --git a/examples/as7-eap-demo/server/src/main/webapp/saas/admin/js/app.js b/examples/as7-eap-demo/server/src/main/webapp/saas/admin/js/app.js
index 1029c93..2a2bf46 100755
--- a/examples/as7-eap-demo/server/src/main/webapp/saas/admin/js/app.js
+++ b/examples/as7-eap-demo/server/src/main/webapp/saas/admin/js/app.js
@@ -40,17 +40,28 @@ module.config([ '$routeProvider', function($routeProvider) {
 		},
 		controller : 'UserDetailCtrl'
 	}).when('/realms/:realm/users/:user', {
-		templateUrl : 'partials/user-detail.html',
-		resolve : {
-			realm : function(RealmLoader) {
-				return RealmLoader();
-			},
-			user : function(UserLoader) {
-				return UserLoader();
-			}
-		},
-		controller : 'UserDetailCtrl'
-	}).when('/realms/:realm/users', {
+            templateUrl : 'partials/user-detail.html',
+            resolve : {
+                realm : function(RealmLoader) {
+                    return RealmLoader();
+                },
+                user : function(UserLoader) {
+                    return UserLoader();
+                }
+            },
+            controller : 'UserDetailCtrl'
+        }).when('/realms/:realm/users/:user/role-mappings', {
+            templateUrl : 'partials/role-mappings.html',
+            resolve : {
+                realm : function(RealmLoader) {
+                    return RealmLoader();
+                },
+                user : function(UserLoader) {
+                    return UserLoader();
+                }
+            },
+            controller : 'UserDetailCtrl'
+        }).when('/realms/:realm/users', {
 		templateUrl : 'partials/user-list.html',
 		resolve : {
 			realm : function(RealmLoader) {
diff --git a/examples/as7-eap-demo/server/src/main/webapp/saas/admin/partials/menu.html b/examples/as7-eap-demo/server/src/main/webapp/saas/admin/partials/menu.html
index 9845267..6786466 100755
--- a/examples/as7-eap-demo/server/src/main/webapp/saas/admin/partials/menu.html
+++ b/examples/as7-eap-demo/server/src/main/webapp/saas/admin/partials/menu.html
@@ -31,18 +31,4 @@
             </ul>
         </div>
     </div>
-    <!--
-    <div class="navbar primary">
-        <div class="navbar-inner" data-ng-controller="RealmDropdownCtrl">
-            <ul class="nav pull-right" data-ng-show="auth.loggedIn">
-                <li class="divider-vertical-left" data-ng-class="path[0] == 'create' && path[1] == 'realm' && 'active'"
-                    data-ng-show="auth.loggedIn"><a href="#/create/realm">New Realm</a></li>
-            </ul>
-            <ul class="nav" data-ng-show="showNav()">
-                <li class="divider-vertical-right"><a href="#/realms/{{current.realm.id}}">Realm</a></li>
-            </ul>
-            <select class="nav pull-left" data-ng-show="showNav()" ng-change="changeRealm()" ng-model="current.realm" ng-options="r.realm for r in current.realms">
-            </select>
-        </div>
-    </div> -->
-</div><!-- End .header -->
+</div>
diff --git a/examples/as7-eap-demo/server/src/main/webapp/saas/admin/partials/role-mappings.html b/examples/as7-eap-demo/server/src/main/webapp/saas/admin/partials/role-mappings.html
new file mode 100755
index 0000000..311afc0
--- /dev/null
+++ b/examples/as7-eap-demo/server/src/main/webapp/saas/admin/partials/role-mappings.html
@@ -0,0 +1,85 @@
+<div id="wrapper" class="container">
+    <div class="row">
+        <div class="bs-sidebar col-md-3 clearfix" data-ng-include data-src="'partials/realm-menu.html'"></div>
+        <div id="content-area" class="col-md-9" role="main">
+            <div class="top-nav">
+                <ul class="rcue-tabs" >
+                    <li><a href="#/create/user/{{realm.id}}">New User</a></li>
+                    <li><a href="#/realms/{{realm.id}}/users">Query Users</a></li>
+                    <li><a href="#">Attributes</a></li>
+                    <li><a href="#">Credentials</a></li>
+                    <li class="active"><a href="#">Role Mappings</a></li>
+                </ul>
+            </div>
+            <div id="content">
+                <h2 class="pull-left">Role Mappings: <span>{{realm.realm}}</span></h2>
+                <p class="subtitle"></p>
+                <form name="realmForm" novalidate>
+                    <fieldset>
+                        <legend uncollapsed><span class="text">Realm Roles</span> </legend>
+                        <div class="form-group">
+                            <div class="controls">
+                                <select multiple size=5>
+                                    <option value="role1">role1</option>
+                                    <option value="role2">role2</option>
+                                    <option value="role3">role3</option>
+                                    <option value="role4">role4</option>
+                                </select>
+                                <button type="submit">---&gt;</button>
+                                <button type="submit">&lt;---</button>
+                                <select multiple size=5>
+                                    <option value="role1">role1</option>
+                                    <option disabled="disabled" value="role2">role2</option>
+                                    <option value="role3">role3</option>
+                                    <option value="role4">role4</option>
+                                </select>
+                            </div>
+                        </div>
+                    </fieldset>
+                    <fieldset>
+                        <legend collapsed><span class="text">Application Roles</span> </legend>
+                        <div class="form-group">
+                            <div class="controls">
+                                <select multiple size=5>
+                                    <option value="role1">role1</option>
+                                    <option value="role2">role2</option>
+                                    <option value="role3">role3</option>
+                                    <option value="role4">role4</option>
+                                </select>
+                                <button type="submit">---&gt;</button>
+                                <button type="submit">&lt;---</button>
+                                <select multiple size=5>
+                                    <option value="role1">role1</option>
+                                    <option disabled="disabled" value="role2">role2</option>
+                                    <option value="role3">role3</option>
+                                    <option value="role4">role4</option>
+                                </select>
+                            </div>
+                        </div>
+                    </fieldset>
+
+                    <div class="form-actions" data-ng-show="createRealm">
+                        <button type="submit" data-ng-click="save()" class="primary" data-ng-show="changed">Save
+                        </button>
+                        <button type="submit" data-ng-click="cancel()" data-ng-click="cancel()"
+                                data-ng-show="changed">Cancel
+                        </button>
+                    </div>
+
+                    <div class="form-actions" data-ng-show="!createRealm">
+                        <button type="submit" data-ng-click="save()" class="primary" data-ng-show="changed">Save
+                            changes
+                        </button>
+                        <button type="submit" data-ng-click="reset()" data-ng-show="changed">Clear changes
+                        </button>
+                        <button type="submit" data-ng-click="remove()" class="danger" data-ng-hide="changed">
+                            Delete
+                        </button>
+                    </div>
+
+                </form>
+            </div>
+        </div>
+        <div id="container-right-bg"></div>
+    </div>
+</div>
\ No newline at end of file
diff --git a/examples/as7-eap-demo/server/src/main/webapp/saas/admin/partials/user-detail.html b/examples/as7-eap-demo/server/src/main/webapp/saas/admin/partials/user-detail.html
index 655c7f7..a62c474 100755
--- a/examples/as7-eap-demo/server/src/main/webapp/saas/admin/partials/user-detail.html
+++ b/examples/as7-eap-demo/server/src/main/webapp/saas/admin/partials/user-detail.html
@@ -16,7 +16,7 @@
                     <li><a href="#/realms/{{realm.id}}/users">Query Users</a></li>
                     <li class="active"><a href="#">Attributes</a></li>
                     <li><a href="#">Credentials</a></li>
-                    <li><a href="#">Role Mappings</a></li>
+                    <li><a href="#/realms/{{realm.id}}/users/{{user.username}}/role-mappings">Role Mappings</a></li>
                 </ul>
             </div>
             <div id="content">
diff --git a/services/src/main/java/org/keycloak/services/managers/TokenManager.java b/services/src/main/java/org/keycloak/services/managers/TokenManager.java
index c195e83..3831ce4 100755
--- a/services/src/main/java/org/keycloak/services/managers/TokenManager.java
+++ b/services/src/main/java/org/keycloak/services/managers/TokenManager.java
@@ -47,7 +47,7 @@ public class TokenManager {
         if (scopeParam != null) scopeMap = decodeScope(scopeParam);
         List<RoleModel> realmRolesRequested = code.getRealmRolesRequested();
         MultivaluedMap<String, RoleModel> resourceRolesRequested = code.getResourceRolesRequested();
-        Set<String> realmMapping = realm.getRoleMappings(user);
+        Set<String> realmMapping = realm.getRoleMappingValues(user);
 
         if (realmMapping != null && realmMapping.size() > 0 && (scopeMap == null || scopeMap.containsKey("realm"))) {
             Set<String> scope = realm.getScope(client);
@@ -67,7 +67,7 @@ public class TokenManager {
             }
         }
         for (ApplicationModel resource : realm.getApplications()) {
-            Set<String> mapping = resource.getRoleMappings(user);
+            Set<String> mapping = resource.getRoleMappingValues(user);
             if (mapping != null && mapping.size() > 0 && (scopeMap == null || scopeMap.containsKey(resource.getName()))) {
                 Set<String> scope = resource.getScope(client);
                 if (scope.size() > 0) {
@@ -176,7 +176,7 @@ public class TokenManager {
             token.expiration((System.currentTimeMillis() / 1000) + realm.getTokenLifespan());
         }
 
-        Set<String> realmMapping = realm.getRoleMappings(user);
+        Set<String> realmMapping = realm.getRoleMappingValues(user);
 
         if (realmMapping != null && realmMapping.size() > 0) {
             SkeletonKeyToken.Access access = new SkeletonKeyToken.Access();
@@ -187,7 +187,7 @@ public class TokenManager {
         }
         if (resources != null) {
             for (ApplicationModel resource : resources) {
-                Set<String> mapping = resource.getRoleMappings(user);
+                Set<String> mapping = resource.getRoleMappingValues(user);
                 if (mapping == null) continue;
                 SkeletonKeyToken.Access access = token.addAccess(resource.getName())
                         .verifyCaller(resource.isSurrogateAuthRequired());
diff --git a/services/src/main/java/org/keycloak/services/models/ApplicationModel.java b/services/src/main/java/org/keycloak/services/models/ApplicationModel.java
index 72640f4..b017885 100755
--- a/services/src/main/java/org/keycloak/services/models/ApplicationModel.java
+++ b/services/src/main/java/org/keycloak/services/models/ApplicationModel.java
@@ -36,11 +36,19 @@ public interface ApplicationModel {
 
     List<RoleModel> getRoles();
 
-    Set<String> getRoleMappings(UserModel user);
+    Set<String> getRoleMappingValues(UserModel user);
 
     void addScope(UserModel agent, String roleName);
 
     void addScope(UserModel agent, RoleModel role);
 
     Set<String> getScope(UserModel agent);
+
+    List<RoleModel> getRoleMappings(UserModel user);
+
+    void deleteRoleMapping(UserModel user, RoleModel role);
+
+    RoleModel getRoleById(String id);
+
+    void grantRole(UserModel user, RoleModel role);
 }
diff --git a/services/src/main/java/org/keycloak/services/models/picketlink/ApplicationAdapter.java b/services/src/main/java/org/keycloak/services/models/picketlink/ApplicationAdapter.java
index d58ede8..dccf7de 100755
--- a/services/src/main/java/org/keycloak/services/models/picketlink/ApplicationAdapter.java
+++ b/services/src/main/java/org/keycloak/services/models/picketlink/ApplicationAdapter.java
@@ -8,6 +8,7 @@ import org.keycloak.services.models.picketlink.relationships.ScopeRelationship;
 import org.picketlink.idm.IdentityManager;
 import org.picketlink.idm.PartitionManager;
 import org.picketlink.idm.RelationshipManager;
+import org.picketlink.idm.model.IdentityType;
 import org.picketlink.idm.model.sample.Grant;
 import org.picketlink.idm.model.sample.Role;
 import org.picketlink.idm.model.sample.SampleModel;
@@ -110,6 +111,22 @@ public class ApplicationAdapter implements ApplicationModel {
     }
 
     @Override
+    public RoleModel getRoleById(String id) {
+        IdentityQuery<Role> query = getIdm().createIdentityQuery(Role.class);
+        query.setParameter(IdentityType.ID, id);
+        List<Role> roles = query.getResultList();
+        if (roles.size() == 0) return null;
+        return new RoleAdapter(roles.get(0), getIdm());
+    }
+
+    @Override
+    public void grantRole(UserModel user, RoleModel role) {
+        SampleModel.grantRole(getRelationshipManager(), ((UserAdapter) user).getUser(), ((RoleAdapter) role).getRole());
+    }
+
+
+
+    @Override
     public RoleAdapter addRole(String name) {
         Role role = new Role(name);
         getIdm().add(role);
@@ -129,7 +146,7 @@ public class ApplicationAdapter implements ApplicationModel {
     }
 
     @Override
-    public Set<String> getRoleMappings(UserModel user) {
+    public Set<String> getRoleMappingValues(UserModel user) {
         RelationshipQuery<Grant> query = getRelationshipManager().createRelationshipQuery(Grant.class);
         query.setParameter(Grant.ASSIGNEE, ((UserAdapter)user).getUser());
         List<Grant> grants = query.getResultList();
@@ -141,6 +158,32 @@ public class ApplicationAdapter implements ApplicationModel {
     }
 
     @Override
+    public List<RoleModel> getRoleMappings(UserModel user) {
+        RelationshipQuery<Grant> query = getRelationshipManager().createRelationshipQuery(Grant.class);
+        query.setParameter(Grant.ASSIGNEE, ((UserAdapter)user).getUser());
+        List<Grant> grants = query.getResultList();
+        List<RoleModel> set = new ArrayList<RoleModel>();
+        for (Grant grant : grants) {
+            if (grant.getRole().getPartition().getId().equals(resource.getId())) set.add(new RoleAdapter(grant.getRole(), getIdm()));
+        }
+        return set;
+    }
+
+    @Override
+    public void deleteRoleMapping(UserModel user, RoleModel role) {
+        RelationshipQuery<Grant> query = getRelationshipManager().createRelationshipQuery(Grant.class);
+        query.setParameter(Grant.ASSIGNEE, ((UserAdapter)user).getUser());
+        query.setParameter(Grant.ROLE, ((RoleAdapter)role).getRole());
+        List<Grant> grants = query.getResultList();
+        for (Grant grant : grants) {
+            getRelationshipManager().remove(grant);
+        }
+    }
+
+
+
+
+    @Override
     public void addScope(UserModel agent, String roleName) {
         IdentityManager idm = getIdm();
         Role role = SampleModel.getRole(idm,roleName);
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 7d5d87e..f0bf782 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
@@ -642,7 +642,18 @@ public class RealmAdapter implements RealmModel {
     }
 
     @Override
-    public Set<String> getRoleMappings(UserModel user) {
+    public void deleteRoleMapping(UserModel user, RoleModel role) {
+        RelationshipQuery<Grant> query = getRelationshipManager().createRelationshipQuery(Grant.class);
+        query.setParameter(Grant.ASSIGNEE, ((UserAdapter)user).getUser());
+        query.setParameter(Grant.ROLE, ((RoleAdapter)role).getRole());
+        List<Grant> grants = query.getResultList();
+        for (Grant grant : grants) {
+            getRelationshipManager().remove(grant);
+        }
+    }
+
+    @Override
+    public Set<String> getRoleMappingValues(UserModel user) {
         RelationshipQuery<Grant> query = getRelationshipManager().createRelationshipQuery(Grant.class);
         query.setParameter(Grant.ASSIGNEE, ((UserAdapter)user).getUser());
         List<Grant> grants = query.getResultList();
@@ -654,6 +665,19 @@ public class RealmAdapter implements RealmModel {
     }
 
     @Override
+    public List<RoleModel> getRoleMappings(UserModel user) {
+        RelationshipQuery<Grant> query = getRelationshipManager().createRelationshipQuery(Grant.class);
+        query.setParameter(Grant.ASSIGNEE, ((UserAdapter)user).getUser());
+        List<Grant> grants = query.getResultList();
+        List<RoleModel> set = new ArrayList<RoleModel>();
+        for (Grant grant : grants) {
+            if (grant.getRole().getPartition().getId().equals(realm.getId())) set.add(new RoleAdapter(grant.getRole(), getIdm()));
+        }
+        return set;
+    }
+
+
+    @Override
     public void addScope(UserModel agent, String roleName) {
         IdentityManager idm = getIdm();
         Role role = SampleModel.getRole(idm, roleName);
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 1927120..da85bac 100755
--- a/services/src/main/java/org/keycloak/services/models/RealmModel.java
+++ b/services/src/main/java/org/keycloak/services/models/RealmModel.java
@@ -107,7 +107,7 @@ public interface RealmModel {
 
     void grantRole(UserModel user, RoleModel role);
 
-    Set<String> getRoleMappings(UserModel user);
+    Set<String> getRoleMappingValues(UserModel user);
 
     void addScope(UserModel agent, String roleName);
 
@@ -156,4 +156,8 @@ public interface RealmModel {
     public void setAutomaticRegistrationAfterSocialLogin(boolean automaticRegistrationAfterSocialLogin);
 
     List<UserModel> searchForUserByAttributes(Map<String, String> attributes);
+
+    List<RoleModel> getRoleMappings(UserModel user);
+
+    void deleteRoleMapping(UserModel user, RoleModel role);
 }
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 32bc854..3015169 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
@@ -120,94 +120,13 @@ 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<String, String> 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<String, String> attr : rep.getAttributes().entrySet()) {
-                user.setAttribute(attr.getKey(), attr.getValue());
-            }
-        }
-        return Response.created(uriInfo.getAbsolutePathBuilder().path(user.getLoginName()).build()).build();
+    public UsersResource users() {
+        UsersResource users = new UsersResource(realm);
+        resourceContext.initResource(users);
+        return users;
     }
 
-    @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<UserRepresentation> 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<UserRepresentation> results = new ArrayList<UserRepresentation>();
-        if (search != null) {
-            List<UserModel> userModels = manager.searchUsers(search, realm);
-            for (UserModel user : userModels) {
-                results.add(manager.toRepresentation(user));
-            }
-        } else {
-            Map<String, String> attributes = new HashMap<String, String>();
-            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<UserModel> userModels = realm.searchForUserByAttributes(attributes);
-            for (UserModel user : userModels) {
-                results.add(manager.toRepresentation(user));
-            }
-
-        }
-        return results;
-    }
 
 
 }
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
new file mode 100755
index 0000000..eedcd86
--- /dev/null
+++ b/services/src/main/java/org/keycloak/services/resources/admin/UsersResource.java
@@ -0,0 +1,309 @@
+package org.keycloak.services.resources.admin;
+
+import org.jboss.resteasy.annotations.cache.NoCache;
+import org.keycloak.representations.idm.*;
+import org.keycloak.services.managers.RealmManager;
+import org.keycloak.services.models.*;
+
+import javax.ws.rs.*;
+import javax.ws.rs.container.ResourceContext;
+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 <a href="mailto:bill@burkecentral.com">Bill Burke</a>
+ * @version $Revision: 1 $
+ */
+public class UsersResource {
+
+    protected RealmModel realm;
+
+    public UsersResource(RealmModel realm) {
+        this.realm = realm;
+    }
+
+    @Context
+    protected ResourceContext resourceContext;
+
+    @Context
+    protected KeycloakSession session;
+
+
+    @Path("{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<String, String> attr : rep.getAttributes().entrySet()) {
+            user.setAttribute(attr.getKey(), attr.getValue());
+        }
+    }
+
+    @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<String, String> attr : rep.getAttributes().entrySet()) {
+                user.setAttribute(attr.getKey(), attr.getValue());
+            }
+        }
+        return Response.created(uriInfo.getAbsolutePathBuilder().path(user.getLoginName()).build()).build();
+    }
+
+    @Path("{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);
+    }
+
+    @GET
+    @NoCache
+    @Produces("application/json")
+    public List<UserRepresentation> 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<UserRepresentation> results = new ArrayList<UserRepresentation>();
+        if (search != null) {
+            List<UserModel> userModels = manager.searchUsers(search, realm);
+            for (UserModel user : userModels) {
+                results.add(manager.toRepresentation(user));
+            }
+        } else {
+            Map<String, String> attributes = new HashMap<String, String>();
+            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<UserModel> userModels = realm.searchForUserByAttributes(attributes);
+            for (UserModel user : userModels) {
+                results.add(manager.toRepresentation(user));
+            }
+
+        }
+        return results;
+    }
+
+    @Path("{username}/role-mappings")
+    @GET
+    public AllRoleMappingsRepresentation getRoleMappings(@PathParam("username") String username) {
+        UserModel user = realm.getUser(username);
+        if (user == null) {
+            throw new NotFoundException();
+        }
+
+        AllRoleMappingsRepresentation all = new AllRoleMappingsRepresentation();
+        all.setRealmId(realm.getId());
+        all.setRealmName(realm.getName());
+        all.setUsername(username);
+        List<RoleModel> realmMappings = realm.getRoleMappings(user);
+        RealmManager manager = new RealmManager(session);
+        if (realmMappings.size() > 0) {
+            List<RoleRepresentation> realmRep = new ArrayList<RoleRepresentation>();
+            for (RoleModel roleModel : realmMappings) {
+                realmRep.add(manager.toRepresentation(roleModel));
+            }
+            all.setRealmMappings(realmRep);
+        }
+
+        List<ApplicationModel> applications = realm.getApplications();
+        if (applications.size() > 0) {
+            Map<String, ApplicationRoleMappings> appMappings = new HashMap<String, ApplicationRoleMappings>();
+            for (ApplicationModel application : applications) {
+                List<RoleModel> roleMappings = application.getRoleMappings(user);
+                if (roleMappings.size() > 0) {
+                    ApplicationRoleMappings mappings = new ApplicationRoleMappings();
+                    mappings.setUsername(user.getLoginName());
+                    mappings.setApplicationId(application.getId());
+                    mappings.setApplication(application.getName());
+                    List<RoleRepresentation> roles = new ArrayList<RoleRepresentation>();
+                    mappings.setMappings(roles);
+                    for (RoleModel role : roleMappings) {
+                        roles.add(manager.toRepresentation(role));
+                    }
+                    appMappings.put(application.getName(), mappings);
+                    all.setApplicationMappings(appMappings);
+                }
+            }
+        }
+        return all;
+    }
+
+    @Path("{username}/role-mappings/realm")
+    @GET
+    public RealmRoleMappingsRepresentation getRealmRoleMappings(@PathParam("username") String username) {
+        UserModel user = realm.getUser(username);
+        if (user == null) {
+            throw new NotFoundException();
+        }
+
+        RealmRoleMappingsRepresentation rep = new RealmRoleMappingsRepresentation();
+        List<RoleModel> realmMappings = realm.getRoleMappings(user);
+        if (realmMappings.size() > 0) {
+            RealmManager manager = new RealmManager(session);
+            List<RoleRepresentation> realmRep = new ArrayList<RoleRepresentation>();
+            for (RoleModel roleModel : realmMappings) {
+                realmRep.add(manager.toRepresentation(roleModel));
+            }
+            rep.setMappings(realmRep);
+        }
+        return rep;
+    }
+
+    @Path("{username}/role-mappings/realm")
+    @POST
+    public void addRealmRoleMappings(@PathParam("username") String username, List<RoleRepresentation> roles) {
+        UserModel user = realm.getUser(username);
+        if (user == null) {
+            throw new NotFoundException();
+        }
+
+        for (RoleRepresentation role : roles) {
+            RoleModel roleModel = realm.getRoleById(role.getId());
+            if (roleModel == null) {
+                throw new NotFoundException();
+            }
+            realm.grantRole(user, roleModel);
+        }
+
+
+    }
+
+    @Path("{username}/role-mappings/realm")
+    @DELETE
+    public void deleteRoleMapping(@PathParam("username") String username, List<RoleRepresentation> roles) {
+        UserModel user = realm.getUser(username);
+        if (user == null) {
+            throw new NotFoundException();
+        }
+
+        if (roles == null) {
+            List<RoleModel> roleModels = realm.getRoleMappings(user);
+            for (RoleModel roleModel : roleModels) {
+                realm.deleteRoleMapping(user, roleModel);
+            }
+
+        } else {
+            for (RoleRepresentation role : roles) {
+                RoleModel roleModel = realm.getRoleById(role.getId());
+                if (roleModel == null) {
+                    throw new NotFoundException();
+                }
+                realm.deleteRoleMapping(user, roleModel);
+            }
+        }
+
+    }
+
+    @Path("{username}/role-mappings/applications/{appId}")
+    @GET
+    public ApplicationRoleMappings getApplicationRoleMappings(@PathParam("username") String username, @PathParam("appId") String appId) {
+        UserModel user = realm.getUser(username);
+        if (user == null) {
+            throw new NotFoundException();
+        }
+
+        ApplicationModel application = realm.getApplicationById(appId);
+
+        if (application == null) {
+            throw new NotFoundException();
+        }
+
+        ApplicationRoleMappings rep = new ApplicationRoleMappings();
+        List<RoleModel> mappings = application.getRoleMappings(user);
+        if (mappings.size() > 0) {
+            RealmManager manager = new RealmManager(session);
+            List<RoleRepresentation> mapRep = new ArrayList<RoleRepresentation>();
+            for (RoleModel roleModel : mappings) {
+                mapRep.add(manager.toRepresentation(roleModel));
+            }
+            rep.setMappings(mapRep);
+        }
+        return rep;
+    }
+
+    @Path("{username}/role-mappings/applications/{appId}")
+    @POST
+    public void addApplicationRoleMapping(@PathParam("username") String username, @PathParam("appId") String appId, List<RoleRepresentation> roles) {
+        UserModel user = realm.getUser(username);
+        if (user == null) {
+            throw new NotFoundException();
+        }
+
+        ApplicationModel application = realm.getApplicationById(appId);
+
+        if (application == null) {
+            throw new NotFoundException();
+        }
+
+
+    }
+
+    @Path("{username}/role-mappings/applications/{appId}")
+    @DELETE
+    public void deleteApplicationRoleMapping(@PathParam("username") String username, @PathParam("appId") String appId, List<RoleRepresentation> roles) {
+        UserModel user = realm.getUser(username);
+        if (user == null) {
+            throw new NotFoundException();
+        }
+
+        ApplicationModel application = realm.getApplicationById(appId);
+
+        if (application == null) {
+            throw new NotFoundException();
+        }
+
+        if (roles == null) {
+            List<RoleModel> roleModels = application.getRoleMappings(user);
+            for (RoleModel roleModel : roleModels) {
+                application.deleteRoleMapping(user, roleModel);
+            }
+
+        } else {
+            for (RoleRepresentation role : roles) {
+                RoleModel roleModel = application.getRoleById(role.getId());
+                if (roleModel == null) {
+                    throw new NotFoundException();
+                }
+                application.deleteRoleMapping(user, roleModel);
+            }
+        }
+    }
+}