keycloak-aplcache
Changes
Details
diff --git a/admin-ui/src/main/resources/META-INF/resources/admin/js/app.js b/admin-ui/src/main/resources/META-INF/resources/admin/js/app.js
index 401be0c..aa32945 100755
--- a/admin-ui/src/main/resources/META-INF/resources/admin/js/app.js
+++ b/admin-ui/src/main/resources/META-INF/resources/admin/js/app.js
@@ -187,6 +187,12 @@ module.config([ '$routeProvider', function($routeProvider) {
},
role : function() {
return {};
+ },
+ roles : function(RoleListLoader) {
+ return RoleListLoader();
+ },
+ applications : function(ApplicationListLoader) {
+ return ApplicationListLoader();
}
},
controller : 'RoleDetailCtrl'
@@ -199,6 +205,12 @@ module.config([ '$routeProvider', function($routeProvider) {
},
role : function(RoleLoader) {
return RoleLoader();
+ },
+ roles : function(RoleListLoader) {
+ return RoleListLoader();
+ },
+ applications : function(ApplicationListLoader) {
+ return ApplicationListLoader();
}
},
controller : 'RoleDetailCtrl'
@@ -227,6 +239,12 @@ module.config([ '$routeProvider', function($routeProvider) {
},
role : function() {
return {};
+ },
+ roles : function(RoleListLoader) {
+ return RoleListLoader();
+ },
+ applications : function(ApplicationListLoader) {
+ return ApplicationListLoader();
}
},
controller : 'ApplicationRoleDetailCtrl'
@@ -242,6 +260,12 @@ module.config([ '$routeProvider', function($routeProvider) {
},
role : function(ApplicationRoleLoader) {
return ApplicationRoleLoader();
+ },
+ roles : function(RoleListLoader) {
+ return RoleListLoader();
+ },
+ applications : function(ApplicationListLoader) {
+ return ApplicationListLoader();
}
},
controller : 'ApplicationRoleDetailCtrl'
diff --git a/admin-ui/src/main/resources/META-INF/resources/admin/js/controllers/applications.js b/admin-ui/src/main/resources/META-INF/resources/admin/js/controllers/applications.js
index df955ad..20d5962 100755
--- a/admin-ui/src/main/resources/META-INF/resources/admin/js/controllers/applications.js
+++ b/admin-ui/src/main/resources/META-INF/resources/admin/js/controllers/applications.js
@@ -99,7 +99,9 @@ module.controller('ApplicationSessionsCtrl', function($scope, $location, realm,
$scope.application = application;
});
-module.controller('ApplicationRoleDetailCtrl', function($scope, realm, application, role, ApplicationRole, $location, Dialog, Notifications) {
+module.controller('ApplicationRoleDetailCtrl', function($scope, realm, application, role, roles, applications,
+ Role, ApplicationRole, RoleById, RoleRealmComposites, RoleApplicationComposites,
+ $http, $location, Dialog, Notifications) {
$scope.realm = realm;
$scope.application = application;
$scope.role = angular.copy(role);
@@ -107,18 +109,6 @@ module.controller('ApplicationRoleDetailCtrl', function($scope, realm, applicati
$scope.changed = $scope.create;
- $scope.$watch(function() {
- return $location.path();
- }, function() {
- $scope.path = $location.path().substring(1).split("/");
- });
-
- $scope.$watch('role', function() {
- if (!angular.equals($scope.role, role)) {
- $scope.changed = true;
- }
- }, true);
-
$scope.save = function() {
if ($scope.create) {
ApplicationRole.save({
@@ -134,27 +124,10 @@ module.controller('ApplicationRoleDetailCtrl', function($scope, realm, applicati
Notifications.success("The role has been created.");
});
} else {
- ApplicationRole.update({
- realm : realm.realm,
- application : application.name,
- role : role.name
- }, $scope.role, function() {
- $scope.changed = false;
- role = angular.copy($scope.role);
- Notifications.success("Your changes have been saved to the role.");
- });
+ $scope.update();
}
};
- $scope.reset = function() {
- $scope.role = angular.copy(role);
- $scope.changed = false;
- };
-
- $scope.cancel = function() {
- $location.url("/realms/" + realm.realm + "/applications/" + application.name + "/roles");
- };
-
$scope.remove = function() {
Dialog.confirmDelete($scope.role.name, 'role', function() {
$scope.role.$remove({
@@ -167,6 +140,16 @@ module.controller('ApplicationRoleDetailCtrl', function($scope, realm, applicati
});
});
};
+
+ $scope.cancel = function () {
+ $location.url("/realms/" + realm.realm + "/applications/" + application.name + "/roles");
+ };
+
+
+ roleControl($scope, realm, role, roles, applications,
+ ApplicationRole, RoleById, RoleRealmComposites, RoleApplicationComposites,
+ $http, $location, Notifications, Dialog);
+
});
module.controller('ApplicationListCtrl', function($scope, realm, applications, Application, $location) {
diff --git a/admin-ui/src/main/resources/META-INF/resources/admin/js/controllers/realm.js b/admin-ui/src/main/resources/META-INF/resources/admin/js/controllers/realm.js
index 3371766..3ff8682 100755
--- a/admin-ui/src/main/resources/META-INF/resources/admin/js/controllers/realm.js
+++ b/admin-ui/src/main/resources/META-INF/resources/admin/js/controllers/realm.js
@@ -675,26 +675,18 @@ module.controller('RoleListCtrl', function($scope, $location, realm, roles) {
});
});
-module.controller('RoleDetailCtrl', function($scope, realm, role, Role, $location, Dialog, Notifications) {
+
+module.controller('RoleDetailCtrl', function($scope, realm, role, roles, applications,
+ Role, ApplicationRole, RoleById, RoleRealmComposites, RoleApplicationComposites,
+ $http, $location, Dialog, Notifications) {
$scope.realm = realm;
$scope.role = angular.copy(role);
$scope.create = !role.name;
$scope.changed = $scope.create;
- $scope.$watch(function() {
- return $location.path();
- }, function() {
- $scope.path = $location.path().substring(1).split("/");
- });
-
- $scope.$watch('role', function() {
- if (!angular.equals($scope.role, role)) {
- $scope.changed = true;
- }
- }, true);
-
$scope.save = function() {
+ console.log('save');
if ($scope.create) {
Role.save({
realm: realm.realm
@@ -708,37 +700,31 @@ module.controller('RoleDetailCtrl', function($scope, realm, role, Role, $locatio
Notifications.success("The role has been created.");
});
} else {
- Role.update({
- realm : realm.realm,
- role : role.name
- }, $scope.role, function() {
- $scope.changed = false;
- role = angular.copy($scope.role);
- Notifications.success("Your changes have been saved to the role.");
- });
+ $scope.update();
}
};
- $scope.reset = function() {
- $scope.role = angular.copy(role);
- $scope.changed = false;
- };
-
- $scope.cancel = function() {
- $location.url("/realms/" + realm.realm + "/roles");
- };
-
- $scope.remove = function() {
- Dialog.confirmDelete($scope.role.name, 'role', function() {
+ $scope.remove = function () {
+ Dialog.confirmDelete($scope.role.name, 'role', function () {
$scope.role.$remove({
- realm : realm.realm,
- role : $scope.role.name
- }, function() {
+ realm: realm.realm,
+ role: $scope.role.name
+ }, function () {
$location.url("/realms/" + realm.realm + "/roles");
Notifications.success("The role has been deleted.");
});
});
};
+
+ $scope.cancel = function () {
+ $location.url("/realms/" + realm.realm + "/roles");
+ };
+
+
+
+ roleControl($scope, realm, role, roles, applications,
+ ApplicationRole, RoleById, RoleRealmComposites, RoleApplicationComposites,
+ $http, $location, Notifications, Dialog);
});
module.controller('RealmSMTPSettingsCtrl', function($scope, Current, Realm, realm, $http, $location, Dialog, Notifications) {
diff --git a/admin-ui/src/main/resources/META-INF/resources/admin/js/services.js b/admin-ui/src/main/resources/META-INF/resources/admin/js/services.js
index 193a8d3..33e47a9 100755
--- a/admin-ui/src/main/resources/META-INF/resources/admin/js/services.js
+++ b/admin-ui/src/main/resources/META-INF/resources/admin/js/services.js
@@ -1,453 +1,645 @@
-'use strict';
-
-var module = angular.module('keycloak.services', [ 'ngResource' ]);
-
-module.service('Dialog', function($dialog) {
- var dialog = {};
-
- var escapeHtml = function(str) {
- var div = document.createElement('div');
- div.appendChild(document.createTextNode(str));
- return div.innerHTML;
- };
-
- dialog.confirmDelete = function(name, type, success) {
- var title = 'Delete ' + escapeHtml(type.charAt(0).toUpperCase() + type.slice(1));
- var msg = '<span class="primary">Are you sure you want to permanently delete the ' + escapeHtml(type) + ' "' + escapeHtml(name) + '"?</span>' +
- '<span>This action can\'t be undone.</span>';
- var btns = [ {
- result : 'cancel',
- label : 'Cancel'
- }, {
- result : 'ok',
- label : 'Delete',
- cssClass : 'destructive'
- } ];
-
- $dialog.messageBox(title, msg, btns).open().then(function(result) {
- if (result == "ok") {
- success();
- }
- });
- }
-
- dialog.confirmGenerateKeys = function(name, type, success) {
- var title = 'Generate new keys for realm';
- var msg = '<span class="primary">Are you sure you want to permanently generate new keys for ' + name + '"?</span>' +
- '<span>This action can\'t be undone.</span>';
- var btns = [ {
- result : 'cancel',
- label : 'Cancel'
- }, {
- result : 'ok',
- label : 'Generate new keys',
- cssClass : 'destructive'
- } ];
-
- $dialog.messageBox(title, msg, btns).open().then(function(result) {
- if (result == "ok") {
- success();
- }
- });
- }
-
- return dialog
-});
-
-module.factory('Notifications', function($rootScope, $timeout) {
- // time (in ms) the notifications are shown
- var delay = 5000;
-
- var notifications = {};
-
- var scheduled = null;
- var schedulePop = function() {
- if (scheduled) {
- $timeout.cancel(scheduled);
- }
-
- scheduled = $timeout(function() {
- $rootScope.notification = null;
- scheduled = null;
- }, delay);
- };
-
- if (!$rootScope.notifications) {
- $rootScope.notifications = [];
- }
-
- notifications.message = function(type, header, message) {
- $rootScope.notification = {
- type : type,
- header: header,
- message : message
- };
-
- schedulePop();
- }
-
- notifications.info = function(message) {
- notifications.message("info", "Info!", message);
- };
-
- notifications.success = function(message) {
- notifications.message("success", "Success!", message);
- };
-
- notifications.error = function(message) {
- notifications.message("error", "Error!", message);
- };
-
- notifications.warn = function(message) {
- notifications.message("warn", "Warning!", message);
- };
-
- return notifications;
-});
-
-module.factory('Realm', function($resource) {
- return $resource('/auth/rest/admin/realms/:id', {
- id : '@realm'
- }, {
- update : {
- method : 'PUT'
- },
- create : {
- method : 'POST',
- params : { id : ''}
- }
-
- });
-});
-
-module.factory('User', function($resource) {
- return $resource('/auth/rest/admin/realms/:realm/users/:userId', {
- realm : '@realm',
- userId : '@userId'
- }, {
- update : {
- method : 'PUT'
- }
- });
-});
-
-module.factory('UserCredentials', function($resource) {
- return $resource('/auth/rest/admin/realms/:realm/users/:userId/credentials', {
- realm : '@realm',
- userId : '@userId'
- }, {
- update : {
- method : 'PUT',
- isArray : true
- }
- });
-});
-
-module.factory('RealmRoleMapping', function($resource) {
- return $resource('/auth/rest/admin/realms/:realm/users/:userId/role-mappings/realm', {
- realm : '@realm',
- userId : '@userId'
- });
-});
-
-module.factory('ApplicationRoleMapping', function($resource) {
- return $resource('/auth/rest/admin/realms/:realm/users/:userId/role-mappings/applications/:application', {
- realm : '@realm',
- userId : '@userId',
- application : "@application"
- });
-});
-
-module.factory('ApplicationRealmScopeMapping', function($resource) {
- return $resource('/auth/rest/admin/realms/:realm/applications/:application/scope-mappings/realm', {
- realm : '@realm',
- application : '@application'
- });
-});
-
-module.factory('ApplicationApplicationScopeMapping', function($resource) {
- return $resource('/auth/rest/admin/realms/:realm/applications/:application/scope-mappings/applications/:targetApp', {
- realm : '@realm',
- application : '@application',
- targetApp : '@targetApp'
- });
-});
-
-
-
-module.factory('RealmRoles', function($resource) {
- return $resource('/auth/rest/admin/realms/:realm/roles', {
- realm : '@realm'
- });
-});
-
-
-
-module.factory('Role', function($resource) {
- return $resource('/auth/rest/admin/realms/:realm/roles/:role', {
- realm : '@realm',
- role : '@role'
- }, {
- update : {
- method : 'PUT'
- }
- });
-});
-
-module.factory('ApplicationRole', function($resource) {
- return $resource('/auth/rest/admin/realms/:realm/applications/:application/roles/:role', {
- realm : '@realm',
- application : "@application",
- role : '@role'
- }, {
- update : {
- method : 'PUT'
- }
- });
-});
-
-
-module.factory('Application', function($resource) {
- return $resource('/auth/rest/admin/realms/:realm/applications/:application', {
- realm : '@realm',
- application : '@name'
- }, {
- update : {
- method : 'PUT'
- }
- });
-});
-
-module.factory('ApplicationInstallation', function($resource) {
- var url = '/auth/rest/admin/realms/:realm/applications/:application/installation';
- var resource = $resource('/auth/rest/admin/realms/:realm/applications/:application/installation', {
- realm : '@realm',
- application : '@application'
- }, {
- update : {
- method : 'PUT'
- }
- });
- resource.url = function(parameters) {
- return url.replace(':realm', parameters.realm).replace(':application', parameters.application);
- }
- return resource;
-});
-
-module.factory('ApplicationCredentials', function($resource) {
- return $resource('/auth/rest/admin/realms/:realm/applications/:application/credentials', {
- realm : '@realm',
- application : '@application'
- }, {
- update : {
- method : 'PUT',
- isArray : true
- }
- });
-});
-
-module.factory('ApplicationOrigins', function($resource) {
- return $resource('/auth/rest/admin/realms/:realm/applications/:application/allowed-origins', {
- realm : '@realm',
- application : '@application'
- }, {
- update : {
- method : 'PUT',
- isArray : true
- }
- });
-});
-
-module.factory('OAuthClient', function($resource) {
- return $resource('/auth/rest/admin/realms/:realm/oauth-clients/:id', {
- realm : '@realm',
- id : '@id'
- }, {
- update : {
- method : 'PUT'
- }
- });
-});
-
-module.factory('OAuthClientCredentials', function($resource) {
- return $resource('/auth/rest/admin/realms/:realm/oauth-clients/:oauth/credentials', {
- realm : '@realm',
- oauth : '@oauth'
- }, {
- update : {
- method : 'PUT',
- isArray : true
- }
- });
-});
-
-module.factory('OAuthClientRealmScopeMapping', function($resource) {
- return $resource('/auth/rest/admin/realms/:realm/oauth-clients/:oauth/scope-mappings/realm', {
- realm : '@realm',
- oauth : '@oauth'
- });
-});
-
-module.factory('OAuthClientApplicationScopeMapping', function($resource) {
- return $resource('/auth/rest/admin/realms/:realm/oauth-clients/:oauth/scope-mappings/applications/:targetApp', {
- realm : '@realm',
- oauth : '@oauth',
- targetApp : '@targetApp'
- });
-});
-
-module.factory('OAuthClientInstallation', function($resource) {
- var url = '/auth/rest/admin/realms/:realm/oauth-clients/:oauth/installation';
- var resource = $resource('/auth/rest/admin/realms/:realm/oauth-clients/:oauth/installation', {
- realm : '@realm',
- oauth : '@oauth'
- }, {
- update : {
- method : 'PUT'
- }
- });
- resource.url = function(parameters) {
- return url.replace(':realm', parameters.realm).replace(':oauth', parameters.oauth);
- }
- return resource;
-});
-
-
-module.factory('Current', function(Realm, $route) {
- var current = {};
-
- current.realms = {};
- current.realm = null;
- current.applications = {};
- current.application = null;
-
- current.refresh = function() {
- current.realm = null;
- current.realms = Realm.query(null, function(realms) {
- if ($route.current.params.realm) {
- for (var i = 0; i < realms.length; i++) {
- if (realms[i].realm == $route.current.params.realm) {
- current.realm = realms[i];
- }
- }
- }
- });
- }
-
- current.refresh();
-
- return current;
-});
-
-module.factory('TimeUnit', function() {
- var t = {};
-
- t.autoUnit = function(time) {
- var unit = 'Seconds';
- if (time % 60 == 0) {
- unit = 'Minutes';
- time = time / 60;
- }
- if (time % 60 == 0) {
- unit = 'Hours';
- time = time / 60;
- }
- if (time % 24 == 0) {
- unit = 'Days'
- time = time / 24;
- }
- return unit;
- }
-
- t.toSeconds = function(time, unit) {
- switch (unit) {
- case 'Seconds': return time;
- case 'Minutes': return time * 60;
- case 'Hours': return time * 360;
- case 'Days': return time * 86400;
- default: throw 'invalid unit ' + unit;
- }
- }
-
- t.toUnit = function(time, unit) {
- switch (unit) {
- case 'Seconds': return time;
- case 'Minutes': return Math.ceil(time / 60);
- case 'Hours': return Math.ceil(time / 360);
- case 'Days': return Math.ceil(time / 86400);
- default: throw 'invalid unit ' + unit;
- }
- }
-
- t.convert = function(time, from, to) {
- var seconds = t.toSeconds(time, from);
- return t.toUnit(seconds, to);
- }
-
- return t;
-});
-
-
-module.factory('PasswordPolicy', function() {
- var p = {};
-
- p.policyMessages = {
- length: "Minimal password length (integer type). Default value is 8.",
- digits: "Minimal number (integer type) of digits in password. Default value is 1.",
- lowerCase: "Minimal number (integer type) of lowercase characters in password. Default value is 1.",
- upperCase: "Minimal number (integer type) of uppercase characters in password. Default value is 1.",
- specialChars: "Minimal number (integer type) of special characters in password. Default value is 1."
- }
-
- p.allPolicies = [
- { name: 'length', value: 8 },
- { name: 'digits', value: 1 },
- { name: 'lowerCase', value: 1 },
- { name: 'upperCase', value: 1 },
- { name: 'specialChars', value: 1 }
- ];
-
- p.parse = function(policyString) {
- var policies = [];
-
- if (!policyString || policyString.length == 0){
- return policies;
- }
-
- var policyArray = policyString.split(" and ");
-
- for (var i = 0; i < policyArray.length; i ++){
- var policyToken = policyArray[i];
- var re = /(\w+)\(*(\d*)\)*/;
-
- var policyEntry = re.exec(policyToken);
-
- policies.push({ name: policyEntry[1], value: parseInt(policyEntry[2]) });
-
- }
-
- return policies;
- };
-
- p.toString = function(policies) {
- if (!policies || policies.length == 0) {
- return null;
- }
-
- var policyString = "";
-
- for (var i in policies){
- policyString += policies[i].name;
- if ( policies[i].value ){
- policyString += '(' + policies[i].value + ')';
- }
- policyString += " and ";
- }
-
- policyString = policyString.substring(0, policyString.length - 5);
-
- return policyString;
- };
-
- return p;
+'use strict';
+
+var module = angular.module('keycloak.services', [ 'ngResource' ]);
+
+module.service('Dialog', function($dialog) {
+ var dialog = {};
+
+ var escapeHtml = function(str) {
+ var div = document.createElement('div');
+ div.appendChild(document.createTextNode(str));
+ return div.innerHTML;
+ };
+
+ dialog.confirmDelete = function(name, type, success) {
+ var title = 'Delete ' + escapeHtml(type.charAt(0).toUpperCase() + type.slice(1));
+ var msg = '<span class="primary">Are you sure you want to permanently delete the ' + escapeHtml(type) + ' "' + escapeHtml(name) + '"?</span>' +
+ '<span>This action can\'t be undone.</span>';
+ var btns = [ {
+ result : 'cancel',
+ label : 'Cancel'
+ }, {
+ result : 'ok',
+ label : 'Delete',
+ cssClass : 'destructive'
+ } ];
+
+ $dialog.messageBox(title, msg, btns).open().then(function(result) {
+ if (result == "ok") {
+ success();
+ }
+ });
+ }
+
+ dialog.confirmGenerateKeys = function(name, type, success) {
+ var title = 'Generate new keys for realm';
+ var msg = '<span class="primary">Are you sure you want to permanently generate new keys for ' + name + '"?</span>' +
+ '<span>This action can\'t be undone.</span>';
+ var btns = [ {
+ result : 'cancel',
+ label : 'Cancel'
+ }, {
+ result : 'ok',
+ label : 'Generate new keys',
+ cssClass : 'destructive'
+ } ];
+
+ $dialog.messageBox(title, msg, btns).open().then(function(result) {
+ if (result == "ok") {
+ success();
+ }
+ });
+ }
+
+ return dialog
+});
+
+module.factory('Notifications', function($rootScope, $timeout) {
+ // time (in ms) the notifications are shown
+ var delay = 5000;
+
+ var notifications = {};
+
+ var scheduled = null;
+ var schedulePop = function() {
+ if (scheduled) {
+ $timeout.cancel(scheduled);
+ }
+
+ scheduled = $timeout(function() {
+ $rootScope.notification = null;
+ scheduled = null;
+ }, delay);
+ };
+
+ if (!$rootScope.notifications) {
+ $rootScope.notifications = [];
+ }
+
+ notifications.message = function(type, header, message) {
+ $rootScope.notification = {
+ type : type,
+ header: header,
+ message : message
+ };
+
+ schedulePop();
+ }
+
+ notifications.info = function(message) {
+ notifications.message("info", "Info!", message);
+ };
+
+ notifications.success = function(message) {
+ notifications.message("success", "Success!", message);
+ };
+
+ notifications.error = function(message) {
+ notifications.message("error", "Error!", message);
+ };
+
+ notifications.warn = function(message) {
+ notifications.message("warn", "Warning!", message);
+ };
+
+ return notifications;
+});
+
+module.factory('Realm', function($resource) {
+ return $resource('/auth/rest/admin/realms/:id', {
+ id : '@realm'
+ }, {
+ update : {
+ method : 'PUT'
+ },
+ create : {
+ method : 'POST',
+ params : { id : ''}
+ }
+
+ });
+});
+
+module.factory('User', function($resource) {
+ return $resource('/auth/rest/admin/realms/:realm/users/:userId', {
+ realm : '@realm',
+ userId : '@userId'
+ }, {
+ update : {
+ method : 'PUT'
+ }
+ });
+});
+
+module.factory('UserCredentials', function($resource) {
+ return $resource('/auth/rest/admin/realms/:realm/users/:userId/credentials', {
+ realm : '@realm',
+ userId : '@userId'
+ }, {
+ update : {
+ method : 'PUT',
+ isArray : true
+ }
+ });
+});
+
+module.factory('RealmRoleMapping', function($resource) {
+ return $resource('/auth/rest/admin/realms/:realm/users/:userId/role-mappings/realm', {
+ realm : '@realm',
+ userId : '@userId'
+ });
+});
+
+module.factory('ApplicationRoleMapping', function($resource) {
+ return $resource('/auth/rest/admin/realms/:realm/users/:userId/role-mappings/applications/:application', {
+ realm : '@realm',
+ userId : '@userId',
+ application : "@application"
+ });
+});
+
+module.factory('ApplicationRealmScopeMapping', function($resource) {
+ return $resource('/auth/rest/admin/realms/:realm/applications/:application/scope-mappings/realm', {
+ realm : '@realm',
+ application : '@application'
+ });
+});
+
+module.factory('ApplicationApplicationScopeMapping', function($resource) {
+ return $resource('/auth/rest/admin/realms/:realm/applications/:application/scope-mappings/applications/:targetApp', {
+ realm : '@realm',
+ application : '@application',
+ targetApp : '@targetApp'
+ });
+});
+
+
+
+module.factory('RealmRoles', function($resource) {
+ return $resource('/auth/rest/admin/realms/:realm/roles', {
+ realm : '@realm'
+ });
+});
+
+module.factory('RoleRealmComposites', function($resource) {
+ return $resource('/auth/rest/admin/realms/:realm/roles-by-id/:role/composites/realm', {
+ realm : '@realm',
+ role : '@role'
+ });
+});
+
+module.factory('RoleApplicationComposites', function($resource) {
+ return $resource('/auth/rest/admin/realms/:realm/roles-by-id/:role/composites/applications/:application', {
+ realm : '@realm',
+ role : '@role',
+ application : "@application"
+ });
+});
+
+
+function roleControl($scope, realm, role, roles, applications,
+ ApplicationRole, RoleById, RoleRealmComposites, RoleApplicationComposites,
+ $http, $location, Notifications, Dialog) {
+
+ $scope.$watch(function () {
+ return $location.path();
+ }, function () {
+ $scope.path = $location.path().substring(1).split("/");
+ });
+
+ $scope.$watch('role', function () {
+ if (!angular.equals($scope.role, role)) {
+ $scope.changed = true;
+ }
+ }, true);
+
+ $scope.update = function () {
+ RoleById.update({
+ realm: realm.realm,
+ role: role.id
+ }, $scope.role, function () {
+ $scope.changed = false;
+ role = angular.copy($scope.role);
+ Notifications.success("Your changes have been saved to the role.");
+ });
+ };
+
+ $scope.reset = function () {
+ $scope.role = angular.copy(role);
+ $scope.changed = false;
+ };
+
+ if (!role.id) return;
+
+ $scope.realmRoles = angular.copy(roles);
+ $scope.selectedRealmRoles = [];
+ $scope.selectedRealmMappings = [];
+ $scope.realmMappings = [];
+ $scope.applications = applications;
+ $scope.applicationRoles = [];
+ $scope.selectedApplicationRoles = [];
+ $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];
+ var idx = $scope.realmRoles.indexOf(realmRole);
+ $scope.realmRoles.splice(idx, 1);
+ break;
+ }
+ }
+
+
+ $scope.realmMappings = RoleRealmComposites.query({realm : realm.realm, role : role.id}, function(){
+ for (var i = 0; i < $scope.realmMappings.length; i++) {
+ var role = $scope.realmMappings[i];
+ for (var j = 0; j < $scope.realmRoles.length; j++) {
+ var realmRole = $scope.realmRoles[j];
+ if (realmRole.id == role.id) {
+ var idx = $scope.realmRoles.indexOf(realmRole);
+ if (idx != -1) {
+ $scope.realmRoles.splice(idx, 1);
+ break;
+ }
+ }
+ }
+ }
+ });
+
+ $scope.addRealmRole = function() {
+ $http.post('/auth/rest/admin/realms/' + realm.realm + '/roles-by-id/' + role.id + '/composites',
+ $scope.selectedRealmRoles).success(function() {
+ for (var i = 0; i < $scope.selectedRealmRoles.length; i++) {
+ var role = $scope.selectedRealmRoles[i];
+ var idx = $scope.realmRoles.indexOf($scope.selectedRealmRoles[i]);
+ if (idx != -1) {
+ $scope.realmRoles.splice(idx, 1);
+ $scope.realmMappings.push(role);
+ }
+ }
+ $scope.selectRealmRoles = [];
+ });
+ };
+
+ $scope.deleteRealmRole = function() {
+ $http.delete('/auth/rest/admin/realms/' + realm.realm + '/roles-by-id/' + role.id + '/composites',
+ {data : $scope.selectedRealmMappings, headers : {"content-type" : "application/json"}}).success(function() {
+ for (var i = 0; i < $scope.selectedRealmMappings.length; i++) {
+ var role = $scope.selectedRealmMappings[i];
+ var idx = $scope.realmMappings.indexOf($scope.selectedRealmMappings[i]);
+ if (idx != -1) {
+ $scope.realmMappings.splice(idx, 1);
+ $scope.realmRoles.push(role);
+ }
+ }
+ $scope.selectedRealmMappings = [];
+ });
+ };
+
+ $scope.addApplicationRole = function() {
+ $http.post('/auth/rest/admin/realms/' + realm.realm + '/roles-by-id/' + role.id + '/composites',
+ $scope.selectedApplicationRoles).success(function() {
+ for (var i = 0; i < $scope.selectedApplicationRoles.length; i++) {
+ var role = $scope.selectedApplicationRoles[i];
+ var idx = $scope.applicationRoles.indexOf($scope.selectedApplicationRoles[i]);
+ if (idx != -1) {
+ $scope.applicationRoles.splice(idx, 1);
+ $scope.applicationMappings.push(role);
+ }
+ }
+ $scope.selectedApplicationRoles = [];
+ });
+ };
+
+ $scope.deleteApplicationRole = function() {
+ $http.delete('/auth/rest/admin/realms/' + realm.realm + '/roles-by-id/' + role.id + '/composites',
+ {data : $scope.selectedApplicationMappings, headers : {"content-type" : "application/json"}}).success(function() {
+ for (var i = 0; i < $scope.selectedApplicationMappings.length; i++) {
+ var role = $scope.selectedApplicationMappings[i];
+ var idx = $scope.applicationMappings.indexOf($scope.selectedApplicationMappings[i]);
+ if (idx != -1) {
+ $scope.applicationMappings.splice(idx, 1);
+ $scope.applicationRoles.push(role);
+ }
+ }
+ $scope.selectedApplicationMappings = [];
+ });
+ };
+
+
+ $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(){
+ for (var i = 0; i < $scope.applicationMappings.length; i++) {
+ var role = $scope.applicationMappings[i];
+ for (var j = 0; j < $scope.applicationRoles.length; j++) {
+ var realmRole = $scope.applicationRoles[j];
+ if (realmRole.id == role.id) {
+ var idx = $scope.applicationRoles.indexOf(realmRole);
+ if (idx != -1) {
+ $scope.applicationRoles.splice(idx, 1);
+ break;
+ }
+ }
+ }
+ }
+ });
+ for (var j = 0; j < $scope.applicationRoles.length; j++) {
+ if ($scope.applicationRoles[j] == role.id) {
+ var appRole = $scope.applicationRoles[j];
+ var idx = $scope.applicationRoles.indexof(appRole);
+ $scope.applicationRoles.splice(idx, 1);
+ break;
+ }
+ }
+ }
+ );
+ };
+
+
+
+
+}
+
+
+module.factory('Role', function($resource) {
+ return $resource('/auth/rest/admin/realms/:realm/roles/:role', {
+ realm : '@realm',
+ role : '@role'
+ }, {
+ update : {
+ method : 'PUT'
+ }
+ });
+});
+
+module.factory('RoleById', function($resource) {
+ return $resource('/auth/rest/admin/realms/:realm/roles-by-id/:role', {
+ realm : '@realm',
+ role : '@role'
+ }, {
+ update : {
+ method : 'PUT'
+ }
+ });
+});
+
+module.factory('ApplicationRole', function($resource) {
+ return $resource('/auth/rest/admin/realms/:realm/applications/:application/roles/:role', {
+ realm : '@realm',
+ application : "@application",
+ role : '@role'
+ }, {
+ update : {
+ method : 'PUT'
+ }
+ });
+});
+
+
+module.factory('Application', function($resource) {
+ return $resource('/auth/rest/admin/realms/:realm/applications/:application', {
+ realm : '@realm',
+ application : '@name'
+ }, {
+ update : {
+ method : 'PUT'
+ }
+ });
+});
+
+module.factory('ApplicationInstallation', function($resource) {
+ var url = '/auth/rest/admin/realms/:realm/applications/:application/installation';
+ var resource = $resource('/auth/rest/admin/realms/:realm/applications/:application/installation', {
+ realm : '@realm',
+ application : '@application'
+ }, {
+ update : {
+ method : 'PUT'
+ }
+ });
+ resource.url = function(parameters) {
+ return url.replace(':realm', parameters.realm).replace(':application', parameters.application);
+ }
+ return resource;
+});
+
+module.factory('ApplicationCredentials', function($resource) {
+ return $resource('/auth/rest/admin/realms/:realm/applications/:application/credentials', {
+ realm : '@realm',
+ application : '@application'
+ }, {
+ update : {
+ method : 'PUT',
+ isArray : true
+ }
+ });
+});
+
+module.factory('ApplicationOrigins', function($resource) {
+ return $resource('/auth/rest/admin/realms/:realm/applications/:application/allowed-origins', {
+ realm : '@realm',
+ application : '@application'
+ }, {
+ update : {
+ method : 'PUT',
+ isArray : true
+ }
+ });
+});
+
+module.factory('OAuthClient', function($resource) {
+ return $resource('/auth/rest/admin/realms/:realm/oauth-clients/:id', {
+ realm : '@realm',
+ id : '@id'
+ }, {
+ update : {
+ method : 'PUT'
+ }
+ });
+});
+
+module.factory('OAuthClientCredentials', function($resource) {
+ return $resource('/auth/rest/admin/realms/:realm/oauth-clients/:oauth/credentials', {
+ realm : '@realm',
+ oauth : '@oauth'
+ }, {
+ update : {
+ method : 'PUT',
+ isArray : true
+ }
+ });
+});
+
+module.factory('OAuthClientRealmScopeMapping', function($resource) {
+ return $resource('/auth/rest/admin/realms/:realm/oauth-clients/:oauth/scope-mappings/realm', {
+ realm : '@realm',
+ oauth : '@oauth'
+ });
+});
+
+module.factory('OAuthClientApplicationScopeMapping', function($resource) {
+ return $resource('/auth/rest/admin/realms/:realm/oauth-clients/:oauth/scope-mappings/applications/:targetApp', {
+ realm : '@realm',
+ oauth : '@oauth',
+ targetApp : '@targetApp'
+ });
+});
+
+module.factory('OAuthClientInstallation', function($resource) {
+ var url = '/auth/rest/admin/realms/:realm/oauth-clients/:oauth/installation';
+ var resource = $resource('/auth/rest/admin/realms/:realm/oauth-clients/:oauth/installation', {
+ realm : '@realm',
+ oauth : '@oauth'
+ }, {
+ update : {
+ method : 'PUT'
+ }
+ });
+ resource.url = function(parameters) {
+ return url.replace(':realm', parameters.realm).replace(':oauth', parameters.oauth);
+ }
+ return resource;
+});
+
+
+module.factory('Current', function(Realm, $route) {
+ var current = {};
+
+ current.realms = {};
+ current.realm = null;
+ current.applications = {};
+ current.application = null;
+
+ current.refresh = function() {
+ current.realm = null;
+ current.realms = Realm.query(null, function(realms) {
+ if ($route.current.params.realm) {
+ for (var i = 0; i < realms.length; i++) {
+ if (realms[i].realm == $route.current.params.realm) {
+ current.realm = realms[i];
+ }
+ }
+ }
+ });
+ }
+
+ current.refresh();
+
+ return current;
+});
+
+module.factory('TimeUnit', function() {
+ var t = {};
+
+ t.autoUnit = function(time) {
+ var unit = 'Seconds';
+ if (time % 60 == 0) {
+ unit = 'Minutes';
+ time = time / 60;
+ }
+ if (time % 60 == 0) {
+ unit = 'Hours';
+ time = time / 60;
+ }
+ if (time % 24 == 0) {
+ unit = 'Days'
+ time = time / 24;
+ }
+ return unit;
+ }
+
+ t.toSeconds = function(time, unit) {
+ switch (unit) {
+ case 'Seconds': return time;
+ case 'Minutes': return time * 60;
+ case 'Hours': return time * 360;
+ case 'Days': return time * 86400;
+ default: throw 'invalid unit ' + unit;
+ }
+ }
+
+ t.toUnit = function(time, unit) {
+ switch (unit) {
+ case 'Seconds': return time;
+ case 'Minutes': return Math.ceil(time / 60);
+ case 'Hours': return Math.ceil(time / 360);
+ case 'Days': return Math.ceil(time / 86400);
+ default: throw 'invalid unit ' + unit;
+ }
+ }
+
+ t.convert = function(time, from, to) {
+ var seconds = t.toSeconds(time, from);
+ return t.toUnit(seconds, to);
+ }
+
+ return t;
+});
+
+
+module.factory('PasswordPolicy', function() {
+ var p = {};
+
+ p.policyMessages = {
+ length: "Minimal password length (integer type). Default value is 8.",
+ digits: "Minimal number (integer type) of digits in password. Default value is 1.",
+ lowerCase: "Minimal number (integer type) of lowercase characters in password. Default value is 1.",
+ upperCase: "Minimal number (integer type) of uppercase characters in password. Default value is 1.",
+ specialChars: "Minimal number (integer type) of special characters in password. Default value is 1."
+ }
+
+ p.allPolicies = [
+ { name: 'length', value: 8 },
+ { name: 'digits', value: 1 },
+ { name: 'lowerCase', value: 1 },
+ { name: 'upperCase', value: 1 },
+ { name: 'specialChars', value: 1 }
+ ];
+
+ p.parse = function(policyString) {
+ var policies = [];
+
+ if (!policyString || policyString.length == 0){
+ return policies;
+ }
+
+ var policyArray = policyString.split(" and ");
+
+ for (var i = 0; i < policyArray.length; i ++){
+ var policyToken = policyArray[i];
+ var re = /(\w+)\(*(\d*)\)*/;
+
+ var policyEntry = re.exec(policyToken);
+
+ policies.push({ name: policyEntry[1], value: parseInt(policyEntry[2]) });
+
+ }
+
+ return policies;
+ };
+
+ p.toString = function(policies) {
+ if (!policies || policies.length == 0) {
+ return null;
+ }
+
+ var policyString = "";
+
+ for (var i in policies){
+ policyString += policies[i].name;
+ if ( policies[i].value ){
+ policyString += '(' + policies[i].value + ')';
+ }
+ policyString += " and ";
+ }
+
+ policyString = policyString.substring(0, policyString.length - 5);
+
+ return policyString;
+ };
+
+ return p;
});
\ No newline at end of file
diff --git a/admin-ui/src/main/resources/META-INF/resources/admin/partials/application-role-detail.html b/admin-ui/src/main/resources/META-INF/resources/admin/partials/application-role-detail.html
index 84a39e3..4c6b5b2 100755
--- a/admin-ui/src/main/resources/META-INF/resources/admin/partials/application-role-detail.html
+++ b/admin-ui/src/main/resources/META-INF/resources/admin/partials/application-role-detail.html
@@ -52,6 +52,10 @@
required> -->
</div>
</div>
+ <div class="form-group clearfix block">
+ <label for="composite" class="control-label">Composite</label>
+ <input ng-model="role.composite" name="composite" id="composite" onoffswitch />
+ </div>
</fieldset>
<div class="form-actions" data-ng-show="create">
<button type="submit" kc-save class="primary" data-ng-show="changed">Save
@@ -70,6 +74,72 @@
Delete
</button>
</div>
+ <fieldset data-ng-show="!create && role.composite">
+ <legend collapsed><span class="text">Composite Realm Roles</span> </legend>
+ <div class="form-group">
+ <div class="controls changing-selectors">
+ <div class="select-title">
+ <label for="available">Available Roles</label>
+ <select id="available" class="form-control" multiple size="5"
+ ng-multiple="true"
+ ng-model="selectedRealmRoles"
+ ng-options="r.name for r in realmRoles">
+ </select>
+ </div>
+ <div class="middle-buttons">
+ <button type="submit" ng-click="addRealmRole()" tooltip="Move right" tooltip-placement="right"><span class="icon-arrow-right">Move right</span></button>
+ <button type="submit" ng-click="deleteRealmRole()" tooltip="Move left" tooltip-placement="right"><span class="icon-arrow-left">Move left</span></button>
+ </div>
+ <div class="select-title">
+ <label for="assigned">Assigned Roles</label>
+ <select id="assigned" class="form-control" multiple size=5
+ ng-multiple="true"
+ ng-model="selectedRealmMappings"
+ ng-options="r.name for r in realmMappings">
+ </select>
+ </div>
+ </div>
+ </div>
+ </fieldset>
+
+ <fieldset ng-show="applications.length > 0 && !create && role.composite">
+ <legend collapsed><span class="text">Composite Application Roles</span> </legend>
+ <div class="form-group input-select">
+ <label for="applications">Application</label>
+ <div class="input-group">
+ <div class="select-rcue">
+ <select id="applications" name="applications" ng-change="changeApplication()" ng-model="compositeApp" ng-options="a.name for a in applications">
+ <option value="" selected> Select an Application...</option>
+ </select>
+ </div>
+ </div>
+ </div>
+ <div class="form-group" ng-show="compositeApp">
+ <div class="controls changing-selectors application">
+ <div class="select-title">
+ <label for="available-app">Available Roles</label>
+ <select id="available-app" class="form-control" multiple size="5"
+ ng-multiple="true"
+ ng-model="selectedApplicationRoles"
+ ng-options="r.name for r in applicationRoles">
+ </select>
+ </div>
+ <div class="middle-buttons">
+ <button type="submit" ng-click="addApplicationRole()" tooltip="Move right" tooltip-placement="right"><span class="icon-arrow-right">Move right</span></button>
+ <button type="submit" ng-click="deleteApplicationRole()" tooltip="Move left" tooltip-placement="right"><span class="icon-arrow-left">Move left</span></button>
+ </div>
+ <div class="select-title">
+ <label for="assigned-app">Assigned Roles</label>
+ <select id="assigned-app" class="form-control" multiple size=5
+ ng-multiple="true"
+ ng-model="selectedApplicationMappings"
+ ng-options="r.name for r in applicationMappings">
+ </select>
+ </div>
+ </div>
+ </div>
+ </fieldset>
+
</form>
</div>
diff --git a/admin-ui/src/main/resources/META-INF/resources/admin/partials/role-detail.html b/admin-ui/src/main/resources/META-INF/resources/admin/partials/role-detail.html
index 50cf512..b835fcb 100755
--- a/admin-ui/src/main/resources/META-INF/resources/admin/partials/role-detail.html
+++ b/admin-ui/src/main/resources/META-INF/resources/admin/partials/role-detail.html
@@ -47,6 +47,10 @@
<textarea rows="5" cols="50" id="description" name="description" data-ng-model="role.description"></textarea>
</div>
</div>
+ <div class="form-group clearfix block">
+ <label for="composite" class="control-label">Composite</label>
+ <input ng-model="role.composite" name="composite" id="composite" onoffswitch />
+ </div>
</fieldset>
<div class="form-actions" data-ng-show="create">
<button type="submit" kc-save class="primary" data-ng-show="changed">Save
@@ -66,6 +70,72 @@
</button>
</div>
+ <fieldset data-ng-show="!create && role.composite">
+ <legend collapsed><span class="text">Composite Realm Roles</span> </legend>
+ <div class="form-group">
+ <div class="controls changing-selectors">
+ <div class="select-title">
+ <label for="available">Available Roles</label>
+ <select id="available" class="form-control" multiple size="5"
+ ng-multiple="true"
+ ng-model="selectedRealmRoles"
+ ng-options="r.name for r in realmRoles">
+ </select>
+ </div>
+ <div class="middle-buttons">
+ <button type="submit" ng-click="addRealmRole()" tooltip="Move right" tooltip-placement="right"><span class="icon-arrow-right">Move right</span></button>
+ <button type="submit" ng-click="deleteRealmRole()" tooltip="Move left" tooltip-placement="right"><span class="icon-arrow-left">Move left</span></button>
+ </div>
+ <div class="select-title">
+ <label for="assigned">Assigned Roles</label>
+ <select id="assigned" class="form-control" multiple size=5
+ ng-multiple="true"
+ ng-model="selectedRealmMappings"
+ ng-options="r.name for r in realmMappings">
+ </select>
+ </div>
+ </div>
+ </div>
+ </fieldset>
+
+ <fieldset ng-show="applications.length > 0 && !create && role.composite">
+ <legend collapsed><span class="text">Composite Application Roles</span> </legend>
+ <div class="form-group input-select">
+ <label for="applications">Application</label>
+ <div class="input-group">
+ <div class="select-rcue">
+ <select id="applications" name="applications" ng-change="changeApplication()" ng-model="compositeApp" ng-options="a.name for a in applications">
+ <option value="" selected> Select an Application...</option>
+ </select>
+ </div>
+ </div>
+ </div>
+ <div class="form-group" ng-show="compositeApp">
+ <div class="controls changing-selectors application">
+ <div class="select-title">
+ <label for="available-app">Available Roles</label>
+ <select id="available-app" class="form-control" multiple size="5"
+ ng-multiple="true"
+ ng-model="selectedApplicationRoles"
+ ng-options="r.name for r in applicationRoles">
+ </select>
+ </div>
+ <div class="middle-buttons">
+ <button type="submit" ng-click="addApplicationRole()" tooltip="Move right" tooltip-placement="right"><span class="icon-arrow-right">Move right</span></button>
+ <button type="submit" ng-click="deleteApplicationRole()" tooltip="Move left" tooltip-placement="right"><span class="icon-arrow-left">Move left</span></button>
+ </div>
+ <div class="select-title">
+ <label for="assigned-app">Assigned Roles</label>
+ <select id="assigned-app" class="form-control" multiple size=5
+ ng-multiple="true"
+ ng-model="selectedApplicationMappings"
+ ng-options="r.name for r in applicationMappings">
+ </select>
+ </div>
+ </div>
+ </div>
+ </fieldset>
+
</form>
</div>
</div>
diff --git a/core/src/main/java/org/keycloak/representations/idm/RoleRepresentation.java b/core/src/main/java/org/keycloak/representations/idm/RoleRepresentation.java
index 59119a6..81d2428 100755
--- a/core/src/main/java/org/keycloak/representations/idm/RoleRepresentation.java
+++ b/core/src/main/java/org/keycloak/representations/idm/RoleRepresentation.java
@@ -1,5 +1,8 @@
package org.keycloak.representations.idm;
+import java.util.List;
+import java.util.Set;
+
/**
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
* @version $Revision: 1 $
@@ -9,6 +12,7 @@ public class RoleRepresentation {
protected String name;
protected String description;
protected boolean composite;
+ protected List<RoleRepresentation> composites;
public RoleRepresentation() {
}
@@ -49,4 +53,12 @@ public class RoleRepresentation {
public void setComposite(boolean composite) {
this.composite = composite;
}
+
+ public List<RoleRepresentation> getComposites() {
+ return composites;
+ }
+
+ public void setComposites(List<RoleRepresentation> composites) {
+ this.composites = composites;
+ }
}
diff --git a/services/src/main/java/org/keycloak/services/resources/admin/ApplicationResource.java b/services/src/main/java/org/keycloak/services/resources/admin/ApplicationResource.java
index a64b45d..cfc4c62 100755
--- a/services/src/main/java/org/keycloak/services/resources/admin/ApplicationResource.java
+++ b/services/src/main/java/org/keycloak/services/resources/admin/ApplicationResource.java
@@ -48,7 +48,7 @@ public class ApplicationResource extends RoleContainerResource {
}
public ApplicationResource(RealmModel realm, ApplicationModel applicationModel, KeycloakSession session) {
- super(applicationModel);
+ super(realm, applicationModel);
this.realm = realm;
this.application = applicationModel;
this.session = session;
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 faf90e7..4f9d5ca 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
@@ -71,7 +71,7 @@ public class ApplicationsResource {
public ApplicationResource getApplication(final @PathParam("app-name") String name) {
ApplicationModel applicationModel = realm.getApplicationByName(name);
if (applicationModel == null) {
- throw new NotFoundException();
+ throw new NotFoundException("Could not find application: " + name);
}
ApplicationResource applicationResource = new ApplicationResource(realm, applicationModel, session);
resourceContext.initResource(applicationResource);
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 09f2fc8..deb46fb 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
@@ -29,7 +29,7 @@ public class RealmAdminResource extends RoleContainerResource {
protected KeycloakSession session;
public RealmAdminResource(UserModel admin, RealmModel realm) {
- super(realm);
+ super(realm, realm);
this.admin = admin;
this.realm = realm;
}
@@ -77,6 +77,14 @@ public class RealmAdminResource extends RoleContainerResource {
return users;
}
+ @Path("roles-by-id")
+ public RoleByIdResource rolesById() {
+ RoleByIdResource resource = new RoleByIdResource(realm);
+ resourceContext.initResource(resource);
+ return resource;
+
+ }
+
}
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
new file mode 100755
index 0000000..98869bf
--- /dev/null
+++ b/services/src/main/java/org/keycloak/services/resources/admin/RoleByIdResource.java
@@ -0,0 +1,119 @@
+package org.keycloak.services.resources.admin;
+
+import org.jboss.resteasy.annotations.cache.NoCache;
+import org.keycloak.models.Constants;
+import org.keycloak.models.RealmModel;
+import org.keycloak.models.RoleContainerModel;
+import org.keycloak.models.RoleModel;
+import org.keycloak.representations.idm.RoleRepresentation;
+import org.keycloak.services.managers.ModelToRepresentation;
+import org.keycloak.services.resources.admin.RoleResource;
+import org.keycloak.services.resources.flows.Flows;
+
+import javax.ws.rs.Consumes;
+import javax.ws.rs.DELETE;
+import javax.ws.rs.GET;
+import javax.ws.rs.NotFoundException;
+import javax.ws.rs.POST;
+import javax.ws.rs.PUT;
+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.Response;
+import javax.ws.rs.core.UriInfo;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Set;
+
+/**
+ * Sometimes its easier to just interact with roles by their ID instead of container/role-name
+ *
+ * @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
+ * @version $Revision: 1 $
+ */
+public class RoleByIdResource extends RoleResource {
+ public RoleByIdResource(RealmModel realm) {
+ super(realm);
+ }
+
+ @Path("{role-id}")
+ @GET
+ @NoCache
+ @Produces("application/json")
+ public RoleRepresentation getRole(final @PathParam("role-id") String id) {
+ RoleModel roleModel = getRoleModel(id);
+ return getRole(roleModel);
+ }
+
+ protected RoleModel getRoleModel(String id) {
+ RoleModel roleModel = realm.getRoleById(id);
+ if (roleModel == null || roleModel.getName().startsWith(Constants.INTERNAL_ROLE)) {
+ throw new NotFoundException("Could not find role with id: " + id);
+ }
+ return roleModel;
+ }
+
+ @Path("{role-id}")
+ @DELETE
+ @NoCache
+ public void deleteRole(final @PathParam("role-id") String id) {
+ RoleModel role = getRoleModel(id);
+ deleteRole(role);
+ }
+
+ @Path("{role-id}")
+ @PUT
+ @Consumes("application/json")
+ public void updateRole(final @PathParam("role-id") String id, final RoleRepresentation rep) {
+ RoleModel role = getRoleModel(id);
+ updateRole(rep, role);
+ }
+
+ @Path("{role-id}/composites")
+ @POST
+ @Consumes("application/json")
+ public void addComposites(final @PathParam("role-id") String id, List<RoleRepresentation> roles) {
+ RoleModel role = getRoleModel(id);
+ addComposites(roles, role);
+ }
+
+ @Path("{role-id}/composites")
+ @GET
+ @NoCache
+ @Produces("application/json")
+ public Set<RoleRepresentation> getRoleComposites(final @PathParam("role-id") String id) {
+ RoleModel role = getRoleModel(id);
+ return getRoleComposites(role);
+ }
+
+ @Path("{role-id}/composites/realm")
+ @GET
+ @NoCache
+ @Produces("application/json")
+ public Set<RoleRepresentation> getRealmRoleComposites(final @PathParam("role-id") String id) {
+ RoleModel role = getRoleModel(id);
+ return getRealmRoleComposites(role);
+ }
+
+ @Path("{role-id}/composites/applications/{app}")
+ @GET
+ @NoCache
+ @Produces("application/json")
+ public Set<RoleRepresentation> getApplicationRoleComposites(final @PathParam("role-id") String id,
+ final @PathParam("app") String appName) {
+ RoleModel role = getRoleModel(id);
+ return getApplicationRoleComposites(appName, role);
+ }
+
+
+ @Path("{role-id}/composites")
+ @DELETE
+ @Consumes("application/json")
+ public void deleteComposites(final @PathParam("role-id") String id, List<RoleRepresentation> roles) {
+ RoleModel role = getRoleModel(id);
+ deleteComposites(roles, 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 1971b31..7728d61 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
@@ -1,7 +1,9 @@
package org.keycloak.services.resources.admin;
import org.jboss.resteasy.annotations.cache.NoCache;
+import org.keycloak.models.ApplicationModel;
import org.keycloak.models.Constants;
+import org.keycloak.models.RealmModel;
import org.keycloak.models.RoleContainerModel;
import org.keycloak.models.RoleModel;
import org.keycloak.representations.idm.RoleRepresentation;
@@ -22,10 +24,11 @@ import java.util.Set;
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
* @version $Revision: 1 $
*/
-public class RoleContainerResource {
+public class RoleContainerResource extends RoleResource {
protected RoleContainerModel roleContainer;
- public RoleContainerResource(RoleContainerModel roleContainer) {
+ public RoleContainerResource(RealmModel realm, RoleContainerModel roleContainer) {
+ super(realm);
this.roleContainer = roleContainer;
}
@@ -44,6 +47,22 @@ public class RoleContainerResource {
return roles;
}
+ @Path("roles")
+ @POST
+ @Consumes("application/json")
+ public Response createRole(final @Context UriInfo uriInfo, final RoleRepresentation rep) {
+ if (roleContainer.getRole(rep.getName()) != null || rep.getName().startsWith(Constants.INTERNAL_ROLE)) {
+ return Flows.errors().exists("Role with name " + rep.getName() + " already exists");
+ }
+ RoleModel role = roleContainer.addRole(rep.getName());
+ if (role == null) {
+ throw new NotFoundException();
+ }
+ role.setDescription(rep.getDescription());
+ role.setComposite(rep.isComposite());
+ return Response.created(uriInfo.getAbsolutePathBuilder().path(role.getName()).build()).build();
+ }
+
@Path("roles/{role-name}")
@GET
@NoCache
@@ -53,7 +72,7 @@ public class RoleContainerResource {
if (roleModel == null || roleModel.getName().startsWith(Constants.INTERNAL_ROLE)) {
throw new NotFoundException("Could not find role: " + roleName);
}
- return ModelToRepresentation.toRepresentation(roleModel);
+ return getRole(roleModel);
}
@Path("roles/{role-name}")
@@ -64,9 +83,7 @@ public class RoleContainerResource {
if (role == null) {
throw new NotFoundException("Could not find role: " + roleName);
}
- if (!roleContainer.removeRoleById(role.getId())) {
- throw new NotFoundException();
- }
+ deleteRole(role);
}
@Path("roles/{role-name}")
@@ -77,9 +94,7 @@ public class RoleContainerResource {
if (role == null || role.getName().startsWith(Constants.INTERNAL_ROLE)) {
throw new NotFoundException("Could not find role: " + roleName);
}
- role.setName(rep.getName());
- role.setDescription(rep.getDescription());
- role.setComposite(rep.isComposite());
+ updateRole(rep, role);
}
@Path("roles/{role-name}/composites")
@@ -90,14 +105,7 @@ public class RoleContainerResource {
if (role == null || role.getName().startsWith(Constants.INTERNAL_ROLE)) {
throw new NotFoundException("Could not find role: " + roleName);
}
- for (RoleRepresentation rep : roles) {
- RoleModel composite = roleContainer.getRole(rep.getName());
- if (role == null || role.getName().startsWith(Constants.INTERNAL_ROLE)) {
- throw new NotFoundException("Could not find composite role: " + rep.getName());
- }
- if (!role.isComposite()) role.setComposite(true);
- role.addCompositeRole(composite);
- }
+ addComposites(roles, role);
}
@Path("roles/{role-name}/composites")
@@ -109,13 +117,32 @@ public class RoleContainerResource {
if (role == null || role.getName().startsWith(Constants.INTERNAL_ROLE)) {
throw new NotFoundException("Could not find role: " + roleName);
}
- if (!role.isComposite() || role.getComposites().size() == 0) return Collections.emptySet();
+ return getRoleComposites(role);
+ }
- Set<RoleRepresentation> composites = new HashSet<RoleRepresentation>(role.getComposites().size());
- for (RoleModel composite : role.getComposites()) {
- composites.add(ModelToRepresentation.toRepresentation(composite));
+ @Path("roles/{role-name}/composites/realm")
+ @GET
+ @NoCache
+ @Produces("application/json")
+ public Set<RoleRepresentation> getRealmRoleComposites(final @PathParam("role-name") String roleName) {
+ RoleModel role = roleContainer.getRole(roleName);
+ if (role == null || role.getName().startsWith(Constants.INTERNAL_ROLE)) {
+ throw new NotFoundException("Could not find role: " + roleName);
+ }
+ return getRealmRoleComposites(role);
+ }
+
+ @Path("roles/{role-name}/composites/application/{app}")
+ @GET
+ @NoCache
+ @Produces("application/json")
+ public Set<RoleRepresentation> getApplicationRoleComposites(final @PathParam("role-name") String roleName,
+ final @PathParam("app") String appName) {
+ RoleModel role = roleContainer.getRole(roleName);
+ if (role == null || role.getName().startsWith(Constants.INTERNAL_ROLE)) {
+ throw new NotFoundException("Could not find role: " + roleName);
}
- return composites;
+ return getApplicationRoleComposites(appName, role);
}
@@ -127,30 +154,8 @@ public class RoleContainerResource {
if (role == null || role.getName().startsWith(Constants.INTERNAL_ROLE)) {
throw new NotFoundException("Could not find role: " + roleName);
}
- for (RoleRepresentation rep : roles) {
- RoleModel composite = roleContainer.getRole(rep.getName());
- if (role == null || role.getName().startsWith(Constants.INTERNAL_ROLE)) {
- throw new NotFoundException("Could not find composite role: " + rep.getName());
- }
- role.removeCompositeRole(composite);
- }
- if (role.getComposites().size() > 0) role.setComposite(false);
+ deleteComposites(roles, role);
}
- @Path("roles")
- @POST
- @Consumes("application/json")
- public Response createRole(final @Context UriInfo uriInfo, final RoleRepresentation rep) {
- if (roleContainer.getRole(rep.getName()) != null || rep.getName().startsWith(Constants.INTERNAL_ROLE)) {
- return Flows.errors().exists("Role with name " + rep.getName() + " already exists");
- }
- RoleModel role = roleContainer.addRole(rep.getName());
- if (role == null) {
- throw new NotFoundException();
- }
- role.setDescription(rep.getDescription());
- role.setComposite(rep.isComposite());
- return Response.created(uriInfo.getAbsolutePathBuilder().path(role.getName()).build()).build();
- }
}
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
new file mode 100755
index 0000000..8bab186
--- /dev/null
+++ b/services/src/main/java/org/keycloak/services/resources/admin/RoleResource.java
@@ -0,0 +1,101 @@
+package org.keycloak.services.resources.admin;
+
+import org.keycloak.models.ApplicationModel;
+import org.keycloak.models.RealmModel;
+import org.keycloak.models.RoleModel;
+import org.keycloak.representations.idm.RoleRepresentation;
+import org.keycloak.services.managers.ModelToRepresentation;
+
+import javax.ws.rs.NotFoundException;
+import java.util.Collections;
+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 RoleResource {
+ protected RealmModel realm;
+
+ public RoleResource(RealmModel realm) {
+ this.realm = realm;
+ }
+
+ protected RoleRepresentation getRole(RoleModel roleModel) {
+ return ModelToRepresentation.toRepresentation(roleModel);
+ }
+
+ protected void deleteRole(RoleModel role) {
+ if (!role.getContainer().removeRoleById(role.getId())) {
+ throw new NotFoundException();
+ }
+ }
+
+ protected void updateRole(RoleRepresentation rep, RoleModel role) {
+ role.setName(rep.getName());
+ role.setDescription(rep.getDescription());
+ role.setComposite(rep.isComposite());
+ }
+
+ protected void addComposites(List<RoleRepresentation> roles, RoleModel role) {
+ for (RoleRepresentation rep : roles) {
+ RoleModel composite = realm.getRoleById(rep.getId());
+ if (composite == null) {
+ throw new NotFoundException("Could not find composite role: " + rep.getName());
+ }
+ if (!role.isComposite()) role.setComposite(true);
+ role.addCompositeRole(composite);
+ }
+ }
+
+ protected Set<RoleRepresentation> getRoleComposites(RoleModel role) {
+ if (!role.isComposite() || role.getComposites().size() == 0) return Collections.emptySet();
+
+ Set<RoleRepresentation> composites = new HashSet<RoleRepresentation>(role.getComposites().size());
+ for (RoleModel composite : role.getComposites()) {
+ composites.add(ModelToRepresentation.toRepresentation(composite));
+ }
+ return composites;
+ }
+
+ protected Set<RoleRepresentation> getRealmRoleComposites(RoleModel role) {
+ if (!role.isComposite() || role.getComposites().size() == 0) return Collections.emptySet();
+
+ Set<RoleRepresentation> composites = new HashSet<RoleRepresentation>(role.getComposites().size());
+ for (RoleModel composite : role.getComposites()) {
+ if (composite.getContainer() instanceof RealmModel)
+ composites.add(ModelToRepresentation.toRepresentation(composite));
+ }
+ return composites;
+ }
+
+ protected Set<RoleRepresentation> getApplicationRoleComposites(String appName, 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))
+ composites.add(ModelToRepresentation.toRepresentation(composite));
+ }
+ return composites;
+ }
+
+ protected void deleteComposites(List<RoleRepresentation> roles, RoleModel role) {
+ for (RoleRepresentation rep : roles) {
+ RoleModel composite = realm.getRoleById(rep.getId());
+ if (composite == null) {
+ throw new NotFoundException("Could not find composite role: " + rep.getName());
+ }
+ role.removeCompositeRole(composite);
+ }
+ if (role.getComposites().size() == 0) role.setComposite(false);
+ }
+}