keycloak-aplcache

Merge pull request #755 from patriot1burke/master admin

10/9/2014 7:31:16 PM

Changes

model/jpa/src/main/java/org/keycloak/models/jpa/entities/AttributeMap.java 72(+0 -72)

Details

diff --git a/core/src/main/java/org/keycloak/representations/idm/ApplicationRepresentation.java b/core/src/main/java/org/keycloak/representations/idm/ApplicationRepresentation.java
index 3580e39..5a3a8fd 100755
--- a/core/src/main/java/org/keycloak/representations/idm/ApplicationRepresentation.java
+++ b/core/src/main/java/org/keycloak/representations/idm/ApplicationRepresentation.java
@@ -1,6 +1,7 @@
 package org.keycloak.representations.idm;
 
 import java.util.List;
+import java.util.Map;
 
 /**
  * @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
@@ -21,6 +22,8 @@ public class ApplicationRepresentation {
     protected Integer notBefore;
     protected Boolean bearerOnly;
     protected Boolean publicClient;
+    protected String protocol;
+    protected Map<String, String> attributes;
     protected Boolean fullScopeAllowed;
 
 
@@ -143,4 +146,20 @@ public class ApplicationRepresentation {
     public void setFullScopeAllowed(Boolean fullScopeAllowed) {
         this.fullScopeAllowed = fullScopeAllowed;
     }
+
+    public String getProtocol() {
+        return protocol;
+    }
+
+    public void setProtocol(String protocol) {
+        this.protocol = protocol;
+    }
+
+    public Map<String, String> getAttributes() {
+        return attributes;
+    }
+
+    public void setAttributes(Map<String, String> attributes) {
+        this.attributes = attributes;
+    }
 }
diff --git a/core/src/main/java/org/keycloak/representations/idm/OAuthClientRepresentation.java b/core/src/main/java/org/keycloak/representations/idm/OAuthClientRepresentation.java
index 4c2193d..e61cdfc 100755
--- a/core/src/main/java/org/keycloak/representations/idm/OAuthClientRepresentation.java
+++ b/core/src/main/java/org/keycloak/representations/idm/OAuthClientRepresentation.java
@@ -1,6 +1,7 @@
 package org.keycloak.representations.idm;
 
 import java.util.List;
+import java.util.Map;
 
 /**
  * @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
@@ -16,6 +17,8 @@ public class OAuthClientRepresentation {
     protected ClaimRepresentation claims;
     protected Integer notBefore;
     protected Boolean publicClient;
+    protected String protocol;
+    protected Map<String, String> attributes;
     protected Boolean directGrantsOnly;
     protected Boolean fullScopeAllowed;
 
@@ -108,4 +111,19 @@ public class OAuthClientRepresentation {
         this.fullScopeAllowed = fullScopeAllowed;
     }
 
+    public String getProtocol() {
+        return protocol;
+    }
+
+    public void setProtocol(String protocol) {
+        this.protocol = protocol;
+    }
+
+    public Map<String, String> getAttributes() {
+        return attributes;
+    }
+
+    public void setAttributes(Map<String, String> attributes) {
+        this.attributes = attributes;
+    }
 }
diff --git a/core/src/main/java/org/keycloak/representations/idm/UserSessionRepresentation.java b/core/src/main/java/org/keycloak/representations/idm/UserSessionRepresentation.java
index 3987955..3035d2d 100755
--- a/core/src/main/java/org/keycloak/representations/idm/UserSessionRepresentation.java
+++ b/core/src/main/java/org/keycloak/representations/idm/UserSessionRepresentation.java
@@ -15,7 +15,7 @@ public class UserSessionRepresentation {
     private String ipAddress;
     private long start;
     private long lastAccess;
-    private Set<String> applications = new HashSet<String>();
+    private Map<String, String> applications = new HashMap<String, String>();
     private Map<String, String> clients = new HashMap<String, String>();
 
     public String getId() {
@@ -58,11 +58,11 @@ public class UserSessionRepresentation {
         this.lastAccess = lastAccess;
     }
 
-    public Set<String> getApplications() {
+    public Map<String, String> getApplications() {
         return applications;
     }
 
-    public void setApplications(Set<String> applications) {
+    public void setApplications(Map<String, String> applications) {
         this.applications = applications;
     }
 
diff --git a/forms/common-themes/src/main/resources/theme/admin/base/resources/js/app.js b/forms/common-themes/src/main/resources/theme/admin/base/resources/js/app.js
index 85e2872..658acdf 100755
--- a/forms/common-themes/src/main/resources/theme/admin/base/resources/js/app.js
+++ b/forms/common-themes/src/main/resources/theme/admin/base/resources/js/app.js
@@ -57,7 +57,6 @@ module.factory('authInterceptor', function($q, Auth) {
 
 
 module.config([ '$routeProvider', function($routeProvider) {
-
     $routeProvider
         /*
         .when('/create/realm', {
diff --git a/forms/common-themes/src/main/resources/theme/admin/base/resources/js/controllers/applications.js b/forms/common-themes/src/main/resources/theme/admin/base/resources/js/controllers/applications.js
index ecb714d..dbb8867 100755
--- a/forms/common-themes/src/main/resources/theme/admin/base/resources/js/controllers/applications.js
+++ b/forms/common-themes/src/main/resources/theme/admin/base/resources/js/controllers/applications.js
@@ -17,14 +17,14 @@ module.controller('ApplicationRoleListCtrl', function($scope, $location, realm, 
 module.controller('ApplicationCredentialsCtrl', function($scope, $location, realm, application, ApplicationCredentials, Notifications) {
     $scope.realm = realm;
     $scope.application = application;
-    var secret = ApplicationCredentials.get({ realm : realm.realm, application : application.name },
+    var secret = ApplicationCredentials.get({ realm : realm.realm, application : application.id },
         function() {
             $scope.secret = secret.value;
         }
     );
 
     $scope.changePassword = function() {
-        var secret = ApplicationCredentials.update({ realm : realm.realm, application : application.name },
+        var secret = ApplicationCredentials.update({ realm : realm.realm, application : application.id },
             function() {
                 Notifications.success('The secret has been changed.');
                 $scope.secret = secret.value;
@@ -54,7 +54,7 @@ module.controller('ApplicationSessionsCtrl', function($scope, realm, sessionCoun
 
     $scope.query = {
         realm : realm.realm,
-        application: $scope.application.name,
+        application: $scope.application.id,
         max : 5,
         first : 0
     }
@@ -110,7 +110,7 @@ module.controller('ApplicationClaimsCtrl', function($scope, realm, application, 
     $scope.save = function () {
         ApplicationClaims.update({
             realm: realm.realm,
-            application: application.name
+            application: application.id
         }, $scope.claims, function () {
             $scope.changed = false;
             claims = angular.copy($scope.claims);
@@ -120,7 +120,7 @@ module.controller('ApplicationClaimsCtrl', function($scope, realm, application, 
     };
 
     $scope.reset = function () {
-        $location.url("/realms/" + realm.realm + "/applications/" + application.name + "/claims");
+        $location.url("/realms/" + realm.realm + "/applications/" + application.id + "/claims");
     };
 
 });
@@ -140,14 +140,14 @@ module.controller('ApplicationRoleDetailCtrl', function($scope, realm, applicati
         if ($scope.create) {
             ApplicationRole.save({
                 realm: realm.realm,
-                application : application.name
+                application : application.id
             }, $scope.role, function (data, headers) {
                 $scope.changed = false;
                 role = angular.copy($scope.role);
 
                 var l = headers().location;
                 var id = l.substring(l.lastIndexOf("/") + 1);
-                $location.url("/realms/" + realm.realm + "/applications/" + application.name + "/roles/" + id);
+                $location.url("/realms/" + realm.realm + "/applications/" + application.id + "/roles/" + id);
                 Notifications.success("The role has been created.");
             });
         } else {
@@ -159,17 +159,17 @@ module.controller('ApplicationRoleDetailCtrl', function($scope, realm, applicati
         Dialog.confirmDelete($scope.role.name, 'role', function() {
             $scope.role.$remove({
                 realm : realm.realm,
-                application : application.name,
+                application : application.id,
                 role : $scope.role.name
             }, function() {
-                $location.url("/realms/" + realm.realm + "/applications/" + application.name + "/roles");
+                $location.url("/realms/" + realm.realm + "/applications/" + application.id + "/roles");
                 Notifications.success("The role has been deleted.");
             });
         });
     };
 
     $scope.cancel = function () {
-        $location.url("/realms/" + realm.realm + "/applications/" + application.name + "/roles");
+        $location.url("/realms/" + realm.realm + "/applications/" + application.id + "/roles");
     };
 
 
@@ -180,7 +180,6 @@ module.controller('ApplicationRoleDetailCtrl', function($scope, realm, applicati
 });
 
 module.controller('ApplicationListCtrl', function($scope, realm, applications, Application, $location) {
-    console.log('ApplicationListCtrl');
     $scope.realm = realm;
     $scope.applications = applications;
     $scope.$watch(function() {
@@ -234,9 +233,20 @@ module.controller('ApplicationDetailCtrl', function($scope, realm, application, 
         "bearer-only"
     ];
 
+    $scope.protocols = [
+        "openid-connect",
+        "saml"
+    ];
+
     $scope.realm = realm;
     $scope.create = !application.name;
+    $scope.samlServerSignature = false;
+    $scope.samlClientSignature = false;
+    $scope.samlServerEncrypt = false;
     if (!$scope.create) {
+        if (!application.attributes) {
+            application.attributes = {};
+        }
         $scope.application= angular.copy(application);
         $scope.accessType = $scope.accessTypes[0];
         if (application.bearerOnly) {
@@ -244,10 +254,38 @@ module.controller('ApplicationDetailCtrl', function($scope, realm, application, 
         } else if (application.publicClient) {
             $scope.accessType = $scope.accessTypes[1];
         }
+        if (application.protocol == 'openid-connect') {
+            $scope.protocol = $scope.protocols[0];
+        } else if (application.protocol == 'saml') {
+            $scope.protocol = $scope.protocols[1];
+        } else { // protocol could be null due to older keycloak installs
+            $scope.protocol = $scope.protocols[0];
+        }
     } else {
-        $scope.application = { enabled: true };
+        $scope.application = { enabled: true, attributes: {}};
         $scope.application.redirectUris = [];
         $scope.accessType = $scope.accessTypes[0];
+        $scope.protocol = $scope.protocols[0];
+    }
+
+    if ($scope.application.attributes["samlServerSignature"]) {
+        if ($scope.application.attributes["samlServerSignature"] == "true") {
+            $scope.samlServerSignature = true;
+        }
+    }
+    if ($scope.application.attributes["samlClientSignature"]) {
+        if ($scope.application.attributes["samlClientSignature"] == "true") {
+            $scope.samlClientSignature = true;
+        }
+    }
+    if ($scope.application.attributes["samlServerEncrypt"]) {
+        if ($scope.application.attributes["samlServerEncrypt"] == "true") {
+            $scope.samlServerEncrypt = true;
+        }
+    }
+
+    $scope.switchChange = function() {
+        $scope.changed = true;
     }
 
     $scope.changeAccessType = function() {
@@ -263,6 +301,14 @@ module.controller('ApplicationDetailCtrl', function($scope, realm, application, 
         }
     };
 
+    $scope.changeProtocol = function() {
+        if ($scope.protocol == "openid-connect") {
+            $scope.application.protocol = "openid-connect";
+        } else if ($scope.accessType == "saml") {
+            $scope.application.protocol = "saml";
+        }
+    };
+
     $scope.$watch(function() {
         return $location.path();
     }, function() {
@@ -291,6 +337,18 @@ module.controller('ApplicationDetailCtrl', function($scope, realm, application, 
     }
 
     $scope.save = function() {
+        if ($scope.samlServerSignature == true) {
+            $scope.application.attributes["samlServerSignature"] = "true";
+        }
+        if ($scope.samlClientSignature == true) {
+            $scope.application.attributes["samlClientSignature"] = "true";
+        }
+        if ($scope.samlServerEncrypt == true) {
+            $scope.application.attributes["samlServerEncrypt"] = "true";
+        }
+
+        $scope.application.protocol = $scope.protocol;
+
         if (!$scope.application.bearerOnly && (!$scope.application.redirectUris || $scope.application.redirectUris.length == 0)) {
             Notifications.error("You must specify at least one redirect uri");
         } else {
@@ -308,11 +366,11 @@ module.controller('ApplicationDetailCtrl', function($scope, realm, application, 
             } else {
                 Application.update({
                     realm : realm.realm,
-                    application : application.name
+                    application : application.id
                 }, $scope.application, function() {
                     $scope.changed = false;
                     application = angular.copy($scope.application);
-                    $location.url("/realms/" + realm.realm + "/applications/" + application.name);
+                    $location.url("/realms/" + realm.realm + "/applications/" + application.id);
                     Notifications.success("Your changes have been saved to the application.");
                 });
             }
@@ -332,7 +390,7 @@ module.controller('ApplicationDetailCtrl', function($scope, realm, application, 
         Dialog.confirmDelete($scope.application.name, 'application', function() {
             $scope.application.$remove({
                 realm : realm.realm,
-                application : $scope.application.name
+                application : $scope.application.id
             }, function() {
                 $location.url("/realms/" + realm.realm + "/applications");
                 Notifications.success("The application has been deleted.");
@@ -366,7 +424,7 @@ module.controller('ApplicationScopeMappingCtrl', function($scope, $http, realm, 
         console.log('change full scope');
         Application.update({
             realm : realm.realm,
-            application : application.name
+            application : application.id
         }, $scope.application, function() {
             $scope.changed = false;
             application = angular.copy($scope.application);
@@ -378,17 +436,17 @@ module.controller('ApplicationScopeMappingCtrl', function($scope, $http, realm, 
 
 
     function updateRealmRoles() {
-        $scope.realmRoles = ApplicationAvailableRealmScopeMapping.query({realm : realm.realm, application : application.name});
-        $scope.realmMappings = ApplicationRealmScopeMapping.query({realm : realm.realm, application : application.name});
-        $scope.realmComposite = ApplicationCompositeRealmScopeMapping.query({realm : realm.realm, application : application.name});
+        $scope.realmRoles = ApplicationAvailableRealmScopeMapping.query({realm : realm.realm, application : application.id});
+        $scope.realmMappings = ApplicationRealmScopeMapping.query({realm : realm.realm, application : application.id});
+        $scope.realmComposite = ApplicationCompositeRealmScopeMapping.query({realm : realm.realm, application : application.id});
     }
 
     function updateAppRoles() {
         if ($scope.targetApp) {
             console.debug($scope.targetApp.name);
-            $scope.applicationRoles = ApplicationAvailableApplicationScopeMapping.query({realm : realm.realm, application : application.name, targetApp : $scope.targetApp.name});
-            $scope.applicationMappings = ApplicationApplicationScopeMapping.query({realm : realm.realm, application : application.name, targetApp : $scope.targetApp.name});
-            $scope.applicationComposite = ApplicationCompositeApplicationScopeMapping.query({realm : realm.realm, application : application.name, targetApp : $scope.targetApp.name});
+            $scope.applicationRoles = ApplicationAvailableApplicationScopeMapping.query({realm : realm.realm, application : application.id, targetApp : $scope.targetApp.id});
+            $scope.applicationMappings = ApplicationApplicationScopeMapping.query({realm : realm.realm, application : application.id, targetApp : $scope.targetApp.id});
+            $scope.applicationComposite = ApplicationCompositeApplicationScopeMapping.query({realm : realm.realm, application : application.id, targetApp : $scope.targetApp.id});
         } else {
             $scope.applicationRoles = null;
             $scope.applicationMappings = null;
@@ -401,7 +459,7 @@ module.controller('ApplicationScopeMappingCtrl', function($scope, $http, realm, 
     };
 
     $scope.addRealmRole = function() {
-        $http.post(authUrl + '/admin/realms/' + realm.realm + '/applications/' + application.name + '/scope-mappings/realm',
+        $http.post(authUrl + '/admin/realms/' + realm.realm + '/applications-by-id/' + application.id + '/scope-mappings/realm',
                 $scope.selectedRealmRoles).success(function() {
                 updateRealmRoles();
                 Notifications.success("Scope mappings updated.");
@@ -409,7 +467,7 @@ module.controller('ApplicationScopeMappingCtrl', function($scope, $http, realm, 
     };
 
     $scope.deleteRealmRole = function() {
-        $http.delete(authUrl + '/admin/realms/' + realm.realm + '/applications/' + application.name +  '/scope-mappings/realm',
+        $http.delete(authUrl + '/admin/realms/' + realm.realm + '/applications-by-id/' + application.id +  '/scope-mappings/realm',
             {data : $scope.selectedRealmMappings, headers : {"content-type" : "application/json"}}).success(function () {
                 updateRealmRoles();
                 Notifications.success("Scope mappings updated.");
@@ -417,7 +475,7 @@ module.controller('ApplicationScopeMappingCtrl', function($scope, $http, realm, 
     };
 
     $scope.addApplicationRole = function() {
-        $http.post(authUrl + '/admin/realms/' + realm.realm + '/applications/' + application.name +  '/scope-mappings/applications/' + $scope.targetApp.name,
+        $http.post(authUrl + '/admin/realms/' + realm.realm + '/applications-by-id/' + application.id +  '/scope-mappings/applications-by-id/' + $scope.targetApp.id,
                 $scope.selectedApplicationRoles).success(function () {
                 updateAppRoles();
                 Notifications.success("Scope mappings updated.");
@@ -425,7 +483,7 @@ module.controller('ApplicationScopeMappingCtrl', function($scope, $http, realm, 
     };
 
     $scope.deleteApplicationRole = function() {
-        $http.delete(authUrl + '/admin/realms/' + realm.realm + '/applications/' + application.name +  '/scope-mappings/applications/' + $scope.targetApp.name,
+        $http.delete(authUrl + '/admin/realms/' + realm.realm + '/applications-by-id/' + application.id +  '/scope-mappings/applications-by-id/' + $scope.targetApp.id,
             {data : $scope.selectedApplicationMappings, headers : {"content-type" : "application/json"}}).success(function () {
                 updateAppRoles();
                 Notifications.success("Scope mappings updated.");
@@ -450,7 +508,7 @@ module.controller('ApplicationRevocationCtrl', function($scope, realm, applicati
     setNotBefore();
 
     var refresh = function() {
-        Application.get({ realm : realm.realm, application: $scope.application.name }, function(updated) {
+        Application.get({ realm : realm.realm, application: $scope.application.id }, function(updated) {
             $scope.application = updated;
             setNotBefore();
         })
@@ -459,7 +517,7 @@ module.controller('ApplicationRevocationCtrl', function($scope, realm, applicati
 
     $scope.clear = function() {
         $scope.application.notBefore = 0;
-        Application.update({ realm : realm.realm, application: application.name}, $scope.application, function () {
+        Application.update({ realm : realm.realm, application: application.id}, $scope.application, function () {
             $scope.notBefore = "None";
             Notifications.success('Not Before cleared for application.');
             refresh();
@@ -467,13 +525,13 @@ module.controller('ApplicationRevocationCtrl', function($scope, realm, applicati
     }
     $scope.setNotBeforeNow = function() {
         $scope.application.notBefore = new Date().getTime()/1000;
-        Application.update({ realm : realm.realm, application: $scope.application.name}, $scope.application, function () {
+        Application.update({ realm : realm.realm, application: $scope.application.id}, $scope.application, function () {
             Notifications.success('Not Before cleared for application.');
             refresh();
         });
     }
     $scope.pushRevocation = function() {
-        ApplicationPushRevocation.save({realm : realm.realm, application: $scope.application.name}, function () {
+        ApplicationPushRevocation.save({realm : realm.realm, application: $scope.application.id}, function () {
             Notifications.success('Push sent for application.');
         });
     }
diff --git a/forms/common-themes/src/main/resources/theme/admin/base/resources/js/controllers/oauth-clients.js b/forms/common-themes/src/main/resources/theme/admin/base/resources/js/controllers/oauth-clients.js
index 63e6089..dfd93d3 100755
--- a/forms/common-themes/src/main/resources/theme/admin/base/resources/js/controllers/oauth-clients.js
+++ b/forms/common-themes/src/main/resources/theme/admin/base/resources/js/controllers/oauth-clients.js
@@ -224,9 +224,9 @@ module.controller('OAuthClientScopeMappingCtrl', function($scope, $http, realm, 
     function updateAppRoles() {
         if ($scope.targetApp) {
             console.debug($scope.targetApp.name);
-            $scope.applicationRoles = OAuthClientAvailableApplicationScopeMapping.query({realm : realm.realm, oauth : oauth.name, targetApp : $scope.targetApp.name});
-            $scope.applicationMappings = OAuthClientApplicationScopeMapping.query({realm : realm.realm, oauth : oauth.name, targetApp : $scope.targetApp.name});
-            $scope.applicationComposite = OAuthClientCompositeApplicationScopeMapping.query({realm : realm.realm, oauth : oauth.name, targetApp : $scope.targetApp.name});
+            $scope.applicationRoles = OAuthClientAvailableApplicationScopeMapping.query({realm : realm.realm, oauth : oauth.name, targetApp : $scope.targetApp.id});
+            $scope.applicationMappings = OAuthClientApplicationScopeMapping.query({realm : realm.realm, oauth : oauth.name, targetApp : $scope.targetApp.id});
+            $scope.applicationComposite = OAuthClientCompositeApplicationScopeMapping.query({realm : realm.realm, oauth : oauth.name, targetApp : $scope.targetApp.id});
         } else {
             $scope.applicationRoles = null;
             $scope.applicationMappings = null;
@@ -256,7 +256,7 @@ module.controller('OAuthClientScopeMappingCtrl', function($scope, $http, realm, 
     };
 
     $scope.addApplicationRole = function() {
-        $http.post(authUrl + '/admin/realms/' + realm.realm + '/oauth-clients/' + oauth.name +  '/scope-mappings/applications/' + $scope.targetApp.name,
+        $http.post(authUrl + '/admin/realms/' + realm.realm + '/oauth-clients/' + oauth.name +  '/scope-mappings/applications-by-id/' + $scope.targetApp.id,
             $scope.selectedApplicationRoles).success(function () {
                 updateAppRoles();
                 Notifications.success("Scope mappings updated.");
@@ -265,7 +265,7 @@ module.controller('OAuthClientScopeMappingCtrl', function($scope, $http, realm, 
     };
 
     $scope.deleteApplicationRole = function() {
-        $http.delete(authUrl + '/admin/realms/' + realm.realm + '/oauth-clients/' + oauth.name +  '/scope-mappings/applications/' + $scope.targetApp.name,
+        $http.delete(authUrl + '/admin/realms/' + realm.realm + '/oauth-clients/' + oauth.name +  '/scope-mappings/applications-by-id/' + $scope.targetApp.id,
             {data : $scope.selectedApplicationMappings, headers : {"content-type" : "application/json"}}).success(function () {
                 updateAppRoles();
                 Notifications.success("Scope mappings updated.");
diff --git a/forms/common-themes/src/main/resources/theme/admin/base/resources/js/controllers/realm.js b/forms/common-themes/src/main/resources/theme/admin/base/resources/js/controllers/realm.js
index 1a0adcb..86e9836 100755
--- a/forms/common-themes/src/main/resources/theme/admin/base/resources/js/controllers/realm.js
+++ b/forms/common-themes/src/main/resources/theme/admin/base/resources/js/controllers/realm.js
@@ -541,7 +541,7 @@ module.controller('RealmDefaultRolesCtrl', function ($scope, Realm, realm, appli
 
         // Populate available roles for selected application
         if ($scope.application) {
-            var appDefaultRoles = ApplicationRole.query({realm: $scope.realm.realm, application: $scope.application.name}, function () {
+            var appDefaultRoles = ApplicationRole.query({realm: $scope.realm.realm, application: $scope.application.id}, function () {
 
                 if (!$scope.application.hasOwnProperty('defaultRoles') || $scope.application.defaultRoles === null) {
                     $scope.application.defaultRoles = [];
@@ -582,7 +582,7 @@ module.controller('RealmDefaultRolesCtrl', function ($scope, Realm, realm, appli
         // Update/save the selected application with new default roles.
         Application.update({
             realm: $scope.realm.realm,
-            application: $scope.application.name
+            application: $scope.application.id
         }, $scope.application, function () {
             Notifications.success("Your changes have been saved to the application.");
         });
@@ -606,7 +606,7 @@ module.controller('RealmDefaultRolesCtrl', function ($scope, Realm, realm, appli
         // Update/save the selected application with new default roles.
         Application.update({
             realm: $scope.realm.realm,
-            application: $scope.application.name
+            application: $scope.application.id
         }, $scope.application, function () {
             Notifications.success("Your changes have been saved to the application.");
         });
diff --git a/forms/common-themes/src/main/resources/theme/admin/base/resources/js/controllers/users.js b/forms/common-themes/src/main/resources/theme/admin/base/resources/js/controllers/users.js
index 7ac791e..8c6154a 100755
--- a/forms/common-themes/src/main/resources/theme/admin/base/resources/js/controllers/users.js
+++ b/forms/common-themes/src/main/resources/theme/admin/base/resources/js/controllers/users.js
@@ -28,9 +28,9 @@ module.controller('UserRoleMappingCtrl', function($scope, $http, realm, user, ap
                 $scope.selectRealmRoles = [];
                 if ($scope.application) {
                     console.log('load available');
-                    $scope.applicationComposite = CompositeApplicationRoleMapping.query({realm : realm.realm, userId : user.username, application : $scope.application.name});
-                    $scope.applicationRoles = AvailableApplicationRoleMapping.query({realm : realm.realm, userId : user.username, application : $scope.application.name});
-                    $scope.applicationMappings = ApplicationRoleMapping.query({realm : realm.realm, userId : user.username, application : $scope.application.name});
+                    $scope.applicationComposite = CompositeApplicationRoleMapping.query({realm : realm.realm, userId : user.username, application : $scope.application.id});
+                    $scope.applicationRoles = AvailableApplicationRoleMapping.query({realm : realm.realm, userId : user.username, application : $scope.application.id});
+                    $scope.applicationMappings = ApplicationRoleMapping.query({realm : realm.realm, userId : user.username, application : $scope.application.id});
                     $scope.selectedApplicationRoles = [];
                     $scope.selectedApplicationMappings = [];
                 }
@@ -49,9 +49,9 @@ module.controller('UserRoleMappingCtrl', function($scope, $http, realm, user, ap
                 $scope.selectRealmRoles = [];
                 if ($scope.application) {
                     console.log('load available');
-                    $scope.applicationComposite = CompositeApplicationRoleMapping.query({realm : realm.realm, userId : user.username, application : $scope.application.name});
-                    $scope.applicationRoles = AvailableApplicationRoleMapping.query({realm : realm.realm, userId : user.username, application : $scope.application.name});
-                    $scope.applicationMappings = ApplicationRoleMapping.query({realm : realm.realm, userId : user.username, application : $scope.application.name});
+                    $scope.applicationComposite = CompositeApplicationRoleMapping.query({realm : realm.realm, userId : user.username, application : $scope.application.id});
+                    $scope.applicationRoles = AvailableApplicationRoleMapping.query({realm : realm.realm, userId : user.username, application : $scope.application.id});
+                    $scope.applicationMappings = ApplicationRoleMapping.query({realm : realm.realm, userId : user.username, application : $scope.application.id});
                     $scope.selectedApplicationRoles = [];
                     $scope.selectedApplicationMappings = [];
                 }
@@ -60,11 +60,11 @@ module.controller('UserRoleMappingCtrl', function($scope, $http, realm, user, ap
     };
 
     $scope.addApplicationRole = function() {
-        $http.post(authUrl + '/admin/realms/' + realm.realm + '/users/' + user.username + '/role-mappings/applications/' + $scope.application.name,
+        $http.post(authUrl + '/admin/realms/' + realm.realm + '/users/' + user.username + '/role-mappings/applications-by-id/' + $scope.application.id,
                 $scope.selectedApplicationRoles).success(function() {
-                $scope.applicationMappings = ApplicationRoleMapping.query({realm : realm.realm, userId : user.username, application : $scope.application.name});
-                $scope.applicationRoles = AvailableApplicationRoleMapping.query({realm : realm.realm, userId : user.username, application : $scope.application.name});
-                $scope.applicationComposite = CompositeApplicationRoleMapping.query({realm : realm.realm, userId : user.username, application : $scope.application.name});
+                $scope.applicationMappings = ApplicationRoleMapping.query({realm : realm.realm, userId : user.username, application : $scope.application.id});
+                $scope.applicationRoles = AvailableApplicationRoleMapping.query({realm : realm.realm, userId : user.username, application : $scope.application.id});
+                $scope.applicationComposite = CompositeApplicationRoleMapping.query({realm : realm.realm, userId : user.username, application : $scope.application.id});
                 $scope.selectedApplicationRoles = [];
                 $scope.selectedApplicationMappings = [];
                 Notifications.success("Role mappings updated.");
@@ -72,11 +72,11 @@ module.controller('UserRoleMappingCtrl', function($scope, $http, realm, user, ap
     };
 
     $scope.deleteApplicationRole = function() {
-        $http.delete(authUrl + '/admin/realms/' + realm.realm + '/users/' + user.username + '/role-mappings/applications/' + $scope.application.name,
+        $http.delete(authUrl + '/admin/realms/' + realm.realm + '/users/' + user.username + '/role-mappings/applications-by-id/' + $scope.application.id,
             {data : $scope.selectedApplicationMappings, headers : {"content-type" : "application/json"}}).success(function() {
-                $scope.applicationMappings = ApplicationRoleMapping.query({realm : realm.realm, userId : user.username, application : $scope.application.name});
-                $scope.applicationRoles = AvailableApplicationRoleMapping.query({realm : realm.realm, userId : user.username, application : $scope.application.name});
-                $scope.applicationComposite = CompositeApplicationRoleMapping.query({realm : realm.realm, userId : user.username, application : $scope.application.name});
+                $scope.applicationMappings = ApplicationRoleMapping.query({realm : realm.realm, userId : user.username, application : $scope.application.id});
+                $scope.applicationRoles = AvailableApplicationRoleMapping.query({realm : realm.realm, userId : user.username, application : $scope.application.id});
+                $scope.applicationComposite = CompositeApplicationRoleMapping.query({realm : realm.realm, userId : user.username, application : $scope.application.id});
                 $scope.selectedApplicationRoles = [];
                 $scope.selectedApplicationMappings = [];
                 Notifications.success("Role mappings updated.");
@@ -88,9 +88,9 @@ module.controller('UserRoleMappingCtrl', function($scope, $http, realm, user, ap
         console.log('changeApplication');
         if ($scope.application) {
             console.log('load available');
-            $scope.applicationComposite = CompositeApplicationRoleMapping.query({realm : realm.realm, userId : user.username, application : $scope.application.name});
-            $scope.applicationRoles = AvailableApplicationRoleMapping.query({realm : realm.realm, userId : user.username, application : $scope.application.name});
-            $scope.applicationMappings = ApplicationRoleMapping.query({realm : realm.realm, userId : user.username, application : $scope.application.name});
+            $scope.applicationComposite = CompositeApplicationRoleMapping.query({realm : realm.realm, userId : user.username, application : $scope.application.id});
+            $scope.applicationRoles = AvailableApplicationRoleMapping.query({realm : realm.realm, userId : user.username, application : $scope.application.id});
+            $scope.applicationMappings = ApplicationRoleMapping.query({realm : realm.realm, userId : user.username, application : $scope.application.id});
         } else {
             $scope.applicationRoles = null;
             $scope.applicationMappings = null;
diff --git a/forms/common-themes/src/main/resources/theme/admin/base/resources/js/loaders.js b/forms/common-themes/src/main/resources/theme/admin/base/resources/js/loaders.js
index 30785b7..4551615 100755
--- a/forms/common-themes/src/main/resources/theme/admin/base/resources/js/loaders.js
+++ b/forms/common-themes/src/main/resources/theme/admin/base/resources/js/loaders.js
@@ -72,7 +72,7 @@ module.factory('RealmSessionStatsLoader', function(Loader, RealmSessionStats, $r
 });
 
 module.factory('RealmApplicationSessionStatsLoader', function(Loader, RealmApplicationSessionStats, $route, $q) {
-    return Loader.get(RealmApplicationSessionStats, function() {
+    return Loader.query(RealmApplicationSessionStats, function() {
         return {
             realm : $route.current.params.realm
         }
@@ -213,6 +213,8 @@ module.factory('ApplicationRoleListLoader', function(Loader, ApplicationRole, $r
 
 module.factory('ApplicationLoader', function(Loader, Application, $route, $q) {
     return Loader.get(Application, function() {
+        console.log('application loader****');
+        console.log($route.current.params.application);
         return {
             realm : $route.current.params.realm,
             application : $route.current.params.application
diff --git a/forms/common-themes/src/main/resources/theme/admin/base/resources/js/services.js b/forms/common-themes/src/main/resources/theme/admin/base/resources/js/services.js
index e5fbcbf..3fafb68 100755
--- a/forms/common-themes/src/main/resources/theme/admin/base/resources/js/services.js
+++ b/forms/common-themes/src/main/resources/theme/admin/base/resources/js/services.js
@@ -311,7 +311,7 @@ module.factory('AvailableRealmRoleMapping', function($resource) {
 
 
 module.factory('ApplicationRoleMapping', function($resource) {
-    return $resource(authUrl + '/admin/realms/:realm/users/:userId/role-mappings/applications/:application', {
+    return $resource(authUrl + '/admin/realms/:realm/users/:userId/role-mappings/applications-by-id/:application', {
         realm : '@realm',
         userId : '@userId',
         application : "@application"
@@ -319,7 +319,7 @@ module.factory('ApplicationRoleMapping', function($resource) {
 });
 
 module.factory('AvailableApplicationRoleMapping', function($resource) {
-    return $resource(authUrl + '/admin/realms/:realm/users/:userId/role-mappings/applications/:application/available', {
+    return $resource(authUrl + '/admin/realms/:realm/users/:userId/role-mappings/applications-by-id/:application/available', {
         realm : '@realm',
         userId : '@userId',
         application : "@application"
@@ -327,7 +327,7 @@ module.factory('AvailableApplicationRoleMapping', function($resource) {
 });
 
 module.factory('CompositeApplicationRoleMapping', function($resource) {
-    return $resource(authUrl + '/admin/realms/:realm/users/:userId/role-mappings/applications/:application/composite', {
+    return $resource(authUrl + '/admin/realms/:realm/users/:userId/role-mappings/applications-by-id/:application/composite', {
         realm : '@realm',
         userId : '@userId',
         application : "@application"
@@ -335,28 +335,28 @@ module.factory('CompositeApplicationRoleMapping', function($resource) {
 });
 
 module.factory('ApplicationRealmScopeMapping', function($resource) {
-    return $resource(authUrl + '/admin/realms/:realm/applications/:application/scope-mappings/realm', {
+    return $resource(authUrl + '/admin/realms/:realm/applications-by-id/:application/scope-mappings/realm', {
         realm : '@realm',
         application : '@application'
     });
 });
 
 module.factory('ApplicationAvailableRealmScopeMapping', function($resource) {
-    return $resource(authUrl + '/admin/realms/:realm/applications/:application/scope-mappings/realm/available', {
+    return $resource(authUrl + '/admin/realms/:realm/applications-by-id/:application/scope-mappings/realm/available', {
         realm : '@realm',
         application : '@application'
     });
 });
 
 module.factory('ApplicationCompositeRealmScopeMapping', function($resource) {
-    return $resource(authUrl + '/admin/realms/:realm/applications/:application/scope-mappings/realm/composite', {
+    return $resource(authUrl + '/admin/realms/:realm/applications-by-id/:application/scope-mappings/realm/composite', {
         realm : '@realm',
         application : '@application'
     });
 });
 
 module.factory('ApplicationApplicationScopeMapping', function($resource) {
-    return $resource(authUrl + '/admin/realms/:realm/applications/:application/scope-mappings/applications/:targetApp', {
+    return $resource(authUrl + '/admin/realms/:realm/applications-by-id/:application/scope-mappings/applications-by-id/:targetApp', {
         realm : '@realm',
         application : '@application',
         targetApp : '@targetApp'
@@ -364,7 +364,7 @@ module.factory('ApplicationApplicationScopeMapping', function($resource) {
 });
 
 module.factory('ApplicationAvailableApplicationScopeMapping', function($resource) {
-    return $resource(authUrl + '/admin/realms/:realm/applications/:application/scope-mappings/applications/:targetApp/available', {
+    return $resource(authUrl + '/admin/realms/:realm/applications-by-id/:application/scope-mappings/applications-by-id/:targetApp/available', {
         realm : '@realm',
         application : '@application',
         targetApp : '@targetApp'
@@ -372,7 +372,7 @@ module.factory('ApplicationAvailableApplicationScopeMapping', function($resource
 });
 
 module.factory('ApplicationCompositeApplicationScopeMapping', function($resource) {
-    return $resource(authUrl + '/admin/realms/:realm/applications/:application/scope-mappings/applications/:targetApp/composite', {
+    return $resource(authUrl + '/admin/realms/:realm/applications-by-id/:application/scope-mappings/applications-by-id/:targetApp/composite', {
         realm : '@realm',
         application : '@application',
         targetApp : '@targetApp'
@@ -407,14 +407,14 @@ module.factory('RealmSessionStats', function($resource) {
 });
 
 module.factory('RealmApplicationSessionStats', function($resource) {
-    return $resource(authUrl + '/admin/realms/:realm/application-session-stats', {
+    return $resource(authUrl + '/admin/realms/:realm/application-by-id-session-stats', {
         realm : '@realm'
     });
 });
 
 
 module.factory('RoleApplicationComposites', function($resource) {
-    return $resource(authUrl + '/admin/realms/:realm/roles-by-id/:role/composites/applications/:application', {
+    return $resource(authUrl + '/admin/realms/:realm/roles-by-id/:role/composites/applications-by-id/:application', {
         realm : '@realm',
         role : '@role',
         application : "@application"
@@ -468,7 +468,6 @@ function roleControl($scope, realm, role, roles, applications,
     $scope.selectedApplicationMappings = [];
     $scope.applicationMappings = [];
 
-    console.log('remove self');
     for (var j = 0; j < $scope.realmRoles.length; j++) {
         if ($scope.realmRoles[j].id == role.id) {
             var realmRole = $scope.realmRoles[j];
@@ -561,8 +560,8 @@ function roleControl($scope, realm, role, roles, applications,
 
 
     $scope.changeApplication = function() {
-        $scope.applicationRoles = ApplicationRole.query({realm : realm.realm, application : $scope.compositeApp.name}, function() {
-                $scope.applicationMappings = RoleApplicationComposites.query({realm : realm.realm, role : role.id, application : $scope.compositeApp.name}, function(){
+        $scope.applicationRoles = ApplicationRole.query({realm : realm.realm, application : $scope.compositeApp.id}, function() {
+                $scope.applicationMappings = RoleApplicationComposites.query({realm : realm.realm, role : role.id, application : $scope.compositeApp.id}, function(){
                     for (var i = 0; i < $scope.applicationMappings.length; i++) {
                         var role = $scope.applicationMappings[i];
                         for (var j = 0; j < $scope.applicationRoles.length; j++) {
@@ -618,7 +617,7 @@ module.factory('RoleById', function($resource) {
 });
 
 module.factory('ApplicationRole', function($resource) {
-    return $resource(authUrl + '/admin/realms/:realm/applications/:application/roles/:role', {
+    return $resource(authUrl + '/admin/realms/:realm/applications-by-id/:application/roles/:role', {
         realm : '@realm',
         application : "@application",
         role : '@role'
@@ -630,7 +629,7 @@ module.factory('ApplicationRole', function($resource) {
 });
 
 module.factory('ApplicationClaims', function($resource) {
-    return $resource(authUrl + '/admin/realms/:realm/applications/:application/claims', {
+    return $resource(authUrl + '/admin/realms/:realm/applications-by-id/:application/claims', {
         realm : '@realm',
         application : "@application"
     },  {
@@ -641,41 +640,41 @@ module.factory('ApplicationClaims', function($resource) {
 });
 
 module.factory('ApplicationSessionStats', function($resource) {
-    return $resource(authUrl + '/admin/realms/:realm/applications/:application/session-stats', {
+    return $resource(authUrl + '/admin/realms/:realm/applications-by-id/:application/session-stats', {
         realm : '@realm',
         application : "@application"
     });
 });
 
 module.factory('ApplicationSessionStatsWithUsers', function($resource) {
-    return $resource(authUrl + '/admin/realms/:realm/applications/:application/session-stats?users=true', {
+    return $resource(authUrl + '/admin/realms/:realm/applications-by-id/:application/session-stats?users=true', {
         realm : '@realm',
         application : "@application"
     });
 });
 
 module.factory('ApplicationSessionCount', function($resource) {
-    return $resource(authUrl + '/admin/realms/:realm/applications/:application/session-count', {
+    return $resource(authUrl + '/admin/realms/:realm/applications-by-id/:application/session-count', {
         realm : '@realm',
         application : "@application"
     });
 });
 
 module.factory('ApplicationUserSessions', function($resource) {
-    return $resource(authUrl + '/admin/realms/:realm/applications/:application/user-sessions', {
+    return $resource(authUrl + '/admin/realms/:realm/applications-by-id/:application/user-sessions', {
         realm : '@realm',
         application : "@application"
     });
 });
 
 module.factory('ApplicationLogoutAll', function($resource) {
-    return $resource(authUrl + '/admin/realms/:realm/applications/:application/logout-all', {
+    return $resource(authUrl + '/admin/realms/:realm/applications-by-id/:application/logout-all', {
         realm : '@realm',
         application : "@application"
     });
 });
 module.factory('ApplicationLogoutUser', function($resource) {
-    return $resource(authUrl + '/admin/realms/:realm/applications/:application/logout-user/:user', {
+    return $resource(authUrl + '/admin/realms/:realm/applications-by-id/:application/logout-user/:user', {
         realm : '@realm',
         application : "@application",
         user : "@user"
@@ -688,7 +687,7 @@ module.factory('RealmLogoutAll', function($resource) {
 });
 
 module.factory('ApplicationPushRevocation', function($resource) {
-    return $resource(authUrl + '/admin/realms/:realm/applications/:application/push-revocation', {
+    return $resource(authUrl + '/admin/realms/:realm/applications-by-id/:application/push-revocation', {
         realm : '@realm',
         application : "@application"
     });
@@ -697,7 +696,7 @@ module.factory('ApplicationPushRevocation', function($resource) {
 
 
 module.factory('Application', function($resource) {
-    return $resource(authUrl + '/admin/realms/:realm/applications/:application', {
+    return $resource(authUrl + '/admin/realms/:realm/applications-by-id/:application', {
         realm : '@realm',
         application : '@application'
     },  {
@@ -708,7 +707,7 @@ module.factory('Application', function($resource) {
 });
 
 module.factory('ApplicationInstallation', function($resource) {
-    var url = authUrl + '/admin/realms/:realm/applications/:application/installation/json';
+    var url = authUrl + '/admin/realms/:realm/applications-by-id/:application/installation/json';
     return {
         url : function(parameters)
         {
@@ -717,7 +716,7 @@ module.factory('ApplicationInstallation', function($resource) {
     }
 });
 module.factory('ApplicationInstallationJBoss', function($resource) {
-    var url = authUrl + '/admin/realms/:realm/applications/:application/installation/jboss';
+    var url = authUrl + '/admin/realms/:realm/applications-by-id/:application/installation/jboss';
     return {
         url : function(parameters)
      {
@@ -727,7 +726,7 @@ module.factory('ApplicationInstallationJBoss', function($resource) {
 });
 
 module.factory('ApplicationCredentials', function($resource) {
-    return $resource(authUrl + '/admin/realms/:realm/applications/:application/client-secret', {
+    return $resource(authUrl + '/admin/realms/:realm/applications-by-id/:application/client-secret', {
         realm : '@realm',
         application : '@application'
     },  {
@@ -738,7 +737,7 @@ module.factory('ApplicationCredentials', function($resource) {
 });
 
 module.factory('ApplicationOrigins', function($resource) {
-    return $resource(authUrl + '/admin/realms/:realm/applications/:application/allowed-origins', {
+    return $resource(authUrl + '/admin/realms/:realm/applications-by-id/:application/allowed-origins', {
         realm : '@realm',
         application : '@application'
     },  {
@@ -806,7 +805,7 @@ module.factory('OAuthClientAvailableRealmScopeMapping', function($resource) {
 });
 
 module.factory('OAuthClientApplicationScopeMapping', function($resource) {
-    return $resource(authUrl + '/admin/realms/:realm/oauth-clients/:oauth/scope-mappings/applications/:targetApp', {
+    return $resource(authUrl + '/admin/realms/:realm/oauth-clients/:oauth/scope-mappings/applications-by-id/:targetApp', {
         realm : '@realm',
         oauth : '@oauth',
         targetApp : '@targetApp'
@@ -814,7 +813,7 @@ module.factory('OAuthClientApplicationScopeMapping', function($resource) {
 });
 
 module.factory('OAuthClientCompositeApplicationScopeMapping', function($resource) {
-    return $resource(authUrl + '/admin/realms/:realm/oauth-clients/:oauth/scope-mappings/applications/:targetApp/composite', {
+    return $resource(authUrl + '/admin/realms/:realm/oauth-clients/:oauth/scope-mappings/applications-by-id/:targetApp/composite', {
         realm : '@realm',
         oauth : '@oauth',
         targetApp : '@targetApp'
@@ -822,7 +821,7 @@ module.factory('OAuthClientCompositeApplicationScopeMapping', function($resource
 });
 
 module.factory('OAuthClientAvailableApplicationScopeMapping', function($resource) {
-    return $resource(authUrl + '/admin/realms/:realm/oauth-clients/:oauth/scope-mappings/applications/:targetApp/available', {
+    return $resource(authUrl + '/admin/realms/:realm/oauth-clients/:oauth/scope-mappings/applications-by-id/:targetApp/available', {
         realm : '@realm',
         oauth : '@oauth',
         targetApp : '@targetApp'
diff --git a/forms/common-themes/src/main/resources/theme/admin/base/resources/partials/application-claims.html b/forms/common-themes/src/main/resources/theme/admin/base/resources/partials/application-claims.html
index 64253df..a01bc3c 100755
--- a/forms/common-themes/src/main/resources/theme/admin/base/resources/partials/application-claims.html
+++ b/forms/common-themes/src/main/resources/theme/admin/base/resources/partials/application-claims.html
@@ -4,7 +4,7 @@
     <div id="content">
         <ol class="breadcrumb" data-ng-hide="create">
             <li><a href="#/realms/{{realm.realm}}/applications">Applications</a></li>
-            <li><a href="#/realms/{{realm.realm}}/applications/{{application.name}}">{{application.name}}</a></li>
+            <li><a href="#/realms/{{realm.realm}}/applications/{{application.id}}">{{application.name}}</a></li>
             <li class="active">Claims</li>
         </ol>
         <h2 data-ng-hide="create"><span>{{application.name}}</span> Allowed Claims <span tooltip-placement="right" tooltip="Allows you to restrict which claim information is stored in the access token generated for the application." class="fa fa-info-circle"></span></h2>
diff --git a/forms/common-themes/src/main/resources/theme/admin/base/resources/partials/application-credentials.html b/forms/common-themes/src/main/resources/theme/admin/base/resources/partials/application-credentials.html
index 0204d74..1da24a2 100755
--- a/forms/common-themes/src/main/resources/theme/admin/base/resources/partials/application-credentials.html
+++ b/forms/common-themes/src/main/resources/theme/admin/base/resources/partials/application-credentials.html
@@ -4,7 +4,7 @@
     <div id="content">
         <ol class="breadcrumb" data-ng-hide="create">
             <li><a href="#/realms/{{realm.realm}}/applications">Applications</a></li>
-            <li><a href="#/realms/{{realm.realm}}/applications/{{application.name}}">{{application.name}}</a></li>
+            <li><a href="#/realms/{{realm.realm}}/applications/{{application.id}}">{{application.name}}</a></li>
             <li class="active">Claims</li>
         </ol>
         <h2 data-ng-hide="create"><span>{{application.name}}</span> Credentials</h2>
diff --git a/forms/common-themes/src/main/resources/theme/admin/base/resources/partials/application-detail.html b/forms/common-themes/src/main/resources/theme/admin/base/resources/partials/application-detail.html
index e23199a..00eec89 100755
--- a/forms/common-themes/src/main/resources/theme/admin/base/resources/partials/application-detail.html
+++ b/forms/common-themes/src/main/resources/theme/admin/base/resources/partials/application-detail.html
@@ -4,7 +4,7 @@
     <div id="content">
         <ol class="breadcrumb" data-ng-hide="create">
             <li><a href="#/realms/{{realm.realm}}/applications">Applications</a></li>
-            <li><a href="#/realms/{{realm.realm}}/applications/{{application.name}}">{{application.name}}</a></li>
+            <li><a href="#/realms/{{realm.realm}}/applications/{{application.id}}">{{application.name}}</a></li>
             <li class="active">Settings</li>
         </ol>
         <ol class="breadcrumb" data-ng-show="create">
@@ -31,6 +31,19 @@
                     <span tooltip-placement="right" tooltip="Disabled applications cannot initiate a login or have obtain access tokens." class="fa fa-info-circle"></span>
                 </div>
                 <div class="form-group">
+                    <label class="col-sm-2 control-label" for="protocol">Client Protocol</label>
+                    <div class="col-sm-6">
+                        <div class="select-kc">
+                            <select id="protocol"
+                                    ng-change="changeProtocol()"
+                                    ng-model="protocol"
+                                    ng-options="aProtocol for aProtocol in protocols">
+                            </select>
+                        </div>
+                    </div>
+                    <span tooltip-placement="right" tooltip="'Confidential' applications require a secret to initiate login protocol.  'Public' clients do not require a secret.  'Bearer-only' applications are web services that never initiate a login." class="fa fa-info-circle"></span>
+                </div>
+                <div class="form-group" data-ng-show="protocol == 'openid-connect'">
                     <label class="col-sm-2 control-label" for="accessType">Access Type</label>
                     <div class="col-sm-6">
                         <div class="select-kc">
@@ -43,6 +56,28 @@
                     </div>
                     <span tooltip-placement="right" tooltip="'Confidential' applications require a secret to initiate login protocol.  'Public' clients do not require a secret.  'Bearer-only' applications are web services that never initiate a login." class="fa fa-info-circle"></span>
                 </div>
+                <div class="form-group clearfix block" data-ng-show="protocol == 'saml'">
+                    <label class="col-sm-2 control-label" for="samlServerSignature">Server Signatures</label>
+                    <div class="col-sm-6">
+                        <input ng-model="samlServerSignature" ng-click="switchChange()" name="samlServerSignature" id="samlServerSignature" onoffswitch />
+                    </div>
+                    <span tooltip-placement="right" tooltip="Should server sent SAML requests and responses be signed by the realm?" class="fa fa-info-circle"></span>
+                </div>
+                <div class="form-group clearfix block" data-ng-show="protocol == 'saml'">
+                    <label class="col-sm-2 control-label" for="samlServerEncrypt">Server Encryption</label>
+                    <div class="col-sm-6">
+                        <input ng-model="samlServerEncrypt" ng-click="switchChange()" name="samlServerEncrypt" id="samlServerEncrypt" onoffswitch />
+                    </div>
+                    <span tooltip-placement="right" tooltip="Should server sent SAML requests and responses be encrypted by the realm?" class="fa fa-info-circle"></span>
+                </div>
+                <div class="form-group clearfix block" data-ng-show="protocol == 'saml'">
+                    <label class="col-sm-2 control-label" for="samlClientSignature">Client Signatures</label>
+                    <div class="col-sm-6">
+                        <input ng-model="samlClientSignature" ng-click="switchChange()" name="samlClientSignature" id="samlClientSignature" onoffswitch />
+                    </div>
+                    <span tooltip-placement="right" tooltip="Will the client sign their saml requests and responses?  And should they be validated?" class="fa fa-info-circle"></span>
+                </div>
+
                 <div class="form-group" data-ng-show="!application.bearerOnly">
                     <label class="col-sm-2 control-label" for="newRedirectUri">Redirect URI <span class="required" data-ng-show="create">*</span></label>
                     <div class="col-sm-6 multiple" ng-repeat="redirectUri in application.redirectUris">
diff --git a/forms/common-themes/src/main/resources/theme/admin/base/resources/partials/application-installation.html b/forms/common-themes/src/main/resources/theme/admin/base/resources/partials/application-installation.html
index 001bc30..e70db27 100755
--- a/forms/common-themes/src/main/resources/theme/admin/base/resources/partials/application-installation.html
+++ b/forms/common-themes/src/main/resources/theme/admin/base/resources/partials/application-installation.html
@@ -5,7 +5,7 @@
     <div id="content">
         <ol class="breadcrumb" data-ng-hide="create">
             <li><a href="#/realms/{{realm.realm}}/applications">Applications</a></li>
-            <li><a href="#/realms/{{realm.realm}}/applications/{{application.name}}">{{application.name}}</a></li>
+            <li><a href="#/realms/{{realm.realm}}/applications/{{application.id}}">{{application.name}}</a></li>
             <li class="active">Installation</li>
         </ol>
         <h2><span>{{application.name}}</span> Adapter Installation <span tooltip-placement="right" tooltip="Helper utility for generating various client adapter configuration formats which you can download or cut and paste to configure your client applications." class="fa fa-info-circle"></span></h2>
diff --git a/forms/common-themes/src/main/resources/theme/admin/base/resources/partials/application-list.html b/forms/common-themes/src/main/resources/theme/admin/base/resources/partials/application-list.html
index fa4997d..f6eec65 100755
--- a/forms/common-themes/src/main/resources/theme/admin/base/resources/partials/application-list.html
+++ b/forms/common-themes/src/main/resources/theme/admin/base/resources/partials/application-list.html
@@ -43,7 +43,7 @@
             </tfoot>-->
             <tbody>
             <tr ng-repeat="app in applications | filter:search">
-                <td><a href="#/realms/{{realm.realm}}/applications/{{app.name}}">{{app.name}}</a></td>
+                <td><a href="#/realms/{{realm.realm}}/applications/{{app.id}}">{{app.name}}</a></td>
                 <td>{{app.enabled}}</td>
                 <td ng-class="{'text-muted': !app.baseUrl}">
                     <a href="{{app.baseUrl}}" data-ng-show="app.baseUrl">{{app.baseUrl}}</a>
diff --git a/forms/common-themes/src/main/resources/theme/admin/base/resources/partials/application-revocation.html b/forms/common-themes/src/main/resources/theme/admin/base/resources/partials/application-revocation.html
index 20e750f..7430b50 100755
--- a/forms/common-themes/src/main/resources/theme/admin/base/resources/partials/application-revocation.html
+++ b/forms/common-themes/src/main/resources/theme/admin/base/resources/partials/application-revocation.html
@@ -4,7 +4,7 @@
     <div id="content">
         <ol class="breadcrumb">
             <li><a href="#/realms/{{realm.realm}}/applications">Applications</a></li>
-            <li><a href="#/realms/{{realm.realm}}/applications/{{application.name}}">{{application.name}}</a></li>
+            <li><a href="#/realms/{{realm.realm}}/applications/{{application.id}}">{{application.name}}</a></li>
             <li class="active">Revocation</li>
         </ol>
         <h2 data-ng-hide="create"><span>{{application.name}}</span> Revocation Policies</h2>
diff --git a/forms/common-themes/src/main/resources/theme/admin/base/resources/partials/application-role-detail.html b/forms/common-themes/src/main/resources/theme/admin/base/resources/partials/application-role-detail.html
index f5704ea..e0ff6a6 100755
--- a/forms/common-themes/src/main/resources/theme/admin/base/resources/partials/application-role-detail.html
+++ b/forms/common-themes/src/main/resources/theme/admin/base/resources/partials/application-role-detail.html
@@ -4,15 +4,15 @@
     <div id="content">
         <ol class="breadcrumb" data-ng-show="create">
             <li><a href="#/realms/{{realm.realm}}/applications">Applications</a></li>
-            <li><a href="#/realms/{{realm.realm}}/applications/{{application.name}}">{{application.name}}</a></li>
-            <li><a href="#/realms/{{realm.realm}}/applications/{{application.name}}/roles">Roles</a></li>
+            <li><a href="#/realms/{{realm.realm}}/applications/{{application.id}}">{{application.name}}</a></li>
+            <li><a href="#/realms/{{realm.realm}}/applications/{{application.id}}/roles">Roles</a></li>
             <li class="active">Add role</li>
         </ol>
 
         <ol class="breadcrumb" data-ng-hide="create">
             <li><a href="#/realms/{{realm.realm}}/applications">Applications</a></li>
-            <li><a href="#/realms/{{realm.realm}}/applications/{{application.name}}">{{application.name}}</a></li>
-            <li><a href="#/realms/{{realm.realm}}/applications/{{application.name}}/roles">Roles</a></li>
+            <li><a href="#/realms/{{realm.realm}}/applications/{{application.id}}">{{application.name}}</a></li>
+            <li><a href="#/realms/{{realm.realm}}/applications/{{application.id}}/roles">Roles</a></li>
             <li class="active">{{role.name}}</li>
         </ol>
 
diff --git a/forms/common-themes/src/main/resources/theme/admin/base/resources/partials/application-role-list.html b/forms/common-themes/src/main/resources/theme/admin/base/resources/partials/application-role-list.html
index 63ab8d0..e21b12d 100755
--- a/forms/common-themes/src/main/resources/theme/admin/base/resources/partials/application-role-list.html
+++ b/forms/common-themes/src/main/resources/theme/admin/base/resources/partials/application-role-list.html
@@ -5,7 +5,7 @@
     <div id="content">
         <ol class="breadcrumb" data-ng-hide="create">
             <li><a href="#/realms/{{realm.realm}}/applications">Applications</a></li>
-            <li><a href="#/realms/{{realm.realm}}/applications/{{application.name}}">{{application.name}}</a></li>
+            <li><a href="#/realms/{{realm.realm}}/applications/{{application.id}}">{{application.name}}</a></li>
             <li class="active">Roles</li>
         </ol>
         <h2><span>{{application.name}}</span> Application Roles</h2>
@@ -14,7 +14,7 @@
             <tr>
                 <th class="kc-table-actions" colspan="3" data-ng-show="access.manageApplications">
                     <div class="pull-right">
-                        <a class="btn btn-primary" href="#/create/role/{{realm.realm}}/applications/{{application.name}}">Add Role</a>
+                        <a class="btn btn-primary" href="#/create/role/{{realm.realm}}/applications/{{application.id}}">Add Role</a>
                         <!-- <button class="remove disabled">Remove</button> -->
                     </div>
                 </th>
@@ -52,7 +52,7 @@
             -->
             <tbody>
             <tr ng-repeat="role in roles">
-                <td><a href="#/realms/{{realm.realm}}/applications/{{application.name}}/roles/{{role.name}}">{{role.name}}</a></td>
+                <td><a href="#/realms/{{realm.realm}}/applications/{{application.id}}/roles/{{role.name}}">{{role.name}}</a></td>
                 <td>{{role.composite}}</td>
                 <td>{{role.description}}</td>
             </tr>
diff --git a/forms/common-themes/src/main/resources/theme/admin/base/resources/partials/application-scope-mappings.html b/forms/common-themes/src/main/resources/theme/admin/base/resources/partials/application-scope-mappings.html
index 1cdbcd8..19c69d5 100755
--- a/forms/common-themes/src/main/resources/theme/admin/base/resources/partials/application-scope-mappings.html
+++ b/forms/common-themes/src/main/resources/theme/admin/base/resources/partials/application-scope-mappings.html
@@ -5,7 +5,7 @@
     <div id="content">
         <ol class="breadcrumb" data-ng-hide="create">
             <li><a href="#/realms/{{realm.realm}}/applications">Applications</a></li>
-            <li><a href="#/realms/{{realm.realm}}/applications/{{application.name}}">{{application.name}}</a></li>
+            <li><a href="#/realms/{{realm.realm}}/applications/{{application.id}}">{{application.name}}</a></li>
             <li class="active">Scope</li>
         </ol>
         <h2><span>{{application.name}}</span> Scope Mappings <span tooltip-placement="right" tooltip="Scope mappings allow you to restrict which user role mappings are included within the access token requested by the application." class="fa fa-info-circle"></span></h2>
diff --git a/forms/common-themes/src/main/resources/theme/admin/base/resources/partials/application-sessions.html b/forms/common-themes/src/main/resources/theme/admin/base/resources/partials/application-sessions.html
index 970c4ea..2a7360d 100755
--- a/forms/common-themes/src/main/resources/theme/admin/base/resources/partials/application-sessions.html
+++ b/forms/common-themes/src/main/resources/theme/admin/base/resources/partials/application-sessions.html
@@ -4,7 +4,7 @@
     <div id="content">
         <ol class="breadcrumb" data-ng-hide="create">
             <li><a href="#/realms/{{realm.realm}}/applications">Applications</a></li>
-            <li><a href="#/realms/{{realm.realm}}/applications/{{application.name}}">{{application.name}}</a></li>
+            <li><a href="#/realms/{{realm.realm}}/applications/{{application.id}}">{{application.name}}</a></li>
             <li class="active">Application Sessions</li>
         </ol>
         <h2><span>{{application.name}}</span> Active Sessions  <span tooltip-placement="right" tooltip="View active sessions for this application.  Allows you to see which users are active and when they logged in." class="fa fa-info-circle"></span></h2>
diff --git a/forms/common-themes/src/main/resources/theme/admin/base/resources/partials/session-realm.html b/forms/common-themes/src/main/resources/theme/admin/base/resources/partials/session-realm.html
index 8752c2c..8730395 100755
--- a/forms/common-themes/src/main/resources/theme/admin/base/resources/partials/session-realm.html
+++ b/forms/common-themes/src/main/resources/theme/admin/base/resources/partials/session-realm.html
@@ -23,9 +23,9 @@
             </tr>
             </thead>
             <tbody>
-            <tr data-ng-repeat="(application, data) in stats">
-                <td><a href="#/realms/{{realm.realm}}/applications/{{application}}/sessions">{{application}}</a></td>
-                <td>{{data}}</td>
+            <tr data-ng-repeat="data in stats">
+                <td><a href="#/realms/{{realm.realm}}/applications/{{data.id}}/sessions">{{data.name}}</a></td>
+                <td>{{data.active}}</td>
             </tr>
             </tbody>
         </table>
diff --git a/forms/common-themes/src/main/resources/theme/admin/base/resources/partials/user-sessions.html b/forms/common-themes/src/main/resources/theme/admin/base/resources/partials/user-sessions.html
index 925248e..26fbab2 100755
--- a/forms/common-themes/src/main/resources/theme/admin/base/resources/partials/user-sessions.html
+++ b/forms/common-themes/src/main/resources/theme/admin/base/resources/partials/user-sessions.html
@@ -38,8 +38,8 @@
                 <td>{{session.start | date:'medium'}}</td>
                 <td>{{session.lastAccess | date:'medium'}}</td>
                 <td>
-                    <div data-ng-repeat="app in session.applications">
-                        <a href="#/realms/{{realm.realm}}/applications/{{app}}/sessions">{{app}}</a>
+                    <div data-ng-repeat="(id, name) in session.applications">
+                        <a href="#/realms/{{realm.realm}}/applications/{{id}}">{{name}}</a>
                     </div>
                 </ul>
                 </td>
diff --git a/forms/common-themes/src/main/resources/theme/admin/base/resources/templates/kc-navigation-application.html b/forms/common-themes/src/main/resources/theme/admin/base/resources/templates/kc-navigation-application.html
old mode 100644
new mode 100755
index a68856c..7df8e71
--- a/forms/common-themes/src/main/resources/theme/admin/base/resources/templates/kc-navigation-application.html
+++ b/forms/common-themes/src/main/resources/theme/admin/base/resources/templates/kc-navigation-application.html
@@ -1,10 +1,10 @@
 <ul class="nav nav-tabs nav-tabs-pf"  data-ng-show="!create">
-    <li ng-class="{active: !path[4]}"><a href="#/realms/{{realm.realm}}/applications/{{application.name}}">Settings</a></li>
-    <li ng-class="{active: path[4] == 'credentials'}" data-ng-show="!application.bearerOnly && !application.publicClient"><a href="#/realms/{{realm.realm}}/applications/{{application.name}}/credentials">Credentials</a></li>
-    <li ng-class="{active: path[4] == 'roles'}"><a href="#/realms/{{realm.realm}}/applications/{{application.name}}/roles">Roles</a></li>
-    <li ng-class="{active: path[4] == 'claims'}" data-ng-show="!application.bearerOnly"><a href="#/realms/{{realm.realm}}/applications/{{application.name}}/claims">Claims</a></li>
-    <li ng-class="{active: path[4] == 'scope-mappings'}" data-ng-show="!application.bearerOnly"><a href="#/realms/{{realm.realm}}/applications/{{application.name}}/scope-mappings">Scope</a></li>
-    <li ng-class="{active: path[4] == 'revocation'}"><a href="#/realms/{{realm.realm}}/applications/{{application.name}}/revocation">Revocation</a></li>
-    <li ng-class="{active: path[4] == 'sessions'}" data-ng-show="!application.bearerOnly"><a href="#/realms/{{realm.realm}}/applications/{{application.name}}/sessions">Sessions</a></li>
-    <li ng-class="{active: path[4] == 'installation'}"><a href="#/realms/{{realm.realm}}/applications/{{application.name}}/installation">Installation</a></li>
+    <li ng-class="{active: !path[4]}"><a href="#/realms/{{realm.realm}}/applications/{{application.id}}">Settings</a></li>
+    <li ng-class="{active: path[4] == 'credentials'}" data-ng-show="!application.bearerOnly && !application.publicClient && application.protocol != 'saml'"><a href="#/realms/{{realm.realm}}/applications/{{application.id}}/credentials">Credentials</a></li>
+    <li ng-class="{active: path[4] == 'roles'}"><a href="#/realms/{{realm.realm}}/applications/{{application.id}}/roles">Roles</a></li>
+    <li ng-class="{active: path[4] == 'claims'}" data-ng-show="!application.bearerOnly"><a href="#/realms/{{realm.realm}}/applications/{{application.id}}/claims">Claims</a></li>
+    <li ng-class="{active: path[4] == 'scope-mappings'}" data-ng-show="!application.bearerOnly"><a href="#/realms/{{realm.realm}}/applications/{{application.id}}/scope-mappings">Scope</a></li>
+    <li ng-class="{active: path[4] == 'revocation'}"><a href="#/realms/{{realm.realm}}/applications/{{application.id}}/revocation">Revocation</a></li>
+    <li ng-class="{active: path[4] == 'sessions'}" data-ng-show="!application.bearerOnly"><a href="#/realms/{{realm.realm}}/applications/{{application.id}}/sessions">Sessions</a></li>
+    <li ng-class="{active: path[4] == 'installation'}"><a href="#/realms/{{realm.realm}}/applications/{{application.id}}/installation">Installation</a></li>
 </ul>
\ No newline at end of file
diff --git a/model/api/src/main/java/org/keycloak/models/ClientModel.java b/model/api/src/main/java/org/keycloak/models/ClientModel.java
index 9ca5a70..61e1574 100755
--- a/model/api/src/main/java/org/keycloak/models/ClientModel.java
+++ b/model/api/src/main/java/org/keycloak/models/ClientModel.java
@@ -1,5 +1,6 @@
 package org.keycloak.models;
 
+import java.util.Map;
 import java.util.Set;
 
 /**
@@ -53,6 +54,15 @@ public interface ClientModel {
     boolean isFullScopeAllowed();
     void setFullScopeAllowed(boolean value);
 
+    String getProtocol();
+    void setProtocol(String protocol);
+
+    void setAttribute(String name, String value);
+    void removeAttribute(String name);
+    String getAttribute(String name);
+    Map<String, String> getAttributes();
+
+
     boolean isPublicClient();
     void setPublicClient(boolean flag);
 
diff --git a/model/api/src/main/java/org/keycloak/models/entities/ClientEntity.java b/model/api/src/main/java/org/keycloak/models/entities/ClientEntity.java
index 0d23c35..3ca5761 100755
--- a/model/api/src/main/java/org/keycloak/models/entities/ClientEntity.java
+++ b/model/api/src/main/java/org/keycloak/models/entities/ClientEntity.java
@@ -1,7 +1,9 @@
 package org.keycloak.models.entities;
 
 import java.util.ArrayList;
+import java.util.HashMap;
 import java.util.List;
+import java.util.Map;
 
 /**
  * @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
@@ -11,12 +13,15 @@ public class ClientEntity extends AbstractIdentifiableEntity {
     private String name;
     private boolean enabled;
     private String secret;
+    private String protocol;
     private long allowedClaimsMask;
     private int notBefore;
     private boolean publicClient;
     private boolean fullScopeAllowed;
 
     private String realmId;
+    private Map<String, String> attributes = new HashMap<String, String>();
+
 
     private List<String> webOrigins = new ArrayList<String>();
     private List<String> redirectUris = new ArrayList<String>();
@@ -109,4 +114,20 @@ public class ClientEntity extends AbstractIdentifiableEntity {
     public void setFullScopeAllowed(boolean fullScopeAllowed) {
         this.fullScopeAllowed = fullScopeAllowed;
     }
+
+    public String getProtocol() {
+        return protocol;
+    }
+
+    public void setProtocol(String protocol) {
+        this.protocol = protocol;
+    }
+
+    public Map<String, String> getAttributes() {
+        return attributes;
+    }
+
+    public void setAttributes(Map<String, String> attributes) {
+        this.attributes = attributes;
+    }
 }
diff --git a/model/api/src/main/java/org/keycloak/models/utils/ModelToRepresentation.java b/model/api/src/main/java/org/keycloak/models/utils/ModelToRepresentation.java
index 0697680..0e78fdd 100755
--- a/model/api/src/main/java/org/keycloak/models/utils/ModelToRepresentation.java
+++ b/model/api/src/main/java/org/keycloak/models/utils/ModelToRepresentation.java
@@ -197,7 +197,7 @@ public class ModelToRepresentation {
         for (ClientSessionModel clientSession : session.getClientSessions()) {
             ClientModel client = clientSession.getClient();
             if (client instanceof ApplicationModel) {
-                rep.getApplications().add(client.getClientId());
+                rep.getApplications().put(client.getId(), client.getClientId());
             } else if (client instanceof OAuthClientModel) {
                 rep.getClients().put(client.getId(), client.getClientId());
             }
@@ -212,6 +212,8 @@ public class ModelToRepresentation {
         rep.setEnabled(applicationModel.isEnabled());
         rep.setAdminUrl(applicationModel.getManagementUrl());
         rep.setPublicClient(applicationModel.isPublicClient());
+        rep.setProtocol(applicationModel.getProtocol());
+        rep.setAttributes(applicationModel.getAttributes());
         rep.setFullScopeAllowed(applicationModel.isFullScopeAllowed());
         rep.setBearerOnly(applicationModel.isBearerOnly());
         rep.setSurrogateAuthRequired(applicationModel.isSurrogateAuthRequired());
@@ -241,6 +243,8 @@ public class ModelToRepresentation {
         rep.setName(model.getClientId());
         rep.setEnabled(model.isEnabled());
         rep.setPublicClient(model.isPublicClient());
+        rep.setProtocol(model.getProtocol());
+        rep.setAttributes(model.getAttributes());
         rep.setFullScopeAllowed(model.isFullScopeAllowed());
         rep.setDirectGrantsOnly(model.isDirectGrantsOnly());
         Set<String> redirectUris = model.getRedirectUris();
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 f3f3970..9d30bce 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
@@ -368,6 +368,7 @@ public class RepresentationToModel {
         applicationModel.setBaseUrl(resourceRep.getBaseUrl());
         if (resourceRep.isBearerOnly() != null) applicationModel.setBearerOnly(resourceRep.isBearerOnly());
         if (resourceRep.isPublicClient() != null) applicationModel.setPublicClient(resourceRep.isPublicClient());
+        if (resourceRep.getProtocol() != null) applicationModel.setProtocol(resourceRep.getProtocol());
         if (resourceRep.isFullScopeAllowed() != null) applicationModel.setFullScopeAllowed(resourceRep.isFullScopeAllowed());
         else applicationModel.setFullScopeAllowed(true);
         applicationModel.updateApplication();
@@ -381,6 +382,12 @@ public class RepresentationToModel {
             KeycloakModelUtils.generateSecret(applicationModel);
         }
 
+        if (resourceRep.getAttributes() != null) {
+            for (Map.Entry<String, String> entry : resourceRep.getAttributes().entrySet()) {
+                applicationModel.setAttribute(entry.getKey(), entry.getValue());
+            }
+        }
+
 
         if (resourceRep.getRedirectUris() != null) {
             for (String redirectUri : resourceRep.getRedirectUris()) {
@@ -438,6 +445,14 @@ public class RepresentationToModel {
         if (rep.isSurrogateAuthRequired() != null) resource.setSurrogateAuthRequired(rep.isSurrogateAuthRequired());
         resource.updateApplication();
 
+        if (rep.getProtocol() != null) resource.setProtocol(rep.getProtocol());
+        if (rep.getAttributes() != null) {
+            for (Map.Entry<String, String> entry : rep.getAttributes().entrySet()) {
+                resource.setAttribute(entry.getKey(), entry.getValue());
+            }
+        }
+
+
         if (rep.getNotBefore() != null) {
             resource.setNotBefore(rep.getNotBefore());
         }
@@ -565,6 +580,12 @@ public class RepresentationToModel {
         if (rep.getNotBefore() != null) {
             model.setNotBefore(rep.getNotBefore());
         }
+        if (rep.getProtocol() != null) model.setProtocol(rep.getProtocol());
+        if (rep.getAttributes() != null) {
+            for (Map.Entry<String, String> entry : rep.getAttributes().entrySet()) {
+                model.setAttribute(entry.getKey(), entry.getValue());
+            }
+        }
 
     }
 
diff --git a/model/invalidation-cache/model-adapters/src/main/java/org/keycloak/models/cache/ClientAdapter.java b/model/invalidation-cache/model-adapters/src/main/java/org/keycloak/models/cache/ClientAdapter.java
index 1565e43..854fa62 100755
--- a/model/invalidation-cache/model-adapters/src/main/java/org/keycloak/models/cache/ClientAdapter.java
+++ b/model/invalidation-cache/model-adapters/src/main/java/org/keycloak/models/cache/ClientAdapter.java
@@ -6,7 +6,9 @@ import org.keycloak.models.RoleContainerModel;
 import org.keycloak.models.RoleModel;
 import org.keycloak.models.cache.entities.CachedClient;
 
+import java.util.HashMap;
 import java.util.HashSet;
+import java.util.Map;
 import java.util.Set;
 
 /**
@@ -208,4 +210,43 @@ public abstract class ClientAdapter implements ClientModel {
         updatedClient.setNotBefore(notBefore);
     }
 
+    @Override
+    public String getProtocol() {
+        if (updatedClient != null) return updatedClient.getProtocol();
+        return cachedClient.getProtocol();
+    }
+
+    @Override
+    public void setProtocol(String protocol) {
+        getDelegateForUpdate();
+        updatedClient.setProtocol(protocol);
+    }
+
+    @Override
+    public void setAttribute(String name, String value) {
+        getDelegateForUpdate();
+        updatedClient.setAttribute(name, value);
+
+    }
+
+    @Override
+    public void removeAttribute(String name) {
+        getDelegateForUpdate();
+        updatedClient.removeAttribute(name);
+
+    }
+
+    @Override
+    public String getAttribute(String name) {
+        if (updatedClient != null) return updatedClient.getAttribute(name);
+        return cachedClient.getAttributes().get(name);
+    }
+
+    @Override
+    public Map<String, String> getAttributes() {
+        if (updatedClient != null) return updatedClient.getAttributes();
+        Map<String, String> copy = new HashMap<String, String>();
+        copy.putAll(cachedClient.getAttributes());
+        return copy;
+    }
 }
diff --git a/model/invalidation-cache/model-adapters/src/main/java/org/keycloak/models/cache/entities/CachedClient.java b/model/invalidation-cache/model-adapters/src/main/java/org/keycloak/models/cache/entities/CachedClient.java
index 5ee1e8d..484619f 100755
--- a/model/invalidation-cache/model-adapters/src/main/java/org/keycloak/models/cache/entities/CachedClient.java
+++ b/model/invalidation-cache/model-adapters/src/main/java/org/keycloak/models/cache/entities/CachedClient.java
@@ -6,7 +6,9 @@ import org.keycloak.models.RealmProvider;
 import org.keycloak.models.RoleModel;
 import org.keycloak.models.cache.RealmCache;
 
+import java.util.HashMap;
 import java.util.HashSet;
+import java.util.Map;
 import java.util.Set;
 
 /**
@@ -21,6 +23,8 @@ public class CachedClient {
     protected Set<String> redirectUris = new HashSet<String>();
     protected boolean enabled;
     protected String secret;
+    protected String protocol;
+    protected Map<String, String> attributes = new HashMap<String, String>();
     protected boolean publicClient;
     protected boolean fullScopeAllowed;
     protected boolean directGrantsOnly;
@@ -34,6 +38,8 @@ public class CachedClient {
         name = model.getClientId();
         this.realm = realm.getId();
         enabled = model.isEnabled();
+        protocol = model.getProtocol();
+        attributes.putAll(model.getAttributes());
         notBefore = model.getNotBefore();
         directGrantsOnly = model.isDirectGrantsOnly();
         publicClient = model.isPublicClient();
@@ -98,4 +104,12 @@ public class CachedClient {
     public boolean isFullScopeAllowed() {
         return fullScopeAllowed;
     }
+
+    public String getProtocol() {
+        return protocol;
+    }
+
+    public Map<String, String> getAttributes() {
+        return attributes;
+    }
 }
diff --git a/model/jpa/src/main/java/org/keycloak/models/jpa/ClientAdapter.java b/model/jpa/src/main/java/org/keycloak/models/jpa/ClientAdapter.java
index 16a370e..51257da 100755
--- a/model/jpa/src/main/java/org/keycloak/models/jpa/ClientAdapter.java
+++ b/model/jpa/src/main/java/org/keycloak/models/jpa/ClientAdapter.java
@@ -10,8 +10,10 @@ import org.keycloak.models.jpa.entities.ScopeMappingEntity;
 
 import javax.persistence.EntityManager;
 import javax.persistence.TypedQuery;
+import java.util.HashMap;
 import java.util.HashSet;
 import java.util.List;
+import java.util.Map;
 import java.util.Set;
 
 /**
@@ -247,4 +249,38 @@ public abstract class ClientAdapter implements ClientModel {
     public int hashCode() {
         return entity.getId().hashCode();
     }
+
+    @Override
+    public String getProtocol() {
+        return entity.getProtocol();
+    }
+
+    @Override
+    public void setProtocol(String protocol) {
+        entity.setProtocol(protocol);
+
+    }
+
+    @Override
+    public void setAttribute(String name, String value) {
+        entity.getAttributes().put(name, value);
+
+    }
+
+    @Override
+    public void removeAttribute(String name) {
+       entity.getAttributes().remove(name);
+    }
+
+    @Override
+    public String getAttribute(String name) {
+        return entity.getAttributes().get(name);
+    }
+
+    @Override
+    public Map<String, String> getAttributes() {
+        Map<String, String> copy = new HashMap<String, String>();
+        copy.putAll(entity.getAttributes());
+        return copy;
+    }
 }
diff --git a/model/jpa/src/main/java/org/keycloak/models/jpa/entities/ClientEntity.java b/model/jpa/src/main/java/org/keycloak/models/jpa/entities/ClientEntity.java
index 7bc66c3..c5652a8 100755
--- a/model/jpa/src/main/java/org/keycloak/models/jpa/entities/ClientEntity.java
+++ b/model/jpa/src/main/java/org/keycloak/models/jpa/entities/ClientEntity.java
@@ -10,9 +10,12 @@ import javax.persistence.Inheritance;
 import javax.persistence.InheritanceType;
 import javax.persistence.JoinColumn;
 import javax.persistence.ManyToOne;
+import javax.persistence.MapKeyColumn;
 import javax.persistence.Table;
 import javax.persistence.UniqueConstraint;
+import java.util.HashMap;
 import java.util.HashSet;
+import java.util.Map;
 import java.util.Set;
 
 /**
@@ -38,6 +41,8 @@ public abstract class ClientEntity {
     private int notBefore;
     @Column(name="PUBLIC_CLIENT")
     private boolean publicClient;
+    @Column(name="PROTOCOL")
+    private String protocol;
     @Column(name="FULL_SCOPE_ALLOWED")
     private boolean fullScopeAllowed;
 
@@ -55,6 +60,12 @@ public abstract class ClientEntity {
     @CollectionTable(name = "REDIRECT_URIS", joinColumns={ @JoinColumn(name="CLIENT_ID") })
     protected Set<String> redirectUris = new HashSet<String>();
 
+    @ElementCollection
+    @MapKeyColumn(name="NAME")
+    @Column(name="VALUE", length = 2048)
+    @CollectionTable(name="CLIENT_ATTRIBUTES", joinColumns={ @JoinColumn(name="CLIENT_ID") })
+    protected Map<String, String> attributes = new HashMap<String, String>();
+
     public RealmEntity getRealm() {
         return realm;
     }
@@ -142,4 +153,20 @@ public abstract class ClientEntity {
     public void setFullScopeAllowed(boolean fullScopeAllowed) {
         this.fullScopeAllowed = fullScopeAllowed;
     }
+
+    public Map<String, String> getAttributes() {
+        return attributes;
+    }
+
+    public void setAttributes(Map<String, String> attributes) {
+        this.attributes = attributes;
+    }
+
+    public String getProtocol() {
+        return protocol;
+    }
+
+    public void setProtocol(String protocol) {
+        this.protocol = protocol;
+    }
 }
diff --git a/model/mongo/src/main/java/org/keycloak/models/mongo/keycloak/adapters/ClientAdapter.java b/model/mongo/src/main/java/org/keycloak/models/mongo/keycloak/adapters/ClientAdapter.java
index dae9f4f..b549f36 100755
--- a/model/mongo/src/main/java/org/keycloak/models/mongo/keycloak/adapters/ClientAdapter.java
+++ b/model/mongo/src/main/java/org/keycloak/models/mongo/keycloak/adapters/ClientAdapter.java
@@ -12,8 +12,10 @@ import org.keycloak.models.mongo.keycloak.entities.MongoRoleEntity;
 import org.keycloak.models.mongo.utils.MongoModelUtils;
 
 import java.util.ArrayList;
+import java.util.HashMap;
 import java.util.HashSet;
 import java.util.List;
+import java.util.Map;
 import java.util.Set;
 
 /**
@@ -240,4 +242,42 @@ public abstract class ClientAdapter<T extends MongoIdentifiableEntity> extends A
         getMongoStore().pullItemFromList(this.getMongoEntity(), "scopeIds", role.getId(), invocationContext);
     }
 
+    @Override
+    public String getProtocol() {
+        return getMongoEntityAsClient().getProtocol();
+    }
+
+    @Override
+    public void setProtocol(String protocol) {
+        getMongoEntityAsClient().setProtocol(protocol);
+        updateMongoEntity();
+
+    }
+
+    @Override
+    public void setAttribute(String name, String value) {
+        getMongoEntityAsClient().getAttributes().put(name, value);
+        updateMongoEntity();
+
+    }
+
+    @Override
+    public void removeAttribute(String name) {
+        getMongoEntityAsClient().getAttributes().remove(name);
+        updateMongoEntity();
+    }
+
+    @Override
+    public String getAttribute(String name) {
+        return getMongoEntityAsClient().getAttributes().get(name);
+    }
+
+    @Override
+    public Map<String, String> getAttributes() {
+        Map<String, String> copy = new HashMap<String, String>();
+        copy.putAll(getMongoEntityAsClient().getAttributes());
+        return copy;
+    }
+
+
 }
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 240d5cb..e1402c9 100755
--- a/services/src/main/java/org/keycloak/services/managers/RealmManager.java
+++ b/services/src/main/java/org/keycloak/services/managers/RealmManager.java
@@ -18,6 +18,7 @@ import org.keycloak.models.UserModel;
 import org.keycloak.models.UserSessionProvider;
 import org.keycloak.models.utils.KeycloakModelUtils;
 import org.keycloak.models.utils.RepresentationToModel;
+import org.keycloak.protocol.oidc.OpenIDConnect;
 import org.keycloak.representations.idm.ApplicationRepresentation;
 import org.keycloak.representations.idm.RealmEventsConfigRepresentation;
 import org.keycloak.representations.idm.RealmRepresentation;
diff --git a/services/src/main/java/org/keycloak/services/resources/admin/ApplicationsByIdResource.java b/services/src/main/java/org/keycloak/services/resources/admin/ApplicationsByIdResource.java
new file mode 100755
index 0000000..f20b73d
--- /dev/null
+++ b/services/src/main/java/org/keycloak/services/resources/admin/ApplicationsByIdResource.java
@@ -0,0 +1,19 @@
+package org.keycloak.services.resources.admin;
+
+import org.keycloak.models.ApplicationModel;
+import org.keycloak.models.RealmModel;
+
+/**
+ * @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
+ * @version $Revision: 1 $
+ */
+public class ApplicationsByIdResource extends ApplicationsResource {
+    public ApplicationsByIdResource(RealmModel realm, RealmAuth auth) {
+        super(realm, auth);
+    }
+
+    @Override
+    protected ApplicationModel getApplicationByPathParam(String id) {
+        return realm.getApplicationById(id);
+    }
+}
diff --git a/services/src/main/java/org/keycloak/services/resources/admin/ApplicationsResource.java b/services/src/main/java/org/keycloak/services/resources/admin/ApplicationsResource.java
index 610e772..c96dcd7 100755
--- a/services/src/main/java/org/keycloak/services/resources/admin/ApplicationsResource.java
+++ b/services/src/main/java/org/keycloak/services/resources/admin/ApplicationsResource.java
@@ -102,7 +102,7 @@ public class ApplicationsResource {
      */
     @Path("{app-name}")
     public ApplicationResource getApplication(final @PathParam("app-name") String name) {
-        ApplicationModel applicationModel = realm.getApplicationByName(name);
+        ApplicationModel applicationModel = getApplicationByPathParam(name);
         if (applicationModel == null) {
             throw new NotFoundException("Could not find application: " + name);
         }
@@ -112,4 +112,8 @@ public class ApplicationsResource {
         return applicationResource;
     }
 
+    protected ApplicationModel getApplicationByPathParam(String name) {
+        return realm.getApplicationByName(name);
+    }
+
 }
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 b6ea102..9c6047a 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
@@ -42,6 +42,7 @@ import javax.ws.rs.core.MediaType;
 import javax.ws.rs.core.Response;
 import javax.ws.rs.core.UriInfo;
 import java.util.HashMap;
+import java.util.LinkedList;
 import java.util.List;
 import java.util.Map;
 
@@ -85,6 +86,19 @@ public class RealmAdminResource {
     }
 
     /**
+     * Base path for managing applications under this realm.
+     *
+     * @return
+     */
+    @Path("applications-by-id")
+    public ApplicationsByIdResource getApplicationsById() {
+        ApplicationsByIdResource applicationsResource = new ApplicationsByIdResource(realm, auth);
+        ResteasyProviderFactory.getInstance().injectProperties(applicationsResource);
+        //resourceContext.initResource(applicationsResource);
+        return applicationsResource;
+    }
+
+    /**
      * base path for managing oauth clients in this realm
      *
      * @return
@@ -271,6 +285,7 @@ public class RealmAdminResource {
     @GET
     @NoCache
     @Produces(MediaType.APPLICATION_JSON)
+    @Deprecated
     public Map<String, Integer> getApplicationSessionStats() {
         auth.requireView();
         Map<String, Integer> stats = new HashMap<String, Integer>();
@@ -283,6 +298,31 @@ public class RealmAdminResource {
     }
 
     /**
+     * Returns a JSON map.  The key is the application id, the value is the number of sessions that currently are active
+     * with that application.  Only application's that actually have a session associated with them will be in this map.
+     *
+     * @return
+     */
+    @Path("application-by-id-session-stats")
+    @GET
+    @NoCache
+    @Produces(MediaType.APPLICATION_JSON)
+    public List<Map<String, String>> getApplicationByIdSessionStats() {
+        auth.requireView();
+        List<Map<String, String>> data = new LinkedList<Map<String, String>>();
+        for (ApplicationModel application : realm.getApplications()) {
+            int size = session.sessions().getActiveUserSessions(application.getRealm(), application);
+            if (size == 0) continue;
+            Map<String, String> map = new HashMap<String, String>();
+            map.put("id", application.getId());
+            map.put("name", application.getName());
+            map.put("active", size + "");
+            data.add(map);
+        }
+        return data;
+    }
+
+    /**
      * View the events provider and how it is configured.
      *
      * @return
diff --git a/services/src/main/java/org/keycloak/services/resources/admin/RoleByIdResource.java b/services/src/main/java/org/keycloak/services/resources/admin/RoleByIdResource.java
index f14fc06..9f26e8d 100755
--- a/services/src/main/java/org/keycloak/services/resources/admin/RoleByIdResource.java
+++ b/services/src/main/java/org/keycloak/services/resources/admin/RoleByIdResource.java
@@ -169,7 +169,35 @@ public class RoleByIdResource extends RoleResource {
                                                                 final @PathParam("app") String appName) {
         RoleModel role = getRoleModel(id);
         auth.requireView();
-        return getApplicationRoleComposites(appName, role);
+        ApplicationModel app = realm.getApplicationByName(appName);
+        if (app == null) {
+            throw new NotFoundException("Could not find application: " + appName);
+
+        }
+        return getApplicationRoleComposites(app, role);
+    }
+
+    /**
+     * Return a set of application-level roles for a specific app that are in the role's composite
+     *
+     * @param id
+     * @param appId
+     * @return
+     */
+    @Path("{role-id}/composites/applications-by-id/{appId}")
+    @GET
+    @NoCache
+    @Produces("application/json")
+    public Set<RoleRepresentation> getApplicationByIdRoleComposites(final @PathParam("role-id") String id,
+                                                                final @PathParam("appId") String appId) {
+        RoleModel role = getRoleModel(id);
+        auth.requireView();
+        ApplicationModel app = realm.getApplicationById(appId);
+        if (app == null) {
+            throw new NotFoundException("Could not find application: " + appId);
+
+        }
+        return getApplicationRoleComposites(app, role);
     }
 
     /**
diff --git a/services/src/main/java/org/keycloak/services/resources/admin/RoleContainerResource.java b/services/src/main/java/org/keycloak/services/resources/admin/RoleContainerResource.java
index a4b6f58..5ee76af 100755
--- a/services/src/main/java/org/keycloak/services/resources/admin/RoleContainerResource.java
+++ b/services/src/main/java/org/keycloak/services/resources/admin/RoleContainerResource.java
@@ -2,6 +2,7 @@ package org.keycloak.services.resources.admin;
 
 import org.jboss.resteasy.annotations.cache.NoCache;
 import org.jboss.resteasy.spi.NotFoundException;
+import org.keycloak.models.ApplicationModel;
 import org.keycloak.models.ModelDuplicateException;
 import org.keycloak.models.RealmModel;
 import org.keycloak.models.RoleContainerModel;
@@ -222,7 +223,40 @@ public class RoleContainerResource extends RoleResource {
         if (role == null) {
             throw new NotFoundException("Could not find role: " + roleName);
         }
-        return getApplicationRoleComposites(appName, role);
+        ApplicationModel app = realm.getApplicationByName(appName);
+        if (app == null) {
+            throw new NotFoundException("Could not find application: " + appName);
+
+        }
+        return getApplicationRoleComposites(app, role);
+    }
+
+
+    /**
+     * An app-level roles for a specific app for this role's composite
+     *
+     * @param roleName role's name (not id!)
+     * @param appId
+     * @return
+     */
+    @Path("{role-name}/composites/application-by-id/{appId}")
+    @GET
+    @NoCache
+    @Produces("application/json")
+    public Set<RoleRepresentation> getApplicationByIdRoleComposites(final @PathParam("role-name") String roleName,
+                                                                final @PathParam("appId") String appId) {
+        auth.requireManage();
+
+        RoleModel role = roleContainer.getRole(roleName);
+        if (role == null) {
+            throw new NotFoundException("Could not find role: " + roleName);
+        }
+        ApplicationModel app = realm.getApplicationById(appId);
+        if (app == null) {
+            throw new NotFoundException("Could not find application: " + appId);
+
+        }
+        return getApplicationRoleComposites(app, role);
     }
 
 
diff --git a/services/src/main/java/org/keycloak/services/resources/admin/RoleResource.java b/services/src/main/java/org/keycloak/services/resources/admin/RoleResource.java
index 52bfae9..8d6fd44 100755
--- a/services/src/main/java/org/keycloak/services/resources/admin/RoleResource.java
+++ b/services/src/main/java/org/keycloak/services/resources/admin/RoleResource.java
@@ -69,15 +69,9 @@ public abstract class RoleResource {
         return composites;
     }
 
-    protected Set<RoleRepresentation> getApplicationRoleComposites(String appName, RoleModel role) {
+    protected Set<RoleRepresentation> getApplicationRoleComposites(ApplicationModel app, RoleModel role) {
         if (!role.isComposite() || role.getComposites().size() == 0) return Collections.emptySet();
 
-        ApplicationModel app = realm.getApplicationByName(appName);
-        if (app == null) {
-            throw new NotFoundException("Could not find application: " + appName);
-
-        }
-
         Set<RoleRepresentation> composites = new HashSet<RoleRepresentation>(role.getComposites().size());
         for (RoleModel composite : role.getComposites()) {
             if (composite.getContainer().equals(app))
diff --git a/services/src/main/java/org/keycloak/services/resources/admin/ScopeMappedApplicationResource.java b/services/src/main/java/org/keycloak/services/resources/admin/ScopeMappedApplicationResource.java
new file mode 100755
index 0000000..e61e6a0
--- /dev/null
+++ b/services/src/main/java/org/keycloak/services/resources/admin/ScopeMappedApplicationResource.java
@@ -0,0 +1,140 @@
+package org.keycloak.services.resources.admin;
+
+import org.jboss.resteasy.annotations.cache.NoCache;
+import org.jboss.resteasy.spi.NotFoundException;
+import org.keycloak.models.ApplicationModel;
+import org.keycloak.models.ClientModel;
+import org.keycloak.models.KeycloakSession;
+import org.keycloak.models.RealmModel;
+import org.keycloak.models.RoleModel;
+import org.keycloak.models.utils.ModelToRepresentation;
+import org.keycloak.representations.idm.RoleRepresentation;
+
+import javax.ws.rs.Consumes;
+import javax.ws.rs.DELETE;
+import javax.ws.rs.GET;
+import javax.ws.rs.POST;
+import javax.ws.rs.Path;
+import javax.ws.rs.PathParam;
+import javax.ws.rs.Produces;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Set;
+
+/**
+ * @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
+ * @version $Revision: 1 $
+ */
+public class ScopeMappedApplicationResource {
+    protected RealmModel realm;
+    private RealmAuth auth;
+    protected ClientModel client;
+    protected KeycloakSession session;
+    protected ApplicationModel app;
+
+    public ScopeMappedApplicationResource(RealmModel realm, RealmAuth auth, ClientModel client, KeycloakSession session, ApplicationModel app) {
+        this.realm = realm;
+        this.auth = auth;
+        this.client = client;
+        this.session = session;
+        this.app = app;
+    }
+
+    /**
+     * Get the roles associated with a client's scope for a specific application.
+     *
+     * @return
+     */
+    @GET
+    @Produces("application/json")
+    @NoCache
+    public List<RoleRepresentation> getApplicationScopeMappings() {
+        auth.requireView();
+
+        Set<RoleModel> mappings = app.getApplicationScopeMappings(client);
+        List<RoleRepresentation> mapRep = new ArrayList<RoleRepresentation>();
+        for (RoleModel roleModel : mappings) {
+            mapRep.add(ModelToRepresentation.toRepresentation(roleModel));
+        }
+        return mapRep;
+    }
+
+    /**
+     * The available application-level roles that can be associated with the client's scope
+     *
+     * @return
+     */
+    @Path("available")
+    @GET
+    @Produces("application/json")
+    @NoCache
+    public List<RoleRepresentation> getAvailableApplicationScopeMappings() {
+        auth.requireView();
+
+        Set<RoleModel> roles = app.getRoles();
+        return ScopeMappedResource.getAvailable(client, roles);
+    }
+
+    /**
+     * Get effective application roles that are associated with the client's scope for a specific application.
+     *
+     * @return
+     */
+    @Path("composite")
+    @GET
+    @Produces("application/json")
+    @NoCache
+    public List<RoleRepresentation> getCompositeApplicationScopeMappings() {
+        auth.requireView();
+
+        Set<RoleModel> roles = app.getRoles();
+        return ScopeMappedResource.getComposite(client, roles);
+    }
+
+    /**
+     * Add application-level roles to the client's scope
+     *
+     * @param roles
+     */
+    @POST
+    @Consumes("application/json")
+    public void addApplicationScopeMapping(List<RoleRepresentation> roles) {
+        auth.requireManage();
+
+        for (RoleRepresentation role : roles) {
+            RoleModel roleModel = app.getRole(role.getName());
+            if (roleModel == null) {
+                throw new NotFoundException("Role not found");
+            }
+            client.addScopeMapping(roleModel);
+        }
+
+    }
+
+    /**
+     * Remove application-level roles from the client's scope.
+     *
+     * @param roles
+     */
+    @DELETE
+    @Consumes("application/json")
+    public void deleteApplicationScopeMapping(List<RoleRepresentation> roles) {
+        auth.requireManage();
+
+        if (roles == null) {
+            Set<RoleModel> roleModels = app.getApplicationScopeMappings(client);
+            for (RoleModel roleModel : roleModels) {
+                client.deleteScopeMapping(roleModel);
+            }
+
+        } else {
+            for (RoleRepresentation role : roles) {
+                RoleModel roleModel = app.getRole(role.getName());
+                if (roleModel == null) {
+                    throw new NotFoundException("Role not found");
+                }
+                client.deleteScopeMapping(roleModel);
+            }
+        }
+    }
+}
diff --git a/services/src/main/java/org/keycloak/services/resources/admin/ScopeMappedResource.java b/services/src/main/java/org/keycloak/services/resources/admin/ScopeMappedResource.java
index 9da9085..8084c44 100755
--- a/services/src/main/java/org/keycloak/services/resources/admin/ScopeMappedResource.java
+++ b/services/src/main/java/org/keycloak/services/resources/admin/ScopeMappedResource.java
@@ -120,10 +120,10 @@ public class ScopeMappedResource {
         auth.requireView();
 
         Set<RoleModel> roles = realm.getRoles();
-        return getAvailable(roles);
+        return getAvailable(client, roles);
     }
 
-    private List<RoleRepresentation> getAvailable(Set<RoleModel> roles) {
+    public static List<RoleRepresentation> getAvailable(ClientModel client, Set<RoleModel> roles) {
         List<RoleRepresentation> available = new ArrayList<RoleRepresentation>();
         for (RoleModel roleModel : roles) {
             if (client.hasScope(roleModel)) continue;
@@ -147,10 +147,10 @@ public class ScopeMappedResource {
         auth.requireView();
 
         Set<RoleModel> roles = realm.getRoles();
-        return getComposite(roles);
+        return getComposite(client, roles);
     }
 
-    private List<RoleRepresentation> getComposite(Set<RoleModel> roles) {
+    public static List<RoleRepresentation> getComposite(ClientModel client, Set<RoleModel> roles) {
         List<RoleRepresentation> composite = new ArrayList<RoleRepresentation>();
         for (RoleModel roleModel : roles) {
             if (client.hasScope(roleModel)) composite.add(ModelToRepresentation.toRepresentation(roleModel));
@@ -201,146 +201,32 @@ public class ScopeMappedResource {
             for (RoleRepresentation role : roles) {
                 RoleModel roleModel = realm.getRoleById(role.getId());
                 if (roleModel == null) {
-                    throw new NotFoundException("Role not found");
+                    throw new NotFoundException("Application not found");
                 }
                 client.deleteScopeMapping(roleModel);
             }
         }
     }
 
-    /**
-     * Get the roles associated with a client's scope for a specific application.
-     *
-     * @param appName roles associated with client's scope for a specific application
-     * @return
-     */
     @Path("applications/{app}")
-    @GET
-    @Produces("application/json")
-    @NoCache
-    public List<RoleRepresentation> getApplicationScopeMappings(@PathParam("app") String appName) {
-        auth.requireView();
-
+    public ScopeMappedApplicationResource getApplicationScopeMappings(@PathParam("app") String appName) {
         ApplicationModel app = realm.getApplicationByName(appName);
 
         if (app == null) {
             throw new NotFoundException("Role not found");
         }
 
-        Set<RoleModel> mappings = app.getApplicationScopeMappings(client);
-        List<RoleRepresentation> mapRep = new ArrayList<RoleRepresentation>();
-        for (RoleModel roleModel : mappings) {
-            mapRep.add(ModelToRepresentation.toRepresentation(roleModel));
-        }
-        return mapRep;
-    }
-
-    /**
-     * The available application-level roles that can be associated with the client's scope
-     *
-     * @param appName available roles for a specific application
-     * @return
-     */
-    @Path("applications/{app}/available")
-    @GET
-    @Produces("application/json")
-    @NoCache
-    public List<RoleRepresentation> getAvailableApplicationScopeMappings(@PathParam("app") String appName) {
-        auth.requireView();
-
-        ApplicationModel app = realm.getApplicationByName(appName);
-
-        if (app == null) {
-            throw new NotFoundException("Role not found");
-        }
-
-        Set<RoleModel> roles = app.getRoles();
-        return getAvailable(roles);
-    }
-
-    /**
-     * Get effective application roles that are associated with the client's scope for a specific application.
-     *
-     * @param appName effective roles for a specific app
-     * @return
-     */
-    @Path("applications/{app}/composite")
-    @GET
-    @Produces("application/json")
-    @NoCache
-    public List<RoleRepresentation> getCompositeApplicationScopeMappings(@PathParam("app") String appName) {
-        auth.requireView();
-
-        ApplicationModel app = realm.getApplicationByName(appName);
-
-        if (app == null) {
-            throw new NotFoundException("Role not found");
-        }
-
-        Set<RoleModel> roles = app.getRoles();
-        return getComposite(roles);
-    }
-
-    /**
-     * Add application-level roles to the client's scope
-     *
-     * @param appName
-     * @param roles
-     */
-    @Path("applications/{app}")
-    @POST
-    @Consumes("application/json")
-    public void addApplicationScopeMapping(@PathParam("app") String appName, List<RoleRepresentation> roles) {
-        auth.requireManage();
-
-        ApplicationModel app = realm.getApplicationByName(appName);
-
-        if (app == null) {
-            throw new NotFoundException("Application not found");
-        }
-
-        for (RoleRepresentation role : roles) {
-            RoleModel roleModel = app.getRole(role.getName());
-            if (roleModel == null) {
-                throw new NotFoundException("Role not found");
-            }
-            client.addScopeMapping(roleModel);
-        }
-
+        return new ScopeMappedApplicationResource(realm, auth, client, session, app);
     }
 
-    /**
-     * Remove application-level roles from the client's scope.
-     *
-     * @param appName
-     * @param roles
-     */
-    @Path("applications/{app}")
-    @DELETE
-    @Consumes("application/json")
-    public void deleteApplicationScopeMapping(@PathParam("app") String appName, List<RoleRepresentation> roles) {
-        auth.requireManage();
-
-        ApplicationModel app = realm.getApplicationByName(appName);
+    @Path("applications-by-id/{appId}")
+    public ScopeMappedApplicationResource getApplicationByIdScopeMappings(@PathParam("appId") String appId) {
+        ApplicationModel app = realm.getApplicationById(appId);
 
         if (app == null) {
             throw new NotFoundException("Application not found");
         }
 
-        if (roles == null) {
-            Set<RoleModel> roleModels = app.getApplicationScopeMappings(client);
-            for (RoleModel roleModel : roleModels) {
-                client.deleteScopeMapping(roleModel);
-            }
-
-        } else {
-            for (RoleRepresentation role : roles) {
-                RoleModel roleModel = app.getRole(role.getName());
-                if (roleModel == null) {
-                    throw new NotFoundException("Role not found");
-                }
-                client.deleteScopeMapping(roleModel);
-            }
-        }
+        return new ScopeMappedApplicationResource(realm, auth, client, session, app);
     }
 }
diff --git a/services/src/main/java/org/keycloak/services/resources/admin/UserApplicationRoleMappingsResource.java b/services/src/main/java/org/keycloak/services/resources/admin/UserApplicationRoleMappingsResource.java
new file mode 100755
index 0000000..4c5b7d6
--- /dev/null
+++ b/services/src/main/java/org/keycloak/services/resources/admin/UserApplicationRoleMappingsResource.java
@@ -0,0 +1,175 @@
+package org.keycloak.services.resources.admin;
+
+import org.jboss.logging.Logger;
+import org.jboss.resteasy.annotations.cache.NoCache;
+import org.jboss.resteasy.spi.NotFoundException;
+import org.keycloak.ClientConnection;
+import org.keycloak.models.ApplicationModel;
+import org.keycloak.models.KeycloakSession;
+import org.keycloak.models.RealmModel;
+import org.keycloak.models.RoleModel;
+import org.keycloak.models.UserModel;
+import org.keycloak.models.utils.ModelToRepresentation;
+import org.keycloak.protocol.oidc.TokenManager;
+import org.keycloak.representations.idm.RoleRepresentation;
+
+import javax.ws.rs.Consumes;
+import javax.ws.rs.DELETE;
+import javax.ws.rs.GET;
+import javax.ws.rs.POST;
+import javax.ws.rs.Path;
+import javax.ws.rs.PathParam;
+import javax.ws.rs.Produces;
+import javax.ws.rs.core.Context;
+import javax.ws.rs.core.UriInfo;
+import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+
+/**
+ * @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
+ * @version $Revision: 1 $
+ */
+public class UserApplicationRoleMappingsResource {
+    protected static final Logger logger = Logger.getLogger(UserApplicationRoleMappingsResource.class);
+
+    protected RealmModel realm;
+    protected RealmAuth auth;
+    protected UserModel user;
+    protected ApplicationModel application;
+
+    public UserApplicationRoleMappingsResource(RealmModel realm, RealmAuth auth, UserModel user, ApplicationModel application) {
+        this.realm = realm;
+        this.auth = auth;
+        this.user = user;
+        this.application = application;
+    }
+
+    /**
+     * Get application-level role mappings for this user for a specific app
+     *
+     * @return
+     */
+    @GET
+    @Produces("application/json")
+    @NoCache
+    public List<RoleRepresentation> getApplicationRoleMappings() {
+        auth.requireView();
+
+        logger.debug("getApplicationRoleMappings");
+
+        Set<RoleModel> mappings = user.getApplicationRoleMappings(application);
+        List<RoleRepresentation> mapRep = new ArrayList<RoleRepresentation>();
+        for (RoleModel roleModel : mappings) {
+            mapRep.add(ModelToRepresentation.toRepresentation(roleModel));
+        }
+        logger.debugv("getApplicationRoleMappings.size() = {0}", mapRep.size());
+        return mapRep;
+    }
+
+    /**
+     * Get effective application-level role mappings.  This recurses any composite roles
+     *
+     * @return
+     */
+    @Path("composite")
+    @GET
+    @Produces("application/json")
+    @NoCache
+    public List<RoleRepresentation> getCompositeApplicationRoleMappings() {
+        auth.requireView();
+
+        logger.debug("getCompositeApplicationRoleMappings");
+
+        Set<RoleModel> roles = application.getRoles();
+        List<RoleRepresentation> mapRep = new ArrayList<RoleRepresentation>();
+        for (RoleModel roleModel : roles) {
+            if (user.hasRole(roleModel)) mapRep.add(ModelToRepresentation.toRepresentation(roleModel));
+        }
+        logger.debugv("getCompositeApplicationRoleMappings.size() = {0}", mapRep.size());
+        return mapRep;
+    }
+
+    /**
+     * Get available application-level roles that can be mapped to the user
+     *
+     * @return
+     */
+    @Path("available")
+    @GET
+    @Produces("application/json")
+    @NoCache
+    public List<RoleRepresentation> getAvailableApplicationRoleMappings() {
+        auth.requireView();
+
+        Set<RoleModel> available = application.getRoles();
+        return getAvailableRoles(user, available);
+    }
+
+    public static List<RoleRepresentation> getAvailableRoles(UserModel user, Set<RoleModel> available) {
+        Set<RoleModel> roles = new HashSet<RoleModel>();
+        for (RoleModel roleModel : available) {
+            if (user.hasRole(roleModel)) continue;
+            roles.add(roleModel);
+        }
+
+        List<RoleRepresentation> mappings = new ArrayList<RoleRepresentation>();
+        for (RoleModel roleModel : roles) {
+            mappings.add(ModelToRepresentation.toRepresentation(roleModel));
+        }
+        return mappings;
+    }
+
+    /**
+     * Add application-level roles to the user role mapping.
+     *
+      * @param roles
+     */
+    @POST
+    @Consumes("application/json")
+    public void addApplicationRoleMapping(List<RoleRepresentation> roles) {
+        auth.requireManage();
+
+        logger.debug("addApplicationRoleMapping");
+        for (RoleRepresentation role : roles) {
+            RoleModel roleModel = application.getRole(role.getName());
+            if (roleModel == null || !roleModel.getId().equals(role.getId())) {
+                throw new NotFoundException("Role not found");
+            }
+            user.grantRole(roleModel);
+        }
+
+    }
+
+    /**
+     * Delete application-level roles from user role mapping.
+     *
+     * @param roles
+     */
+    @DELETE
+    @Consumes("application/json")
+    public void deleteApplicationRoleMapping(List<RoleRepresentation> roles) {
+        auth.requireManage();
+
+        if (roles == null) {
+            Set<RoleModel> roleModels = user.getApplicationRoleMappings(application);
+            for (RoleModel roleModel : roleModels) {
+                if (!(roleModel.getContainer() instanceof ApplicationModel)) {
+                    ApplicationModel app = (ApplicationModel) roleModel.getContainer();
+                    if (!app.getId().equals(application.getId())) continue;
+                }
+                user.deleteRoleMapping(roleModel);
+            }
+
+        } else {
+            for (RoleRepresentation role : roles) {
+                RoleModel roleModel = application.getRole(role.getName());
+                if (roleModel == null || !roleModel.getId().equals(role.getId())) {
+                    throw new NotFoundException("Role not found");
+                }
+                user.deleteRoleMapping(roleModel);
+            }
+        }
+    }
+}
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 0873314..5eff07b 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
@@ -519,7 +519,7 @@ public class UsersResource {
         }
 
         Set<RoleModel> available = realm.getRoles();
-        return getAvailableRoles(user, available);
+        return UserApplicationRoleMappingsResource.getAvailableRoles(user, available);
     }
 
     /**
@@ -586,136 +586,8 @@ public class UsersResource {
         }
     }
 
-    /**
-     * Get application-level role mappings for this user for a specific app
-     *
-     * @param username username (not id!)
-     * @param appName app name (not id!)
-     * @return
-     */
-    @Path("{username}/role-mappings/applications/{app}")
-    @GET
-    @Produces("application/json")
-    @NoCache
-    public List<RoleRepresentation> getApplicationRoleMappings(@PathParam("username") String username, @PathParam("app") String appName) {
-        auth.requireView();
-
-        logger.debug("getApplicationRoleMappings");
-
-        UserModel user = session.users().getUserByUsername(username, realm);
-        if (user == null) {
-            throw new NotFoundException("User not found");
-        }
-
-        ApplicationModel application = realm.getApplicationByName(appName);
-
-        if (application == null) {
-            throw new NotFoundException("Application not found");
-        }
-
-        Set<RoleModel> mappings = user.getApplicationRoleMappings(application);
-        List<RoleRepresentation> mapRep = new ArrayList<RoleRepresentation>();
-        for (RoleModel roleModel : mappings) {
-            mapRep.add(ModelToRepresentation.toRepresentation(roleModel));
-        }
-        logger.debugv("getApplicationRoleMappings.size() = {0}", mapRep.size());
-        return mapRep;
-    }
-
-    /**
-     * Get effective application-level role mappings.  This recurses any composite roles
-     *
-     * @param username username (not id!)
-     * @param appName app name (not id!)
-     * @return
-     */
-    @Path("{username}/role-mappings/applications/{app}/composite")
-    @GET
-    @Produces("application/json")
-    @NoCache
-    public List<RoleRepresentation> getCompositeApplicationRoleMappings(@PathParam("username") String username, @PathParam("app") String appName) {
-        auth.requireView();
-
-        logger.debug("getCompositeApplicationRoleMappings");
-
-        UserModel user = session.users().getUserByUsername(username, realm);
-        if (user == null) {
-            throw new NotFoundException("User not found");
-        }
-
-        ApplicationModel application = realm.getApplicationByName(appName);
-
-        if (application == null) {
-            throw new NotFoundException("Application not found");
-        }
-
-        Set<RoleModel> roles = application.getRoles();
-        List<RoleRepresentation> mapRep = new ArrayList<RoleRepresentation>();
-        for (RoleModel roleModel : roles) {
-            if (user.hasRole(roleModel)) mapRep.add(ModelToRepresentation.toRepresentation(roleModel));
-        }
-        logger.debugv("getCompositeApplicationRoleMappings.size() = {0}", mapRep.size());
-        return mapRep;
-    }
-
-    /**
-     * Get available application-level roles that can be mapped to the user
-     *
-     * @param username username (not id!)
-     * @param appName app name (not id!)
-     * @return
-     */
-    @Path("{username}/role-mappings/applications/{app}/available")
-    @GET
-    @Produces("application/json")
-    @NoCache
-    public List<RoleRepresentation> getAvailableApplicationRoleMappings(@PathParam("username") String username, @PathParam("app") String appName) {
-        auth.requireView();
-
-        logger.debug("getApplicationRoleMappings");
-
-        UserModel user = session.users().getUserByUsername(username, realm);
-        if (user == null) {
-            throw new NotFoundException("User not found");
-        }
-
-        ApplicationModel application = realm.getApplicationByName(appName);
-
-        if (application == null) {
-            throw new NotFoundException("Application not found");
-        }
-        Set<RoleModel> available = application.getRoles();
-        return getAvailableRoles(user, available);
-    }
-
-    protected List<RoleRepresentation> getAvailableRoles(UserModel user, Set<RoleModel> available) {
-        Set<RoleModel> roles = new HashSet<RoleModel>();
-        for (RoleModel roleModel : available) {
-            if (user.hasRole(roleModel)) continue;
-            roles.add(roleModel);
-        }
-
-        List<RoleRepresentation> mappings = new ArrayList<RoleRepresentation>();
-        for (RoleModel roleModel : roles) {
-            mappings.add(ModelToRepresentation.toRepresentation(roleModel));
-        }
-        return mappings;
-    }
-
-    /**
-     * Add applicaiton-level roles to the user role mapping.
-     *
-     * @param username username (not id!)
-     * @param appName app name (not id!)
-     * @param roles
-     */
     @Path("{username}/role-mappings/applications/{app}")
-    @POST
-    @Consumes("application/json")
-    public void addApplicationRoleMapping(@PathParam("username") String username, @PathParam("app") String appName, List<RoleRepresentation> roles) {
-        auth.requireManage();
-
-        logger.debug("addApplicationRoleMapping");
+    public UserApplicationRoleMappingsResource getUserApplicationRoleMappingsResource(@PathParam("username") String username, @PathParam("app") String appName) {
         UserModel user = session.users().getUserByUsername(username, realm);
         if (user == null) {
             throw new NotFoundException("User not found");
@@ -727,61 +599,25 @@ public class UsersResource {
             throw new NotFoundException("Application not found");
         }
 
-        for (RoleRepresentation role : roles) {
-            RoleModel roleModel = application.getRole(role.getName());
-            if (roleModel == null || !roleModel.getId().equals(role.getId())) {
-                throw new NotFoundException("Role not found");
-            }
-            user.grantRole(roleModel);
-        }
+        return new UserApplicationRoleMappingsResource(realm, auth, user, application);
 
     }
-
-    /**
-     * Delete application-level roles from user role mapping.
-     *
-     * @param username username (not id!)
-     * @param appName app name (not id!)
-     * @param roles
-     */
-    @Path("{username}/role-mappings/applications/{app}")
-    @DELETE
-    @Consumes("application/json")
-    public void deleteApplicationRoleMapping(@PathParam("username") String username, @PathParam("app") String appName, List<RoleRepresentation> roles) {
-        auth.requireManage();
-
+    @Path("{username}/role-mappings/applications-by-id/{appId}")
+    public UserApplicationRoleMappingsResource getUserApplicationRoleMappingsResourceById(@PathParam("username") String username, @PathParam("appId") String appId) {
         UserModel user = session.users().getUserByUsername(username, realm);
         if (user == null) {
             throw new NotFoundException("User not found");
         }
 
-        ApplicationModel application = realm.getApplicationByName(appName);
+        ApplicationModel application = realm.getApplicationById(appId);
 
         if (application == null) {
             throw new NotFoundException("Application not found");
         }
 
-        if (roles == null) {
-            Set<RoleModel> roleModels = user.getApplicationRoleMappings(application);
-            for (RoleModel roleModel : roleModels) {
-                if (!(roleModel.getContainer() instanceof ApplicationModel)) {
-                    ApplicationModel app = (ApplicationModel) roleModel.getContainer();
-                    if (!app.getId().equals(application.getId())) continue;
-                }
-                user.deleteRoleMapping(roleModel);
-            }
+        return new UserApplicationRoleMappingsResource(realm, auth, user, application);
 
-        } else {
-            for (RoleRepresentation role : roles) {
-                RoleModel roleModel = application.getRole(role.getName());
-                if (roleModel == null || !roleModel.getId().equals(role.getId())) {
-                    throw new NotFoundException("Role not found");
-                }
-                user.deleteRoleMapping(roleModel);
-            }
-        }
     }
-
     /**
      *  Set up a temporary password for this user.  User will have to reset this temporary password when they log
      *  in next.