keycloak-aplcache
Changes
admin-ui/src/main/resources/META-INF/resources/admin/partials/application-scope-mappings.html 4(+2 -2)
admin-ui/src/main/resources/META-INF/resources/admin/partials/oauth-client-credentials.html 4(+2 -2)
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 2f04486..62142ed 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
@@ -521,6 +521,8 @@ module.factory('errorInterceptor', function($q, $window, $rootScope, $location,
console.log('session timeout?');
Auth.loggedIn = false;
window.location = '/auth/rest/admin/login?path=' + $location.path();
+ } else if (response.status == 403) {
+ Notifications.error("Forbidden");
} else if (response.status == 404) {
Notifications.error("Not found");
} else if (response.status) {
@@ -672,20 +674,6 @@ module.directive('kcInput', function() {
return d;
});
-module.directive('kcDisableForm', function() {
- var d = {
- scope : true,
- replace : false,
- link : function(scope, element, attrs) {
- var form = element.children('form');
- console.debug(form);
- var input = element.children('input');
- input.attr('disabled', 'true');
- }
- };
- return d;
-});
-
module.directive('kcEnter', function() {
return function(scope, element, attrs) {
element.bind("keydown keypress", function(event) {
@@ -791,6 +779,21 @@ module.directive('kcSelect', function ($compile, Notifications) {
}
});
+module.directive('kcReadOnly', function() {
+ var d = {
+ replace : false,
+ link : function(scope, element, attrs) {
+ if (scope.$eval(attrs.kcReadOnly)) {
+ element.find('input').attr('disabled', 'disabled');
+ element.find('button').attr('disabled', 'disabled');
+ element.find('select').attr('disabled', 'disabled');
+ element.find('textarea').attr('disabled', 'disabled');
+ }
+ }
+ };
+ return d;
+});
+
module.directive('kcNavigation', function ($compile, Notifications) {
return {
scope: true,
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 eb54464..8220e9c 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
@@ -22,6 +22,22 @@ module.controller('GlobalCtrl', function($scope, $http, Auth, Current, $location
$scope.access = {
admin: data.admin,
+ get viewRealm() {
+ return getAccess(Current.realm.realm, 'view-realm') || this.viewRealm;
+ },
+
+ get viewApplications() {
+ return getAccess(Current.realm.realm, 'view-applications') || this.manageApplications;
+ },
+
+ get viewClients() {
+ return getAccess(Current.realm.realm, 'view-clients') || this.manageClients;
+ },
+
+ get viewUsers() {
+ return getAccess(Current.realm.realm, 'view-users') || this.manageClients;
+ },
+
get manageRealm() {
return getAccess(Current.realm.realm, 'manage-realm');
},
diff --git a/admin-ui/src/main/resources/META-INF/resources/admin/partials/application-credentials.html b/admin-ui/src/main/resources/META-INF/resources/admin/partials/application-credentials.html
index 8716490..a839ccf 100755
--- a/admin-ui/src/main/resources/META-INF/resources/admin/partials/application-credentials.html
+++ b/admin-ui/src/main/resources/META-INF/resources/admin/partials/application-credentials.html
@@ -16,7 +16,7 @@
<li class="active">Credentials</li>
</ol>
<h2 data-ng-hide="create"><span>{{application.name}}</span> Credentials</h2>
- <form class="form-horizontal" name="credentialForm" novalidate>
+ <form class="form-horizontal" name="credentialForm" novalidate kc-read-only="!access.manageApplications">
<fieldset >
<legend><span class="text">Client Secret</span></legend>
<div class="form-group">
@@ -27,7 +27,7 @@
</div>
</div>
</fieldset>
- <div class="pull-right form-actions">
+ <div class="pull-right form-actions" data-ng-show="access.manageApplications">
<button type="submit" data-ng-click="changePassword()" class="btn btn-primary btn-lg">Regenerate Secret
</button>
</div>
diff --git a/admin-ui/src/main/resources/META-INF/resources/admin/partials/application-detail.html b/admin-ui/src/main/resources/META-INF/resources/admin/partials/application-detail.html
index be13612..f123d1c 100755
--- a/admin-ui/src/main/resources/META-INF/resources/admin/partials/application-detail.html
+++ b/admin-ui/src/main/resources/META-INF/resources/admin/partials/application-detail.html
@@ -23,7 +23,7 @@
<li class="active">Settings</li>
</ol>
<h2 data-ng-hide="create"><span>{{application.name}}</span> Settings</h2>
- <form class="form-horizontal" name="applicationForm" novalidate>
+ <form class="form-horizontal" name="applicationForm" novalidate kc-read-only="!access.manageApplications">
<fieldset class="border-top">
<div class="form-group">
<label class="col-sm-2 control-label" for="name">Name <span class="required" data-ng-show="create">*</span></label>
@@ -108,11 +108,11 @@
</div>
</fieldset>
- <div class="pull-right form-actions" data-ng-show="create">
+ <div class="pull-right form-actions" data-ng-show="create && access.manageApplications">
<button kc-cancel data-ng-click="cancel()">Cancel</button>
<button kc-save data-ng-show="changed">Save</button>
</div>
- <div class="pull-right form-actions" data-ng-show="!create">
+ <div class="pull-right form-actions" data-ng-show="!create && access.manageApplications">
<button kc-reset data-ng-show="changed">Clear changes</button>
<button kc-save data-ng-show="changed">Save</button>
<button kc-delete data-ng-click="remove()" data-ng-hide="changed">Delete</button>
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 3f6437f..e103b12 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
@@ -29,7 +29,7 @@
<h2 data-ng-hide="create"><span>{{application.name}}</span> {{role.name}}</h2>
<h2 data-ng-show="create"><span>{{application.name}}</span> Add Role</h2>
- <form class="form-horizontal" name="realmForm" novalidate>
+ <form class="form-horizontal" name="realmForm" novalidate kc-read-only="!access.manageApplications">
<span class="fieldset-notice"><span class="required">*</span> Required fields</span>
<fieldset class="border-top">
@@ -134,11 +134,11 @@
</div>
</fieldset>
- <div class="pull-right form-actions" data-ng-show="create">
+ <div class="pull-right form-actions" data-ng-show="create && access.manageApplications">
<button kc-cancel data-ng-click="cancel()">Cancel</button>
<button kc-save data-ng-show="changed">Save</button>
</div>
- <div class="pull-right form-actions" data-ng-show="!create">
+ <div class="pull-right form-actions" data-ng-show="!create && access.manageApplications">
<button kc-reset data-ng-show="changed">Clear changes</button>
<button kc-save data-ng-show="changed">Save</button>
<button kc-delete data-ng-click="remove()" data-ng-hide="changed">Delete</button>
diff --git a/admin-ui/src/main/resources/META-INF/resources/admin/partials/application-role-list.html b/admin-ui/src/main/resources/META-INF/resources/admin/partials/application-role-list.html
index f6031f2..087d11d 100755
--- a/admin-ui/src/main/resources/META-INF/resources/admin/partials/application-role-list.html
+++ b/admin-ui/src/main/resources/META-INF/resources/admin/partials/application-role-list.html
@@ -21,7 +21,7 @@
<table class="table">
<thead>
<tr>
- <th class="kc-table-actions" colspan="3">
+ <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>
<!-- <button class="remove disabled">Remove</button> -->
diff --git a/admin-ui/src/main/resources/META-INF/resources/admin/partials/application-scope-mappings.html b/admin-ui/src/main/resources/META-INF/resources/admin/partials/application-scope-mappings.html
index 9432d99..865f9d6 100755
--- a/admin-ui/src/main/resources/META-INF/resources/admin/partials/application-scope-mappings.html
+++ b/admin-ui/src/main/resources/META-INF/resources/admin/partials/application-scope-mappings.html
@@ -19,7 +19,7 @@
</ol>
<h2><span>{{application.name}}</span> Scope Mappings</h2>
<p class="subtitle"></p>
- <form class="form-horizontal" name="realmForm" novalidate>
+ <form class="form-horizontal" name="realmForm" novalidate kc-read-only="!access.manageApplications">
<fieldset>
<legend><span class="text">Realm Roles</span></legend>
<div class="form-group col-sm-10">
@@ -59,7 +59,7 @@
<div class="col-sm-4">
<div class="input-group">
<div class="select-kc">
- <select id="applications" name="applications" ng-change="changeApplication()" ng-model="targetApp" ng-options="a.name for a in (applications|remove:application:'id')">
+ <select id="applications" name="applications" ng-change="changeApplication()" ng-model="targetApp" ng-options="a.name for a in (applications|remove:application:'id')" ng-disabled="false">
<option value="" selected> Select an Application </option>
</select>
</div>
diff --git a/admin-ui/src/main/resources/META-INF/resources/admin/partials/oauth-client-credentials.html b/admin-ui/src/main/resources/META-INF/resources/admin/partials/oauth-client-credentials.html
index 03ad7f7..f931492 100755
--- a/admin-ui/src/main/resources/META-INF/resources/admin/partials/oauth-client-credentials.html
+++ b/admin-ui/src/main/resources/META-INF/resources/admin/partials/oauth-client-credentials.html
@@ -15,7 +15,7 @@
<li class="active">Credentials</li>
</ol>
<h2 data-ng-hide="create"><span>{{oauth.name}}</span> Credentials</h2>
- <form class="form-horizontal" name="credentialForm" novalidate>
+ <form class="form-horizontal" name="credentialForm" novalidate kc-read-only="!access.manageClients">
<fieldset >
<legend><span class="text">Client Secret</span></legend>
<div class="form-group">
@@ -26,7 +26,7 @@
</div>
</div>
</fieldset>
- <div class="pull-right form-actions">
+ <div class="pull-right form-actions" data-ng-show="access.manageClients">
<button type="submit" data-ng-click="changePassword()" class="btn btn-primary btn-lg">Regenerate Secret
</button>
</div>
diff --git a/admin-ui/src/main/resources/META-INF/resources/admin/partials/oauth-client-detail.html b/admin-ui/src/main/resources/META-INF/resources/admin/partials/oauth-client-detail.html
index 7ac2ed7..01e1835 100755
--- a/admin-ui/src/main/resources/META-INF/resources/admin/partials/oauth-client-detail.html
+++ b/admin-ui/src/main/resources/META-INF/resources/admin/partials/oauth-client-detail.html
@@ -21,7 +21,7 @@
<li class="active">Settings</li>
</ol>
<h2 data-ng-hide="create"><span>{{oauth.name}}</span> Settings</h2>
- <form class="form-horizontal" name="oauthForm" novalidate>
+ <form class="form-horizontal" name="oauthForm" novalidate kc-read-only="!access.manageClients">
<fieldset class="border-top">
<div class="form-group">
@@ -90,11 +90,11 @@
</div>
</fieldset>
- <div class="pull-right form-actions" data-ng-show="create">
+ <div class="pull-right form-actions" data-ng-show="create && access.manageClients">
<button kc-cancel data-ng-click="cancel()">Cancel</button>
<button kc-save data-ng-show="changed">Save</button>
</div>
- <div class="pull-right form-actions" data-ng-show="!create">
+ <div class="pull-right form-actions" data-ng-show="!create && access.manageClients">
<button kc-reset data-ng-show="changed">Clear changes</button>
<button kc-save data-ng-show="changed">Save</button>
<button kc-delete data-ng-click="remove()" data-ng-hide="changed">Delete</button>
diff --git a/admin-ui/src/main/resources/META-INF/resources/admin/partials/oauth-client-scope-mappings.html b/admin-ui/src/main/resources/META-INF/resources/admin/partials/oauth-client-scope-mappings.html
index 111a98c..424fab2 100755
--- a/admin-ui/src/main/resources/META-INF/resources/admin/partials/oauth-client-scope-mappings.html
+++ b/admin-ui/src/main/resources/META-INF/resources/admin/partials/oauth-client-scope-mappings.html
@@ -17,7 +17,7 @@
</ol>
<h2><span>{{oauth.name}}</span> Scope Mappings</h2>
<p class="subtitle"></p>
- <form class="form-horizontal" name="realmForm" novalidate>
+ <form class="form-horizontal" name="realmForm" novalidate kc-read-only="!access.manageClients">
<fieldset>
<legend><span class="text">Realm Roles</span></legend>
<div class="form-group col-sm-10">
@@ -57,7 +57,7 @@
<div class="col-sm-4">
<div class="input-group">
<div class="select-kc">
- <select id="applications" name="applications" ng-change="changeApplication()" ng-model="targetApp" ng-options="a.name for a in (applications)">
+ <select id="applications" name="applications" ng-change="changeApplication()" ng-model="targetApp" ng-options="a.name for a in (applications)" ng-disabled="false">
<option value="" selected> Select an Application </option>
</select>
</div>
diff --git a/admin-ui/src/main/resources/META-INF/resources/admin/partials/realm-credentials.html b/admin-ui/src/main/resources/META-INF/resources/admin/partials/realm-credentials.html
index aad2f6d..0a595cd 100755
--- a/admin-ui/src/main/resources/META-INF/resources/admin/partials/realm-credentials.html
+++ b/admin-ui/src/main/resources/META-INF/resources/admin/partials/realm-credentials.html
@@ -9,9 +9,9 @@
<li class="active">Required Credentials</li>
</ol>
<h2><span>{{realm.realm}}</span> Credentials</h2>
- <form class="form-horizontal" name="realmForm" novalidate>
+ <form class="form-horizontal" name="realmForm" novalidate kc-read-only="!access.manageRealm">
<fieldset class="border-top">
- <legend uncollapsed><span class="text">Realm Credentials Settings</span></legend>
+ <legend><span class="text">Realm Credentials Settings</span></legend>
<div class="form-group">
<label class="col-sm-2 control-label" for="user" class="control-label two-lines">Required User Credentials</label>
@@ -21,7 +21,7 @@
</div>
</fieldset>
<fieldset class="border-top">
- <legend uncollapsed><span class="text">Realm Password Policy</span></legend>
+ <legend><span class="text">Realm Password Policy</span></legend>
<table class="table">
<caption class="hidden">Table of Password Policies</caption>
<thead>
@@ -63,7 +63,7 @@
</tbody>
</table>
</fieldset>
- <div class="pull-right form-actions">
+ <div class="pull-right form-actions" data-ng-show="access.manageRealm">
<button kc-reset data-ng-show="changed">Clear changes</button>
<button kc-save data-ng-show="changed">Save</button>
</div>
diff --git a/admin-ui/src/main/resources/META-INF/resources/admin/partials/realm-default-roles.html b/admin-ui/src/main/resources/META-INF/resources/admin/partials/realm-default-roles.html
index 1dc2751..a947e30 100755
--- a/admin-ui/src/main/resources/META-INF/resources/admin/partials/realm-default-roles.html
+++ b/admin-ui/src/main/resources/META-INF/resources/admin/partials/realm-default-roles.html
@@ -8,7 +8,7 @@
<li class="active">Registration</li>
</ol>
<h2><span>{{realm.realm}}</span> Default Roles</h2>
- <form class="form-horizontal" name="realmForm" novalidate>
+ <form class="form-horizontal" name="realmForm" novalidate kc-read-only="!access.manageRealm">
<fieldset>
<legend><span class="text">Realm Default Roles</span> </legend>
<div class="form-group">
@@ -48,7 +48,7 @@
<div class="col-sm-4">
<div class="input-group">
<div class="select-kc">
- <select id="applications" name="applications" ng-change="changeApplication()" ng-model="application" ng-options="a.name for a in applications">
+ <select id="applications" name="applications" ng-change="changeApplication()" ng-model="application" ng-options="a.name for a in applications" ng-disabled="false">
<option value="" selected> Select an Application...</option>
</select>
</div>
diff --git a/admin-ui/src/main/resources/META-INF/resources/admin/partials/realm-detail.html b/admin-ui/src/main/resources/META-INF/resources/admin/partials/realm-detail.html
index 055231c..4fa18c0 100755
--- a/admin-ui/src/main/resources/META-INF/resources/admin/partials/realm-detail.html
+++ b/admin-ui/src/main/resources/META-INF/resources/admin/partials/realm-detail.html
@@ -7,11 +7,11 @@
<li><a href="#/realms/{{realm.realm}}">Settings</a></li>
<li class="active">General</li>
</ol>
- <div data-ng-show="access.manageRealm">
+ <div data-ng-show="access.viewRealm">
<h2 class="pull-left" data-ng-show="createRealm">Add Realm</h2>
<h2 data-ng-hide="createRealm"><span>{{realm.realm}}</span> General Settings</h2>
<p class="subtitle" data-ng-show="createRealm"><span class="required">*</span> Required fields</p>
- <form class="form-horizontal" name="realmForm" novalidate>
+ <form class="form-horizontal" name="realmForm" novalidate kc-read-only="!access.manageRealm">
<fieldset>
<legend class="aj-collapse open"><span class="text">Required Settings</span></legend>
<div class="form-group">
@@ -91,18 +91,18 @@
</div>
</fieldset>
- <div class="pull-right form-actions" data-ng-show="createRealm">
+ <div class="pull-right form-actions" data-ng-show="createRealm && access.manageRealm">
<button kc-cancel data-ng-click="cancel()">Cancel</button>
<button kc-save data-ng-show="changed">Save</button>
</div>
- <div class="pull-right form-actions" data-ng-show="!createRealm">
+ <div class="pull-right form-actions" data-ng-show="!createRealm && access.manageRealm">
<button kc-reset data-ng-show="changed">Clear changes</button>
<button kc-save data-ng-show="changed">Save</button>
<button kc-delete data-ng-click="remove()" data-ng-hide="changed">Delete</button>
</div>
</form>
</div>
- <div data-ng-hide="access.manageRealm">
+ <div data-ng-hide="access.viewRealm">
<h2 ><span>{{realm.realm}}</span></h2>
</div>
diff --git a/admin-ui/src/main/resources/META-INF/resources/admin/partials/realm-keys.html b/admin-ui/src/main/resources/META-INF/resources/admin/partials/realm-keys.html
index 0f96867..d471df6 100755
--- a/admin-ui/src/main/resources/META-INF/resources/admin/partials/realm-keys.html
+++ b/admin-ui/src/main/resources/META-INF/resources/admin/partials/realm-keys.html
@@ -8,7 +8,7 @@
<li class="active">Keys</li>
</ol>
<h2><span>{{realm.realm}}</span> Keys</h2>
- <form class="form-horizontal" name="realmForm" novalidate>
+ <form class="form-horizontal" name="realmForm" novalidate kc-read-only="!access.manageRealm">
<fieldset class="border-top">
<div class="form-group">
<label class="col-sm-2 control-label" for="publicKey">Public key</label>
@@ -19,7 +19,7 @@
</div>
</div>
</fieldset>
- <div class="pull-right form-actions">
+ <div class="pull-right form-actions" data-ng-show="access.manageRealm">
<button class="btn btn-primary btn-lg" type="submit" data-ng-click="generate()">Generate new keys</button>
</div>
</form>
diff --git a/admin-ui/src/main/resources/META-INF/resources/admin/partials/realm-menu.html b/admin-ui/src/main/resources/META-INF/resources/admin/partials/realm-menu.html
index 95c7068..10ac577 100755
--- a/admin-ui/src/main/resources/META-INF/resources/admin/partials/realm-menu.html
+++ b/admin-ui/src/main/resources/META-INF/resources/admin/partials/realm-menu.html
@@ -1,9 +1,9 @@
<ul data-ng-hide="createRealm">
- <li data-ng-show="access.manageRealm" data-ng-class="((!path[2] || path[1] == 'role' || path[2] == 'roles' || path[2] == 'token-settings' ||
+ <li data-ng-show="access.viewRealm" data-ng-class="((!path[2] || path[1] == 'role' || path[2] == 'roles' || path[2] == 'token-settings' ||
path[2] == 'social-settings' || path[2] == 'required-credentials' || path[2] == 'default-roles' || path[2] == 'registration-settings' ||
path[2] == 'keys-settings' || path[2] == 'smtp-settings') && path[3] != 'applications') && 'active'"><a href="#/realms/{{realm.realm}}">Settings</a></li>
- <li data-ng-show="access.manageUsers" data-ng-class="(path[2] == 'users' || path[1] == 'user') && 'active'"><a href="#/realms/{{realm.realm}}/users">Users</a>
+ <li data-ng-show="access.viewUsers" data-ng-class="(path[2] == 'users' || path[1] == 'user') && 'active'"><a href="#/realms/{{realm.realm}}/users">Users</a>
</li>
- <li data-ng-show="access.manageApplications" data-ng-class="(path[2] == 'applications' || path[1] == 'application' || path[3] == 'applications') && 'active'"><a href="#/realms/{{realm.realm}}/applications">Applications</a></li>
- <li data-ng-show="access.manageClients" data-ng-class="(path[2] == 'oauth-clients' || path[1] == 'oauth-client') && 'active'"><a href="#/realms/{{realm.realm}}/oauth-clients">OAuth Clients</a></li>
+ <li data-ng-show="access.viewApplications" data-ng-class="(path[2] == 'applications' || path[1] == 'application' || path[3] == 'applications') && 'active'"><a href="#/realms/{{realm.realm}}/applications">Applications</a></li>
+ <li data-ng-show="access.viewClients" data-ng-class="(path[2] == 'oauth-clients' || path[1] == 'oauth-client') && 'active'"><a href="#/realms/{{realm.realm}}/oauth-clients">OAuth Clients</a></li>
</ul>
\ No newline at end of file
diff --git a/admin-ui/src/main/resources/META-INF/resources/admin/partials/realm-smtp.html b/admin-ui/src/main/resources/META-INF/resources/admin/partials/realm-smtp.html
index cba699a..e03dc51 100755
--- a/admin-ui/src/main/resources/META-INF/resources/admin/partials/realm-smtp.html
+++ b/admin-ui/src/main/resources/META-INF/resources/admin/partials/realm-smtp.html
@@ -8,10 +8,10 @@
<li class="active">SMTP Configuration</li>
</ol>
<h2><span>{{realm.realm}}</span> Email Server Settings</h2>
- <form class="form-horizontal" name="realmForm" novalidate>
+ <form class="form-horizontal" name="realmForm" novalidate kc-read-only="!access.manageRealm">
<span class="fieldset-notice"><span class="required">*</span> Required fields</span>
<fieldset>
- <legend uncollapsed><span class="text">Required Settings</span></legend>
+ <legend><span class="text">Required Settings</span></legend>
<div class="form-group clearfix">
<label class="col-sm-2 control-label" for="smtpHost">Host <span class="required">*</span></label>
<div class="col-sm-4">
@@ -44,7 +44,7 @@
</div>
</fieldset>
<fieldset>
- <legend uncollapsed><span class="text">Authentication</span></legend>
+ <legend><span class="text">Authentication</span></legend>
<div class="form-group clearfix">
<label class="col-sm-2 control-label" for="smtpAuth">Enable Authentication</label>
<div class="col-sm-4">
@@ -65,7 +65,7 @@
</div>
</fieldset>
- <div class="pull-right form-actions">
+ <div class="pull-right form-actions" data-ng-show="access.manageRealm">
<button data-kc-reset data-ng-show="changed">Clear changes</button>
<button data-kc-save data-ng-show="changed">Save</button>
</div>
diff --git a/admin-ui/src/main/resources/META-INF/resources/admin/partials/realm-tokens.html b/admin-ui/src/main/resources/META-INF/resources/admin/partials/realm-tokens.html
index ac83d09..7dc96e6 100755
--- a/admin-ui/src/main/resources/META-INF/resources/admin/partials/realm-tokens.html
+++ b/admin-ui/src/main/resources/META-INF/resources/admin/partials/realm-tokens.html
@@ -8,7 +8,7 @@
<li class="active">Token</li>
</ol>
<h2><span>{{realm.realm}}</span> Token Settings</h2>
- <form class="form-horizontal" name="realmForm" novalidate>
+ <form class="form-horizontal" name="realmForm" novalidate kc-read-only="!access.manageRealm">
<fieldset class="border-top">
<div class="form-group">
<label class="col-sm-2 control-label" for="rememberMe">Remember Me</label>
@@ -113,7 +113,7 @@
</div>
</div>
</fieldset>
- <div class="pull-right form-actions">
+ <div class="pull-right form-actions" data-ng-show="access.manageRealm">
<button kc-reset data-ng-show="changed">Clear changes</button>
<button kc-save data-ng-show="changed">Save</button>
</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 cb65d93..fc25f41 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
@@ -28,7 +28,7 @@
</ol>
<h2 data-ng-show="create"><span>{{realm.realm}}</span> Add Role</h2>
<p class="subtitle" data-ng-show="create"><span class="required">*</span> Required fields</p>
- <form class="form-horizontal" name="realmForm" novalidate>
+ <form class="form-horizontal" name="realmForm" novalidate kc-read-only="!access.manageRealm">
<fieldset>
<div class="form-group">
<label class="col-sm-2 control-label" for="name">Role name <span class="required" data-ng-show="create">*</span></label>
@@ -96,7 +96,7 @@
<div class="col-sm-4">
<div class="input-group">
<div class="select-kc">
- <select id="applications" name="applications" ng-change="changeApplication()" ng-model="compositeApp" ng-options="a.name for a in applications">
+ <select id="applications" name="applications" ng-change="changeApplication()" ng-model="compositeApp" ng-options="a.name for a in applications" ng-disabled="false">
<option value="" selected> Select an Application...</option>
</select>
</div>
@@ -133,7 +133,7 @@
</div>
</fieldset>
- <div class="pull-right form-actions" data-ng-show="!create">
+ <div class="pull-right form-actions" data-ng-show="!create && access.manageRealm">
<button kc-reset data-ng-show="changed">Clear changes</button>
<button kc-save data-ng-show="changed">Save</button>
<button kc-delete data-ng-click="remove()" data-ng-hide="changed">Delete</button>
diff --git a/admin-ui/src/main/resources/META-INF/resources/admin/partials/role-list.html b/admin-ui/src/main/resources/META-INF/resources/admin/partials/role-list.html
index e3a6ae3..e0062e0 100755
--- a/admin-ui/src/main/resources/META-INF/resources/admin/partials/role-list.html
+++ b/admin-ui/src/main/resources/META-INF/resources/admin/partials/role-list.html
@@ -13,7 +13,7 @@
<table class="table">
<thead>
<tr>
- <th class="kc-table-actions" colspan="3">
+ <th class="kc-table-actions" colspan="3" data-ng-show="access.manageRealm">
<div class="pull-right">
<a class="btn btn-primary" href="#/create/role/{{realm.realm}}">Add Role</a>
<!-- <button class="remove disabled">Remove</button> -->
diff --git a/admin-ui/src/main/resources/META-INF/resources/admin/partials/role-mappings.html b/admin-ui/src/main/resources/META-INF/resources/admin/partials/role-mappings.html
index 0e61d1a..c290d7a 100755
--- a/admin-ui/src/main/resources/META-INF/resources/admin/partials/role-mappings.html
+++ b/admin-ui/src/main/resources/META-INF/resources/admin/partials/role-mappings.html
@@ -2,7 +2,7 @@
<div id="content-area" class="col-md-9" role="main">
<ul class="nav nav-tabs nav-tabs-pf" data-ng-show="!create">
<li><a href="#/realms/{{realm.realm}}/users/{{user.username}}">Attributes</a></li>
- <li><a href="#/realms/{{realm.realm}}/users/{{user.username}}/user-credentials">Credentials</a></li>
+ <li data-ng-show="access.manageUsers"><a href="#/realms/{{realm.realm}}/users/{{user.username}}/user-credentials">Credentials</a></li>
<li class="active"><a href="#/realms/{{realm.realm}}/users/{{user.username}}/role-mappings">Role Mappings</a></li>
</ul>
<div id="content">
@@ -13,7 +13,7 @@
<li class="active">Role Mappings</li>
</ol>
<h2><span>{{user.username}}'s</span> Role Mappings</h2>
- <form class="form-horizontal" name="realmForm" novalidate>
+ <form class="form-horizontal" name="realmForm" novalidate kc-read-only="!access.manageUsers">
<fieldset>
<legend><span class="text">Realm Roles</span> </legend>
@@ -54,7 +54,7 @@
<div class="col-sm-4">
<div class="input-group">
<div class="select-kc">
- <select id="applications" name="applications" ng-change="changeApplication()" ng-model="application" ng-options="a.name for a in applications">
+ <select id="applications" name="applications" ng-change="changeApplication()" ng-model="application" ng-options="a.name for a in applications" ng-disabled="false">
<option value="" selected> Select an Application...</option>
</select>
</div>
diff --git a/admin-ui/src/main/resources/META-INF/resources/admin/partials/user-detail.html b/admin-ui/src/main/resources/META-INF/resources/admin/partials/user-detail.html
index c258661..4ce093a 100755
--- a/admin-ui/src/main/resources/META-INF/resources/admin/partials/user-detail.html
+++ b/admin-ui/src/main/resources/META-INF/resources/admin/partials/user-detail.html
@@ -3,7 +3,7 @@
<ul class="nav nav-tabs nav-tabs-pf" data-ng-show="!create">
<li class="active"><a href="#/realms/{{realm.realm}}/users/{{user.username}}">Attributes</a></li>
- <li><a href="#/realms/{{realm.realm}}/users/{{user.username}}/user-credentials">Credentials</a></li>
+ <li data-ng-show="access.manageUsers"><a href="#/realms/{{realm.realm}}/users/{{user.username}}/user-credentials">Credentials</a></li>
<li><a href="#/realms/{{realm.realm}}/users/{{user.username}}/role-mappings">Role Mappings</a></li>
</ul>
@@ -22,7 +22,7 @@
</ol>
<h2 data-ng-hide="create"><span>{{user.username}}'s</span> Attributes</h2>
- <form class="form-horizontal" name="userForm" novalidate>
+ <form class="form-horizontal" name="userForm" novalidate kc-read-only="!access.manageUsers">
<span class="fieldset-notice"><span class="required">*</span> Required fields</span>
<fieldset class="border-top">
<div class="form-group">
@@ -79,12 +79,12 @@
</div>
</div>
</fieldset>
- <div class="pull-right form-actions" data-ng-show="create">
+ <div class="pull-right form-actions" data-ng-show="create && access.manageUsers">
<button kc-cancel data-ng-click="cancel()">Cancel</button>
<button kc-save data-ng-show="changed">Save</button>
</div>
- <div class="pull-right form-actions" data-ng-show="!create">
+ <div class="pull-right form-actions" data-ng-show="!create && access.manageUsers">
<button kc-reset data-ng-show="changed">Clear changes</button>
<button kc-save data-ng-show="changed">Save</button>
<button kc-delete data-ng-click="remove()" data-ng-hide="changed">Delete</button>
diff --git a/admin-ui/src/main/resources/META-INF/resources/admin/templates/kc-navigation.html b/admin-ui/src/main/resources/META-INF/resources/admin/templates/kc-navigation.html
index 715a3a7..307aab6 100644
--- a/admin-ui/src/main/resources/META-INF/resources/admin/templates/kc-navigation.html
+++ b/admin-ui/src/main/resources/META-INF/resources/admin/templates/kc-navigation.html
@@ -1,10 +1,10 @@
<ul class="nav nav-tabs nav-tabs-pf">
<li ng-class="{active: !path[2]}"><a href="#/realms/{{realm.realm}}">General</a></li>
- <li ng-class="{active: path[2] == 'social'}" data-ng-show="kcSocial && auth.hasAccess(realm.realm, 'manage-realm')"><a href="#/realms/{{realm.realm}}/social-settings">Social</a></li>
- <li ng-class="{active: path[2] == 'roles'}" data-ng-show="access.manageRealm"><a href="#/realms/{{realm.realm}}/roles">Roles</a></li>
- <li ng-class="{active: path[2] == 'default-roles'}" data-ng-show="access.manageRealm"><a href="#/realms/{{realm.realm}}/default-roles">Default Roles</a></li>
- <li ng-class="{active: path[2] == 'required-credentials'}" data-ng-show="access.manageRealm"><a href="#/realms/{{realm.realm}}/required-credentials">Credentials</a></li>
- <li ng-class="{active: path[2] == 'token-settings'}" data-ng-show="access.manageRealm"><a href="#/realms/{{realm.realm}}/token-settings">Token</a></li>
- <li ng-class="{active: path[2] == 'keys-settings'}" data-ng-show="access.manageRealm"><a href="#/realms/{{realm.realm}}/keys-settings">Keys</a></li>
- <li ng-class="{active: path[2] == 'smtp-settings'}" data-ng-show="access.manageRealm"><a href="#/realms/{{realm.realm}}/smtp-settings">Email</a></li>
+ <li ng-class="{active: path[2] == 'social'}" data-ng-show="kcSocial && access.viewRealm"><a href="#/realms/{{realm.realm}}/social-settings">Social</a></li>
+ <li ng-class="{active: path[2] == 'roles'}" data-ng-show="access.viewRealm"><a href="#/realms/{{realm.realm}}/roles">Roles</a></li>
+ <li ng-class="{active: path[2] == 'default-roles'}" data-ng-show="access.viewRealm"><a href="#/realms/{{realm.realm}}/default-roles">Default Roles</a></li>
+ <li ng-class="{active: path[2] == 'required-credentials'}" data-ng-show="access.viewRealm"><a href="#/realms/{{realm.realm}}/required-credentials">Credentials</a></li>
+ <li ng-class="{active: path[2] == 'token-settings'}" data-ng-show="access.viewRealm"><a href="#/realms/{{realm.realm}}/token-settings">Token</a></li>
+ <li ng-class="{active: path[2] == 'keys-settings'}" data-ng-show="access.viewRealm"><a href="#/realms/{{realm.realm}}/keys-settings">Keys</a></li>
+ <li ng-class="{active: path[2] == 'smtp-settings'}" data-ng-show="access.viewRealm"><a href="#/realms/{{realm.realm}}/smtp-settings">Email</a></li>
</ul>
\ No newline at end of file
diff --git a/model/api/src/main/java/org/keycloak/models/AdminRoles.java b/model/api/src/main/java/org/keycloak/models/AdminRoles.java
index ab414bf..a156be7 100644
--- a/model/api/src/main/java/org/keycloak/models/AdminRoles.java
+++ b/model/api/src/main/java/org/keycloak/models/AdminRoles.java
@@ -9,12 +9,17 @@ public class AdminRoles {
public static String ADMIN = "admin";
+ public static String VIEW_REALM = "view-realm";
+ public static String VIEW_USERS = "view-users";
+ public static String VIEW_APPLICATIONS = "view-applications";
+ public static String VIEW_CLIENTS = "view-clients";
+
public static String MANAGE_REALM = "manage-realm";
public static String MANAGE_USERS = "manage-users";
public static String MANAGE_APPLICATIONS = "manage-applications";
public static String MANAGE_CLIENTS = "manage-clients";
- public static String[] ALL_REALM_ROLES = {MANAGE_REALM, MANAGE_USERS, MANAGE_APPLICATIONS, MANAGE_CLIENTS};
+ public static String[] ALL_REALM_ROLES = {VIEW_REALM, VIEW_USERS, VIEW_APPLICATIONS, VIEW_CLIENTS, MANAGE_REALM, MANAGE_USERS, MANAGE_APPLICATIONS, MANAGE_CLIENTS};
public static String getAdminApp(RealmModel realm) {
return realm.getName() + APP_SUFFIX;
diff --git a/services/src/main/java/org/keycloak/services/managers/Auth.java b/services/src/main/java/org/keycloak/services/managers/Auth.java
index 3a2b21c..6bc8628 100644
--- a/services/src/main/java/org/keycloak/services/managers/Auth.java
+++ b/services/src/main/java/org/keycloak/services/managers/Auth.java
@@ -1,23 +1,14 @@
package org.keycloak.services.managers;
-import org.keycloak.models.ApplicationModel;
-import org.keycloak.models.Constants;
import org.keycloak.models.RealmModel;
-import org.keycloak.models.RoleModel;
import org.keycloak.models.UserModel;
import org.keycloak.representations.AccessToken;
-import javax.ws.rs.ForbiddenException;
-import java.util.Collections;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.Map;
-import java.util.Set;
-
/**
* @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
*/
public class Auth {
+
private final boolean cookie;
private final RealmModel realm;
private final AccessToken token;
@@ -62,77 +53,40 @@ public class Auth {
return token;
}
- public void require(String role) {
- if (!has(role)) {
- throw new ForbiddenException();
- }
- }
-
- public void require(String app, String role) {
- if (!has(app, role)) {
- throw new ForbiddenException();
- }
- }
-
- public void require(ApplicationModel app, String role) {
- if (!has(app, role)) {
- throw new ForbiddenException();
- }
- }
-
- public void requireOneOf(String app, String... roles) {
- if(!hasOneOf(app, roles)) {
- throw new ForbiddenException();
- }
- }
-
- public void requireOneOf(ApplicationModel app, String... roles) {
- if(!hasOneOf(app, roles)) {
- throw new ForbiddenException();
- }
- }
-
- public boolean has(String role) {
- if (cookie) {
+ public boolean hasRealmRole(String role) {
+ if (cookie) {
return realm.hasRole(user, realm.getRole(role));
} else {
- return token.getRealmAccess() != null && token.getRealmAccess().isUserInRole(role);
+ AccessToken.Access access = token.getRealmAccess();
+ return access != null && access.isUserInRole(role);
}
}
- public boolean has(String app, String role) {
- if (cookie) {
- return realm.hasRole(user, realm.getApplicationByName(app).getRole(role));
- } else {
- AccessToken.Access access = token.getResourceAccess(app);
- return access != null && access.isUserInRole(role);
+ public boolean hasOneOfRealmRole(String... roles) {
+ for (String r : roles) {
+ if (hasRealmRole(r)) {
+ return true;
+ }
}
+ return false;
}
- public boolean has(ApplicationModel app, String role) {
+ public boolean hasAppRole(String app, String role) {
if (cookie) {
- return realm.hasRole(user, app.getRole(role));
+ return realm.hasRole(user, realm.getApplicationByName(app).getRole(role));
} else {
- AccessToken.Access access = token.getResourceAccess(app.getName());
+ AccessToken.Access access = token.getResourceAccess(app);
return access != null && access.isUserInRole(role);
}
}
- public boolean hasOneOf(String app, String... roles) {
+ public boolean hasOneOfAppRole(String app, String... roles) {
for (String r : roles) {
- if (has(app, r)) {
+ if (hasAppRole(app, r)) {
return true;
}
}
return false;
}
- public boolean hasOneOf(ApplicationModel app, String... roles) {
- for (String r : roles) {
- if (has(app, r)) {
- return true;
- }
- }
- return false;
- }
}
diff --git a/services/src/main/java/org/keycloak/services/resources/AccountService.java b/services/src/main/java/org/keycloak/services/resources/AccountService.java
index 407d2c9..a3afea9 100755
--- a/services/src/main/java/org/keycloak/services/resources/AccountService.java
+++ b/services/src/main/java/org/keycloak/services/resources/AccountService.java
@@ -81,7 +81,7 @@ public class AccountService {
Auth auth = getAuth(false);
if (auth != null) {
try {
- auth.require(application, AccountRoles.MANAGE_ACCOUNT);
+ require(auth, AccountRoles.MANAGE_ACCOUNT);
} catch (ForbiddenException e) {
return Flows.forms(realm, request, uriInfo).setError("No access").createErrorPage();
}
@@ -113,7 +113,7 @@ public class AccountService {
return forwardToPage(null, AccountPages.ACCOUNT);
} else if (types.contains(MediaType.APPLICATION_JSON_TYPE)) {
Auth auth = getAuth(true);
- auth.requireOneOf(application, AccountRoles.MANAGE_ACCOUNT, AccountRoles.VIEW_PROFILE);
+ requireOneOf(auth, AccountRoles.MANAGE_ACCOUNT, AccountRoles.VIEW_PROFILE);
return Cors.add(request, Response.ok(ModelToRepresentation.toRepresentation(auth.getUser()))).auth().allowedOrigins(auth.getClient()).build();
} else {
@@ -138,7 +138,7 @@ public class AccountService {
@Consumes(MediaType.APPLICATION_FORM_URLENCODED)
public Response processAccountUpdate(final MultivaluedMap<String, String> formData) {
Auth auth = getAuth(true);
- auth.require(application, AccountRoles.MANAGE_ACCOUNT);
+ require(auth, AccountRoles.MANAGE_ACCOUNT);
UserModel user = auth.getUser();
@@ -160,7 +160,7 @@ public class AccountService {
@GET
public Response processTotpRemove() {
Auth auth = getAuth(true);
- auth.require(application, AccountRoles.MANAGE_ACCOUNT);
+ require(auth, AccountRoles.MANAGE_ACCOUNT);
UserModel user = auth.getUser();
user.setTotp(false);
@@ -174,7 +174,7 @@ public class AccountService {
@Consumes(MediaType.APPLICATION_FORM_URLENCODED)
public Response processTotpUpdate(final MultivaluedMap<String, String> formData) {
Auth auth = getAuth(true);
- auth.require(application, AccountRoles.MANAGE_ACCOUNT);
+ require(auth, AccountRoles.MANAGE_ACCOUNT);
UserModel user = auth.getUser();
@@ -204,7 +204,7 @@ public class AccountService {
@Consumes(MediaType.APPLICATION_FORM_URLENCODED)
public Response processPasswordUpdate(final MultivaluedMap<String, String> formData) {
Auth auth = getAuth(true);
- auth.require(application, AccountRoles.MANAGE_ACCOUNT);
+ require(auth, AccountRoles.MANAGE_ACCOUNT);
UserModel user = auth.getUser();
@@ -345,4 +345,16 @@ public class AccountService {
return null;
}
+ public void require(Auth auth, String role) {
+ if (!auth.hasAppRole(application.getName(), role)) {
+ throw new ForbiddenException();
+ }
+ }
+
+ public void requireOneOf(Auth auth, String... roles) {
+ if (!auth.hasOneOfAppRole(application.getName(), roles)) {
+ throw new ForbiddenException();
+ }
+ }
+
}
diff --git a/services/src/main/java/org/keycloak/services/resources/admin/AdminService.java b/services/src/main/java/org/keycloak/services/resources/admin/AdminService.java
index 7a5719a..7a3fad1 100755
--- a/services/src/main/java/org/keycloak/services/resources/admin/AdminService.java
+++ b/services/src/main/java/org/keycloak/services/resources/admin/AdminService.java
@@ -234,6 +234,7 @@ public class AdminService {
if (auth == null) {
throw new NotAuthorizedException("Bearer");
}
+
RealmsAdminResource adminResource = new RealmsAdminResource(auth, tokenManager);
resourceContext.initResource(adminResource);
return adminResource;
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 e6f677c..3ab4f04 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
@@ -34,9 +34,10 @@ import java.util.Set;
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
* @version $Revision: 1 $
*/
-public class ApplicationResource extends RoleContainerResource {
+public class ApplicationResource {
protected static final Logger logger = Logger.getLogger(RealmAdminResource.class);
protected RealmModel realm;
+ private RealmAuth auth;
protected ApplicationModel application;
protected KeycloakSession session;
@Context
@@ -49,11 +50,13 @@ public class ApplicationResource extends RoleContainerResource {
return (KeycloakApplication)keycloak;
}
- public ApplicationResource(RealmModel realm, ApplicationModel applicationModel, KeycloakSession session) {
- super(realm, applicationModel);
+ public ApplicationResource(RealmModel realm, RealmAuth auth, ApplicationModel applicationModel, KeycloakSession session) {
this.realm = realm;
+ this.auth = auth;
this.application = applicationModel;
this.session = session;
+
+ auth.init(RealmAuth.Resource.APPLICATION);
}
@Path("claims")
@@ -64,6 +67,8 @@ public class ApplicationResource extends RoleContainerResource {
@PUT
@Consumes(MediaType.APPLICATION_JSON)
public void update(final ApplicationRepresentation rep) {
+ auth.requireManage();
+
ApplicationManager applicationManager = new ApplicationManager(new RealmManager(session));
applicationManager.updateApplication(rep, application);
}
@@ -73,6 +78,8 @@ public class ApplicationResource extends RoleContainerResource {
@NoCache
@Produces(MediaType.APPLICATION_JSON)
public ApplicationRepresentation getApplication() {
+ auth.requireView();
+
ApplicationManager applicationManager = new ApplicationManager(new RealmManager(session));
return applicationManager.toRepresentation(application);
}
@@ -83,6 +90,8 @@ public class ApplicationResource extends RoleContainerResource {
@Path("installation/json")
@Produces(MediaType.APPLICATION_JSON)
public String getInstallation() throws IOException {
+ auth.requireView();
+
ApplicationManager applicationManager = new ApplicationManager(new RealmManager(session));
Object rep = applicationManager.toInstallationRepresentation(realm, application, getKeycloakApplication().getBaseUri(uriInfo));
@@ -95,6 +104,8 @@ public class ApplicationResource extends RoleContainerResource {
@Path("installation/jboss")
@Produces(MediaType.TEXT_PLAIN)
public String getJBossInstallation() throws IOException {
+ auth.requireView();
+
ApplicationManager applicationManager = new ApplicationManager(new RealmManager(session));
return applicationManager.toJBossSubsystemConfig(realm, application, getKeycloakApplication().getBaseUri(uriInfo));
}
@@ -102,6 +113,8 @@ public class ApplicationResource extends RoleContainerResource {
@DELETE
@NoCache
public void deleteApplication() {
+ auth.requireManage();
+
realm.removeApplication(application.getId());
}
@@ -110,6 +123,8 @@ public class ApplicationResource extends RoleContainerResource {
@Produces("application/json")
@Consumes("application/json")
public CredentialRepresentation regenerateSecret() {
+ auth.requireManage();
+
logger.debug("regenerateSecret");
UserCredentialModel cred = new ApplicationManager().generateSecret(realm, application);
CredentialRepresentation rep = ModelToRepresentation.toRepresentation(cred);
@@ -120,6 +135,8 @@ public class ApplicationResource extends RoleContainerResource {
@GET
@Produces("application/json")
public CredentialRepresentation getClientSecret() {
+ auth.requireView();
+
logger.debug("getClientSecret");
UserCredentialModel model = realm.getSecret(application.getApplicationUser());
if (model == null) throw new NotFoundException("Application does not have a secret");
@@ -129,7 +146,12 @@ public class ApplicationResource extends RoleContainerResource {
@Path("scope-mappings")
public ScopeMappedResource getScopeMappedResource() {
- return new ScopeMappedResource(realm, application.getApplicationUser(), session);
+ return new ScopeMappedResource(realm, auth, application.getApplicationUser(), session);
+ }
+
+ @Path("roles")
+ public RoleContainerResource getRoleContainerResource() {
+ return new RoleContainerResource(realm, auth, application);
}
@Path("allowed-origins")
@@ -137,6 +159,8 @@ public class ApplicationResource extends RoleContainerResource {
@Produces("application/json")
public Set<String> getAllowedOrigins()
{
+ auth.requireView();
+
return application.getApplicationUser().getWebOrigins();
}
@@ -145,6 +169,8 @@ public class ApplicationResource extends RoleContainerResource {
@Consumes("application/json")
public void updateAllowedOrigins(Set<String> allowedOrigins)
{
+ auth.requireManage();
+
application.getApplicationUser().setWebOrigins(allowedOrigins);
}
@@ -153,6 +179,8 @@ public class ApplicationResource extends RoleContainerResource {
@Consumes("application/json")
public void deleteAllowedOrigins(Set<String> allowedOrigins)
{
+ auth.requireManage();
+
for (String origin : allowedOrigins) {
application.getApplicationUser().removeWebOrigin(origin);
}
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 4f9d5ca..6387e00 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
@@ -32,6 +32,7 @@ import java.util.List;
public class ApplicationsResource {
protected static final Logger logger = Logger.getLogger(RealmAdminResource.class);
protected RealmModel realm;
+ private RealmAuth auth;
@Context
protected ResourceContext resourceContext;
@@ -39,19 +40,32 @@ public class ApplicationsResource {
@Context
protected KeycloakSession session;
- public ApplicationsResource(RealmModel realm) {
+ public ApplicationsResource(RealmModel realm, RealmAuth auth) {
this.realm = realm;
+ this.auth = auth;
+
+ auth.init(RealmAuth.Resource.APPLICATION);
}
@GET
@Produces(MediaType.APPLICATION_JSON)
@NoCache
public List<ApplicationRepresentation> getApplications() {
+ auth.requireAny();
+
List<ApplicationRepresentation> rep = new ArrayList<ApplicationRepresentation>();
List<ApplicationModel> applicationModels = realm.getApplications();
ApplicationManager resourceManager = new ApplicationManager(new RealmManager(session));
+
+ boolean view = auth.hasView();
for (ApplicationModel applicationModel : applicationModels) {
- rep.add(resourceManager.toRepresentation(applicationModel));
+ if (view) {
+ rep.add(resourceManager.toRepresentation(applicationModel));
+ } else {
+ ApplicationRepresentation app = new ApplicationRepresentation();
+ app.setName(applicationModel.getName());
+ rep.add(app);
+ }
}
return rep;
}
@@ -59,6 +73,8 @@ public class ApplicationsResource {
@POST
@Consumes(MediaType.APPLICATION_JSON)
public Response createApplication(final @Context UriInfo uriInfo, final ApplicationRepresentation rep) {
+ auth.requireManage();
+
if (realm.getApplicationNameMap().containsKey(rep.getName())) {
return Flows.errors().exists("Application " + rep.getName() + " already exists");
}
@@ -73,7 +89,7 @@ public class ApplicationsResource {
if (applicationModel == null) {
throw new NotFoundException("Could not find application: " + name);
}
- ApplicationResource applicationResource = new ApplicationResource(realm, applicationModel, session);
+ ApplicationResource applicationResource = new ApplicationResource(realm, auth, applicationModel, session);
resourceContext.initResource(applicationResource);
return applicationResource;
}
diff --git a/services/src/main/java/org/keycloak/services/resources/admin/OAuthClientResource.java b/services/src/main/java/org/keycloak/services/resources/admin/OAuthClientResource.java
index ba1f0a1..25da583 100755
--- a/services/src/main/java/org/keycloak/services/resources/admin/OAuthClientResource.java
+++ b/services/src/main/java/org/keycloak/services/resources/admin/OAuthClientResource.java
@@ -38,6 +38,7 @@ import java.util.List;
public class OAuthClientResource {
protected static final Logger logger = Logger.getLogger(RealmAdminResource.class);
protected RealmModel realm;
+ private RealmAuth auth;
protected OAuthClientModel oauthClient;
protected KeycloakSession session;
@Context
@@ -50,10 +51,13 @@ public class OAuthClientResource {
return (KeycloakApplication)application;
}
- public OAuthClientResource(RealmModel realm, OAuthClientModel oauthClient, KeycloakSession session) {
+ public OAuthClientResource(RealmModel realm, RealmAuth auth, OAuthClientModel oauthClient, KeycloakSession session) {
this.realm = realm;
+ this.auth = auth;
this.oauthClient = oauthClient;
this.session = session;
+
+ auth.init(RealmAuth.Resource.CLIENT);
}
@Path("claims")
@@ -65,6 +69,8 @@ public class OAuthClientResource {
@PUT
@Consumes(MediaType.APPLICATION_JSON)
public void update(final OAuthClientRepresentation rep) {
+ auth.requireManage();
+
OAuthClientManager manager = new OAuthClientManager(realm);
manager.update(rep, oauthClient);
}
@@ -74,6 +80,8 @@ public class OAuthClientResource {
@NoCache
@Produces(MediaType.APPLICATION_JSON)
public OAuthClientRepresentation getOAuthClient() {
+ auth.requireView();
+
return OAuthClientManager.toRepresentation(oauthClient);
}
@@ -82,6 +90,8 @@ public class OAuthClientResource {
@Path("installation")
@Produces(MediaType.APPLICATION_JSON)
public String getInstallation() throws IOException {
+ auth.requireView();
+
OAuthClientManager manager = new OAuthClientManager(realm);
Object rep = manager.toInstallationRepresentation(realm, oauthClient, getApplication().getBaseUri(uriInfo));
@@ -92,6 +102,8 @@ public class OAuthClientResource {
@DELETE
@NoCache
public void deleteOAuthClient() {
+ auth.requireManage();
+
realm.removeOAuthClient(oauthClient.getId());
}
@@ -100,6 +112,8 @@ public class OAuthClientResource {
@Produces("application/json")
@Consumes("application/json")
public CredentialRepresentation regenerateSecret() {
+ auth.requireManage();
+
logger.debug("regenerateSecret");
UserCredentialModel cred = UserCredentialModel.generateSecret();
realm.updateCredential(oauthClient.getOAuthAgent(), cred);
@@ -111,6 +125,8 @@ public class OAuthClientResource {
@GET
@Produces("application/json")
public CredentialRepresentation getClientSecret() {
+ auth.requireView();
+
logger.debug("getClientSecret");
UserCredentialModel model = realm.getSecret(oauthClient.getOAuthAgent());
if (model == null) throw new NotFoundException("Application does not have a secret");
@@ -119,7 +135,7 @@ public class OAuthClientResource {
@Path("scope-mappings")
public ScopeMappedResource getScopeMappedResource() {
- return new ScopeMappedResource(realm, oauthClient.getOAuthAgent(), session);
+ return new ScopeMappedResource(realm, auth, oauthClient.getOAuthAgent(), session);
}
diff --git a/services/src/main/java/org/keycloak/services/resources/admin/OAuthClientsResource.java b/services/src/main/java/org/keycloak/services/resources/admin/OAuthClientsResource.java
index eaacae6..4456224 100755
--- a/services/src/main/java/org/keycloak/services/resources/admin/OAuthClientsResource.java
+++ b/services/src/main/java/org/keycloak/services/resources/admin/OAuthClientsResource.java
@@ -35,10 +35,14 @@ public class OAuthClientsResource {
@Context
protected ResourceContext resourceContext;
+ private RealmAuth auth;
- public OAuthClientsResource(RealmModel realm, KeycloakSession session) {
+ public OAuthClientsResource(RealmModel realm, RealmAuth auth, KeycloakSession session) {
+ this.auth = auth;
this.realm = realm;
this.session = session;
+
+ auth.init(RealmAuth.Resource.CLIENT);
}
@GET
@@ -47,8 +51,16 @@ public class OAuthClientsResource {
public List<OAuthClientRepresentation> getOAuthClients() {
List<OAuthClientRepresentation> rep = new ArrayList<OAuthClientRepresentation>();
List<OAuthClientModel> oauthModels = realm.getOAuthClients();
+
+ boolean view = auth.hasView();
for (OAuthClientModel oauth : oauthModels) {
- rep.add(OAuthClientManager.toRepresentation(oauth));
+ if (view) {
+ rep.add(OAuthClientManager.toRepresentation(oauth));
+ } else {
+ OAuthClientRepresentation client = new OAuthClientRepresentation();
+ client.setName(oauth.getOAuthAgent().getLoginName());
+ rep.add(client);
+ }
}
return rep;
}
@@ -56,6 +68,8 @@ public class OAuthClientsResource {
@POST
@Consumes(MediaType.APPLICATION_JSON)
public Response createOAuthClient(final @Context UriInfo uriInfo, final OAuthClientRepresentation rep) {
+ auth.requireManage();
+
OAuthClientManager resourceManager = new OAuthClientManager(realm);
OAuthClientModel oauth = resourceManager.create(rep);
return Response.created(uriInfo.getAbsolutePathBuilder().path(oauth.getId()).build()).build();
@@ -63,11 +77,13 @@ public class OAuthClientsResource {
@Path("{id}")
public OAuthClientResource getOAuthClient(final @PathParam("id") String id) {
+ auth.requireView();
+
OAuthClientModel oauth = realm.getOAuthClientById(id);
if (oauth == null) {
throw new NotFoundException();
}
- OAuthClientResource oAuthClientResource = new OAuthClientResource(realm, oauth, session);
+ OAuthClientResource oAuthClientResource = new OAuthClientResource(realm, auth, oauth, session);
resourceContext.initResource(oAuthClientResource);
return oAuthClientResource;
}
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 5ea0987..7f2f020 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
@@ -19,9 +19,9 @@ import javax.ws.rs.core.Context;
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
* @version $Revision: 1 $
*/
-public class RealmAdminResource extends RoleContainerResource {
+public class RealmAdminResource {
protected static final Logger logger = Logger.getLogger(RealmAdminResource.class);
- protected Auth auth;
+ protected RealmAuth auth;
protected RealmModel realm;
private TokenManager tokenManager;
@@ -31,43 +31,43 @@ public class RealmAdminResource extends RoleContainerResource {
@Context
protected KeycloakSession session;
- public RealmAdminResource(Auth auth, RealmModel realm, TokenManager tokenManager) {
- super(realm, realm);
+ public RealmAdminResource(RealmAuth auth, RealmModel realm, TokenManager tokenManager) {
this.auth = auth;
this.realm = realm;
this.tokenManager = tokenManager;
+
+ auth.init(RealmAuth.Resource.REALM);
}
@Path("applications")
public ApplicationsResource getApplications() {
- auth.require(AdminRoles.getAdminApp(realm), AdminRoles.MANAGE_APPLICATIONS);
-
- ApplicationsResource applicationsResource = new ApplicationsResource(realm);
+ ApplicationsResource applicationsResource = new ApplicationsResource(realm, auth);
resourceContext.initResource(applicationsResource);
return applicationsResource;
}
@Path("oauth-clients")
public OAuthClientsResource getOAuthClients() {
- auth.require(AdminRoles.getAdminApp(realm), AdminRoles.MANAGE_CLIENTS);
-
- OAuthClientsResource oauth = new OAuthClientsResource(realm, session);
+ OAuthClientsResource oauth = new OAuthClientsResource(realm, auth, session);
resourceContext.initResource(oauth);
return oauth;
}
+ @Path("roles")
+ public RoleContainerResource getRoleContainerResource() {
+ return new RoleContainerResource(realm, auth, realm);
+ }
+
@GET
@NoCache
@Produces("application/json")
public RealmRepresentation getRealm() {
- String realmAdminApp = AdminRoles.getAdminApp(realm);
- if (auth.has(realmAdminApp, AdminRoles.MANAGE_REALM)) {
+ if (auth.hasView()) {
return ModelToRepresentation.toRepresentation(realm);
} else {
- auth.requireOneOf(AdminRoles.getAdminApp(realm), AdminRoles.ALL_REALM_ROLES);
+ auth.requireAny();
RealmRepresentation rep = new RealmRepresentation();
- rep.setId(realm.getId());
rep.setRealm(realm.getName());
return rep;
@@ -77,15 +77,15 @@ public class RealmAdminResource extends RoleContainerResource {
@PUT
@Consumes("application/json")
public void updateRealm(final RealmRepresentation rep) {
- auth.require(AdminRoles.getAdminApp(realm), AdminRoles.MANAGE_REALM);
+ auth.requireManage();
logger.debug("updating realm: " + realm.getName());
new RealmManager(session).updateRealm(rep, realm);
}
@DELETE
- public void deleteRealms() {
- auth.require(AdminRoles.getAdminApp(realm), AdminRoles.MANAGE_REALM);
+ public void deleteRealm() {
+ auth.requireManage();
if (!new RealmManager(session).removeRealm(realm)) {
throw new NotFoundException();
@@ -94,18 +94,14 @@ public class RealmAdminResource extends RoleContainerResource {
@Path("users")
public UsersResource users() {
- auth.require(AdminRoles.getAdminApp(realm), AdminRoles.MANAGE_USERS);
-
- UsersResource users = new UsersResource(realm, tokenManager);
+ UsersResource users = new UsersResource(realm, auth, tokenManager);
resourceContext.initResource(users);
return users;
}
@Path("roles-by-id")
public RoleByIdResource rolesById() {
- auth.require(AdminRoles.getAdminApp(realm), AdminRoles.MANAGE_REALM);
-
- RoleByIdResource resource = new RoleByIdResource(realm);
+ RoleByIdResource resource = new RoleByIdResource(realm, auth);
resourceContext.initResource(resource);
return resource;
}
diff --git a/services/src/main/java/org/keycloak/services/resources/admin/RealmAuth.java b/services/src/main/java/org/keycloak/services/resources/admin/RealmAuth.java
new file mode 100644
index 0000000..d059c4c
--- /dev/null
+++ b/services/src/main/java/org/keycloak/services/resources/admin/RealmAuth.java
@@ -0,0 +1,88 @@
+package org.keycloak.services.resources.admin;
+
+import org.keycloak.models.AdminRoles;
+import org.keycloak.services.managers.Auth;
+
+import javax.ws.rs.ForbiddenException;
+
+/**
+ * @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
+ */
+public class RealmAuth {
+
+ private Resource resource;
+
+ public enum Resource {
+ APPLICATION, CLIENT, USER, REALM
+ }
+
+ private Auth auth;
+ private String realmAdminApp;
+
+ public RealmAuth(Auth auth, String realmAdminApp) {
+ this.auth = auth;
+ this.realmAdminApp = realmAdminApp;
+ }
+
+ public RealmAuth init(Resource resource) {
+ this.resource = resource;
+ return this;
+ }
+
+ public void requireAny() {
+ if (!auth.hasOneOfAppRole(realmAdminApp, AdminRoles.ALL_REALM_ROLES)) {
+ throw new ForbiddenException();
+ }
+ }
+
+ public boolean hasView() {
+ return auth.hasOneOfAppRole(realmAdminApp, getViewRole(resource), getManageRole(resource));
+ }
+
+ public boolean hasManage() {
+ return auth.hasOneOfAppRole(realmAdminApp, getManageRole(resource));
+ }
+
+ public void requireView() {
+ if (!hasView()) {
+ throw new ForbiddenException();
+ }
+ }
+
+ public void requireManage() {
+ if (!hasManage()) {
+ throw new ForbiddenException();
+ }
+ }
+
+ private String getViewRole(Resource resource) {
+ switch (resource) {
+ case APPLICATION:
+ return AdminRoles.VIEW_APPLICATIONS;
+ case CLIENT:
+ return AdminRoles.VIEW_CLIENTS;
+ case USER:
+ return AdminRoles.VIEW_USERS;
+ case REALM:
+ return AdminRoles.VIEW_REALM;
+ default:
+ throw new IllegalStateException();
+ }
+ }
+
+ private String getManageRole(Resource resource) {
+ switch (resource) {
+ case APPLICATION:
+ return AdminRoles.MANAGE_APPLICATIONS;
+ case CLIENT:
+ return AdminRoles.MANAGE_CLIENTS;
+ case USER:
+ return AdminRoles.MANAGE_USERS;
+ case REALM:
+ return AdminRoles.MANAGE_REALM;
+ default:
+ throw new IllegalStateException();
+ }
+ }
+
+}
diff --git a/services/src/main/java/org/keycloak/services/resources/admin/RealmsAdminResource.java b/services/src/main/java/org/keycloak/services/resources/admin/RealmsAdminResource.java
index f0691d4..c2cbafb 100755
--- a/services/src/main/java/org/keycloak/services/resources/admin/RealmsAdminResource.java
+++ b/services/src/main/java/org/keycloak/services/resources/admin/RealmsAdminResource.java
@@ -6,8 +6,6 @@ import org.jboss.resteasy.plugins.providers.multipart.InputPart;
import org.jboss.resteasy.plugins.providers.multipart.MultipartFormDataInput;
import org.jboss.resteasy.util.GenericType;
import org.keycloak.models.AdminRoles;
-import org.keycloak.models.ApplicationModel;
-import org.keycloak.models.Constants;
import org.keycloak.models.KeycloakSession;
import org.keycloak.models.RealmModel;
import org.keycloak.representations.idm.RealmRepresentation;
@@ -67,11 +65,10 @@ public class RealmsAdminResource {
for (RealmModel realm : realms) {
String realmAdminApp = AdminRoles.getAdminApp(realm);
- if (auth.has(realmAdminApp, AdminRoles.MANAGE_REALM)) {
+ if (auth.hasAppRole(realmAdminApp, AdminRoles.MANAGE_REALM)) {
reps.add(ModelToRepresentation.toRepresentation(realm));
- } else if (auth.hasOneOf(realmAdminApp, AdminRoles.ALL_REALM_ROLES)) {
+ } else if (auth.hasOneOfAppRole(realmAdminApp, AdminRoles.ALL_REALM_ROLES)) {
RealmRepresentation rep = new RealmRepresentation();
- rep.setId(realm.getId());
rep.setRealm(realm.getName());
reps.add(rep);
}
@@ -90,7 +87,9 @@ public class RealmsAdminResource {
@POST
@Consumes("application/json")
public Response importRealm(@Context final UriInfo uriInfo, final RealmRepresentation rep) {
- auth.require(AdminRoles.ADMIN);
+ if (!auth.hasRealmRole(AdminRoles.ADMIN)) {
+ throw new ForbiddenException();
+ }
logger.debug("importRealm: {0}", rep.getRealm());
RealmManager realmManager = new RealmManager(session);
@@ -107,7 +106,9 @@ public class RealmsAdminResource {
@POST
@Consumes(MediaType.MULTIPART_FORM_DATA)
public Response uploadRealm(MultipartFormDataInput input) throws IOException {
- auth.require(AdminRoles.ADMIN);
+ if (!auth.hasRealmRole(AdminRoles.ADMIN)) {
+ throw new ForbiddenException();
+ }
Map<String, List<InputPart>> uploadForm = input.getFormDataMap();
List<InputPart> inputParts = uploadForm.get("file");
@@ -128,9 +129,9 @@ public class RealmsAdminResource {
RealmModel realm = realmManager.getRealmByName(name);
if (realm == null) throw new NotFoundException("{realm} = " + name);
- auth.requireOneOf(AdminRoles.getAdminApp(realm), AdminRoles.ALL_REALM_ROLES);
+ RealmAuth realmAuth = new RealmAuth(auth, AdminRoles.getAdminApp(realm));
- RealmAdminResource adminResource = new RealmAdminResource(auth, realm, tokenManager);
+ RealmAdminResource adminResource = new RealmAdminResource(realmAuth, realm, tokenManager);
resourceContext.initResource(adminResource);
return adminResource;
}
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 98869bf..f5b7cb0 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
@@ -1,14 +1,13 @@
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.OAuthClientModel;
import org.keycloak.models.RealmModel;
-import org.keycloak.models.RoleContainerModel;
import org.keycloak.models.RoleModel;
+import org.keycloak.models.UserModel;
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;
@@ -19,10 +18,6 @@ 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;
@@ -33,8 +28,14 @@ import java.util.Set;
* @version $Revision: 1 $
*/
public class RoleByIdResource extends RoleResource {
- public RoleByIdResource(RealmModel realm) {
+ private final RealmModel realm;
+ private final RealmAuth auth;
+
+ public RoleByIdResource(RealmModel realm, RealmAuth auth) {
super(realm);
+
+ this.realm = realm;
+ this.auth = auth;
}
@Path("{role-id}")
@@ -43,6 +44,7 @@ public class RoleByIdResource extends RoleResource {
@Produces("application/json")
public RoleRepresentation getRole(final @PathParam("role-id") String id) {
RoleModel roleModel = getRoleModel(id);
+ auth.requireView();
return getRole(roleModel);
}
@@ -51,6 +53,19 @@ public class RoleByIdResource extends RoleResource {
if (roleModel == null || roleModel.getName().startsWith(Constants.INTERNAL_ROLE)) {
throw new NotFoundException("Could not find role with id: " + id);
}
+
+ RealmAuth.Resource r = null;
+ if (roleModel.getContainer() instanceof RealmModel) {
+ r = RealmAuth.Resource.REALM;
+ } else if (roleModel.getContainer() instanceof ApplicationModel) {
+ r = RealmAuth.Resource.APPLICATION;
+ } else if (roleModel.getContainer() instanceof OAuthClientModel) {
+ r = RealmAuth.Resource.CLIENT;
+ } else if (roleModel.getContainer() instanceof UserModel) {
+ r = RealmAuth.Resource.USER;
+ }
+ auth.init(r);
+
return roleModel;
}
@@ -59,6 +74,7 @@ public class RoleByIdResource extends RoleResource {
@NoCache
public void deleteRole(final @PathParam("role-id") String id) {
RoleModel role = getRoleModel(id);
+ auth.requireManage();
deleteRole(role);
}
@@ -67,6 +83,7 @@ public class RoleByIdResource extends RoleResource {
@Consumes("application/json")
public void updateRole(final @PathParam("role-id") String id, final RoleRepresentation rep) {
RoleModel role = getRoleModel(id);
+ auth.requireManage();
updateRole(rep, role);
}
@@ -75,6 +92,7 @@ public class RoleByIdResource extends RoleResource {
@Consumes("application/json")
public void addComposites(final @PathParam("role-id") String id, List<RoleRepresentation> roles) {
RoleModel role = getRoleModel(id);
+ auth.requireManage();
addComposites(roles, role);
}
@@ -84,6 +102,7 @@ public class RoleByIdResource extends RoleResource {
@Produces("application/json")
public Set<RoleRepresentation> getRoleComposites(final @PathParam("role-id") String id) {
RoleModel role = getRoleModel(id);
+ auth.requireView();
return getRoleComposites(role);
}
@@ -93,6 +112,7 @@ public class RoleByIdResource extends RoleResource {
@Produces("application/json")
public Set<RoleRepresentation> getRealmRoleComposites(final @PathParam("role-id") String id) {
RoleModel role = getRoleModel(id);
+ auth.requireView();
return getRealmRoleComposites(role);
}
@@ -103,6 +123,7 @@ public class RoleByIdResource extends RoleResource {
public Set<RoleRepresentation> getApplicationRoleComposites(final @PathParam("role-id") String id,
final @PathParam("app") String appName) {
RoleModel role = getRoleModel(id);
+ auth.requireView();
return getApplicationRoleComposites(appName, role);
}
@@ -112,8 +133,8 @@ public class RoleByIdResource extends RoleResource {
@Consumes("application/json")
public void deleteComposites(final @PathParam("role-id") String id, List<RoleRepresentation> roles) {
RoleModel role = getRoleModel(id);
+ auth.requireManage();
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 e1f07fb..5bbd44b 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,6 @@
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;
@@ -10,13 +9,19 @@ import org.keycloak.representations.idm.RoleRepresentation;
import org.keycloak.services.managers.ModelToRepresentation;
import org.keycloak.services.resources.flows.Flows;
-import javax.ws.rs.*;
+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.Collections;
-import java.util.HashSet;
import java.util.List;
import java.util.Set;
@@ -25,18 +30,24 @@ import java.util.Set;
* @version $Revision: 1 $
*/
public class RoleContainerResource extends RoleResource {
+ private final RealmModel realm;
+ private final RealmAuth auth;
protected RoleContainerModel roleContainer;
- public RoleContainerResource(RealmModel realm, RoleContainerModel roleContainer) {
+ public RoleContainerResource(RealmModel realm, RealmAuth auth, RoleContainerModel roleContainer) {
super(realm);
+ this.realm = realm;
+ this.auth = auth;
this.roleContainer = roleContainer;
}
- @Path("roles")
+ @Path("")
@GET
@NoCache
@Produces("application/json")
public List<RoleRepresentation> getRoles() {
+ auth.requireAny();
+
Set<RoleModel> roleModels = roleContainer.getRoles();
List<RoleRepresentation> roles = new ArrayList<RoleRepresentation>();
for (RoleModel roleModel : roleModels) {
@@ -47,10 +58,12 @@ public class RoleContainerResource extends RoleResource {
return roles;
}
- @Path("roles")
+ @Path("")
@POST
@Consumes("application/json")
public Response createRole(final @Context UriInfo uriInfo, final RoleRepresentation rep) {
+ auth.requireManage();
+
if (roleContainer.getRole(rep.getName()) != null || rep.getName().startsWith(Constants.INTERNAL_ROLE)) {
return Flows.errors().exists("Role with name " + rep.getName() + " already exists");
}
@@ -62,11 +75,13 @@ public class RoleContainerResource extends RoleResource {
return Response.created(uriInfo.getAbsolutePathBuilder().path(role.getName()).build()).build();
}
- @Path("roles/{role-name}")
+ @Path("{role-name}")
@GET
@NoCache
@Produces("application/json")
public RoleRepresentation getRole(final @PathParam("role-name") String roleName) {
+ auth.requireView();
+
RoleModel roleModel = roleContainer.getRole(roleName);
if (roleModel == null || roleModel.getName().startsWith(Constants.INTERNAL_ROLE)) {
throw new NotFoundException("Could not find role: " + roleName);
@@ -74,10 +89,12 @@ public class RoleContainerResource extends RoleResource {
return getRole(roleModel);
}
- @Path("roles/{role-name}")
+ @Path("{role-name}")
@DELETE
@NoCache
public void deleteRole(final @PathParam("role-name") String roleName) {
+ auth.requireManage();
+
RoleModel role = roleContainer.getRole(roleName);
if (role == null) {
throw new NotFoundException("Could not find role: " + roleName);
@@ -85,10 +102,12 @@ public class RoleContainerResource extends RoleResource {
deleteRole(role);
}
- @Path("roles/{role-name}")
+ @Path("{role-name}")
@PUT
@Consumes("application/json")
public void updateRole(final @PathParam("role-name") String roleName, final RoleRepresentation rep) {
+ auth.requireManage();
+
RoleModel role = roleContainer.getRole(roleName);
if (role == null || role.getName().startsWith(Constants.INTERNAL_ROLE)) {
throw new NotFoundException("Could not find role: " + roleName);
@@ -96,10 +115,12 @@ public class RoleContainerResource extends RoleResource {
updateRole(rep, role);
}
- @Path("roles/{role-name}/composites")
+ @Path("{role-name}/composites")
@POST
@Consumes("application/json")
public void addComposites(final @PathParam("role-name") String roleName, List<RoleRepresentation> roles) {
+ auth.requireManage();
+
RoleModel role = roleContainer.getRole(roleName);
if (role == null || role.getName().startsWith(Constants.INTERNAL_ROLE)) {
throw new NotFoundException("Could not find role: " + roleName);
@@ -107,11 +128,13 @@ public class RoleContainerResource extends RoleResource {
addComposites(roles, role);
}
- @Path("roles/{role-name}/composites")
+ @Path("{role-name}/composites")
@GET
@NoCache
@Produces("application/json")
public Set<RoleRepresentation> getRoleComposites(final @PathParam("role-name") String roleName) {
+ auth.requireManage();
+
RoleModel role = roleContainer.getRole(roleName);
if (role == null || role.getName().startsWith(Constants.INTERNAL_ROLE)) {
throw new NotFoundException("Could not find role: " + roleName);
@@ -119,11 +142,13 @@ public class RoleContainerResource extends RoleResource {
return getRoleComposites(role);
}
- @Path("roles/{role-name}/composites/realm")
+ @Path("{role-name}/composites/realm")
@GET
@NoCache
@Produces("application/json")
public Set<RoleRepresentation> getRealmRoleComposites(final @PathParam("role-name") String roleName) {
+ auth.requireManage();
+
RoleModel role = roleContainer.getRole(roleName);
if (role == null || role.getName().startsWith(Constants.INTERNAL_ROLE)) {
throw new NotFoundException("Could not find role: " + roleName);
@@ -131,12 +156,14 @@ public class RoleContainerResource extends RoleResource {
return getRealmRoleComposites(role);
}
- @Path("roles/{role-name}/composites/application/{app}")
+ @Path("{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) {
+ auth.requireManage();
+
RoleModel role = roleContainer.getRole(roleName);
if (role == null || role.getName().startsWith(Constants.INTERNAL_ROLE)) {
throw new NotFoundException("Could not find role: " + roleName);
@@ -145,10 +172,12 @@ public class RoleContainerResource extends RoleResource {
}
- @Path("roles/{role-name}/composites")
+ @Path("{role-name}/composites")
@DELETE
@Consumes("application/json")
public void deleteComposites(final @PathParam("role-name") String roleName, List<RoleRepresentation> roles) {
+ auth.requireManage();
+
RoleModel role = roleContainer.getRole(roleName);
if (role == null || role.getName().startsWith(Constants.INTERNAL_ROLE)) {
throw new NotFoundException("Could not find role: " + roleName);
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 91e42b4..94d95af 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
@@ -16,7 +16,7 @@ import java.util.Set;
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
* @version $Revision: 1 $
*/
-public class RoleResource {
+public abstract class RoleResource {
protected RealmModel realm;
public RoleResource(RealmModel realm) {
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 c630d28..c5e8662 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
@@ -32,11 +32,13 @@ import java.util.Set;
*/
public class ScopeMappedResource {
protected RealmModel realm;
+ private RealmAuth auth;
protected UserModel agent;
protected KeycloakSession session;
- public ScopeMappedResource(RealmModel realm, UserModel account, KeycloakSession session) {
+ public ScopeMappedResource(RealmModel realm, RealmAuth auth, UserModel account, KeycloakSession session) {
this.realm = realm;
+ this.auth = auth;
this.agent = account;
this.session = session;
}
@@ -45,6 +47,8 @@ public class ScopeMappedResource {
@Produces("application/json")
@NoCache
public MappingsRepresentation getScopeMappings() {
+ auth.requireView();
+
MappingsRepresentation all = new MappingsRepresentation();
Set<RoleModel> realmMappings = realm.getRealmScopeMappings(agent);
RealmManager manager = new RealmManager(session);
@@ -83,6 +87,8 @@ public class ScopeMappedResource {
@Produces("application/json")
@NoCache
public List<RoleRepresentation> getRealmScopeMappings() {
+ auth.requireView();
+
Set<RoleModel> realmMappings = realm.getRealmScopeMappings(agent);
List<RoleRepresentation> realmMappingsRep = new ArrayList<RoleRepresentation>();
RealmManager manager = new RealmManager(session);
@@ -96,6 +102,8 @@ public class ScopeMappedResource {
@POST
@Consumes("application/json")
public void addRealmScopeMappings(List<RoleRepresentation> roles) {
+ auth.requireManage();
+
for (RoleRepresentation role : roles) {
RoleModel roleModel = realm.getRoleById(role.getId());
if (roleModel == null) {
@@ -111,6 +119,8 @@ public class ScopeMappedResource {
@DELETE
@Consumes("application/json")
public void deleteRealmScopeMappings(List<RoleRepresentation> roles) {
+ auth.requireManage();
+
if (roles == null) {
Set<RoleModel> roleModels = realm.getRealmScopeMappings(agent);
for (RoleModel roleModel : roleModels) {
@@ -133,6 +143,8 @@ public class ScopeMappedResource {
@Produces("application/json")
@NoCache
public List<RoleRepresentation> getApplicationScopeMappings(@PathParam("app") String appName) {
+ auth.requireView();
+
ApplicationModel app = realm.getApplicationByName(appName);
if (app == null) {
@@ -151,6 +163,8 @@ public class ScopeMappedResource {
@POST
@Consumes("application/json")
public void addApplicationScopeMapping(@PathParam("app") String appName, List<RoleRepresentation> roles) {
+ auth.requireManage();
+
ApplicationModel app = realm.getApplicationByName(appName);
if (app == null) {
@@ -171,6 +185,8 @@ public class ScopeMappedResource {
@DELETE
@Consumes("application/json")
public void deleteApplicationScopeMapping(@PathParam("app") String appName, List<RoleRepresentation> roles) {
+ auth.requireManage();
+
ApplicationModel app = realm.getApplicationByName(appName);
if (app == null) {
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 2af61a9..212c6b6 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
@@ -13,6 +13,7 @@ import org.keycloak.representations.idm.*;
import org.keycloak.services.email.EmailException;
import org.keycloak.services.email.EmailSender;
import org.keycloak.services.managers.AccessCodeEntry;
+import org.keycloak.services.managers.Auth;
import org.keycloak.services.managers.ModelToRepresentation;
import org.keycloak.services.managers.RealmManager;
import org.keycloak.services.managers.TokenManager;
@@ -50,11 +51,15 @@ public class UsersResource {
protected RealmModel realm;
+ private RealmAuth auth;
private TokenManager tokenManager;
- public UsersResource(RealmModel realm, TokenManager tokenManager) {
+ public UsersResource(RealmModel realm, RealmAuth auth, TokenManager tokenManager) {
+ this.auth = auth;
this.realm = realm;
this.tokenManager = tokenManager;
+
+ auth.init(RealmAuth.Resource.USER);
}
@Context
@@ -71,6 +76,8 @@ public class UsersResource {
@PUT
@Consumes("application/json")
public void updateUser(final @PathParam("username") String username, final UserRepresentation rep) {
+ auth.requireManage();
+
UserModel user = realm.getUser(username);
if (user == null) {
throw new NotFoundException();
@@ -81,6 +88,8 @@ public class UsersResource {
@POST
@Consumes("application/json")
public Response createUser(final @Context UriInfo uriInfo, final UserRepresentation rep) {
+ auth.requireManage();
+
if (realm.getUser(rep.getUsername()) != null) {
return Flows.errors().exists("User with username " + rep.getUsername() + " already exists");
}
@@ -125,6 +134,8 @@ public class UsersResource {
@NoCache
@Produces("application/json")
public UserRepresentation getUser(final @PathParam("username") String username) {
+ auth.requireView();
+
UserModel user = realm.getUser(username);
if (user == null || !isUser(user)) {
throw new NotFoundException();
@@ -136,6 +147,8 @@ public class UsersResource {
@DELETE
@NoCache
public void deleteUser(final @PathParam("username") String username) {
+ auth.requireManage();
+
realm.removeUser(username);
}
@@ -147,6 +160,8 @@ public class UsersResource {
@QueryParam("firstName") String first,
@QueryParam("email") String email,
@QueryParam("username") String username) {
+ auth.requireView();
+
RealmManager manager = new RealmManager(session);
List<UserRepresentation> results = new ArrayList<UserRepresentation>();
List<UserModel> userModels;
@@ -191,6 +206,8 @@ public class UsersResource {
@Produces("application/json")
@NoCache
public MappingsRepresentation getRoleMappings(@PathParam("username") String username) {
+ auth.requireView();
+
UserModel user = realm.getUser(username);
if (user == null) {
throw new NotFoundException();
@@ -234,6 +251,8 @@ public class UsersResource {
@Produces("application/json")
@NoCache
public List<RoleRepresentation> getRealmRoleMappings(@PathParam("username") String username) {
+ auth.requireView();
+
UserModel user = realm.getUser(username);
if (user == null) {
throw new NotFoundException();
@@ -252,6 +271,8 @@ public class UsersResource {
@POST
@Consumes("application/json")
public void addRealmRoleMappings(@PathParam("username") String username, List<RoleRepresentation> roles) {
+ auth.requireManage();
+
logger.debug("** addRealmRoleMappings: {0}", roles);
UserModel user = realm.getUser(username);
if (user == null) {
@@ -273,6 +294,8 @@ public class UsersResource {
@DELETE
@Consumes("application/json")
public void deleteRealmRoleMappings(@PathParam("username") String username, List<RoleRepresentation> roles) {
+ auth.requireManage();
+
logger.debug("deleteRealmRoleMappings");
UserModel user = realm.getUser(username);
if (user == null) {
@@ -301,6 +324,8 @@ public class UsersResource {
@Produces("application/json")
@NoCache
public List<RoleRepresentation> getApplicationRoleMappings(@PathParam("username") String username, @PathParam("app") String appName) {
+ auth.requireView();
+
logger.debug("getApplicationRoleMappings");
UserModel user = realm.getUser(username);
@@ -327,6 +352,8 @@ public class UsersResource {
@POST
@Consumes("application/json")
public void addApplicationRoleMapping(@PathParam("username") String username, @PathParam("app") String appName, List<RoleRepresentation> roles) {
+ auth.requireManage();
+
logger.debug("addApplicationRoleMapping");
UserModel user = realm.getUser(username);
if (user == null) {
@@ -353,6 +380,8 @@ public class UsersResource {
@DELETE
@Consumes("application/json")
public void deleteApplicationRoleMapping(@PathParam("username") String username, @PathParam("app") String appName, List<RoleRepresentation> roles) {
+ auth.requireManage();
+
UserModel user = realm.getUser(username);
if (user == null) {
throw new NotFoundException();
@@ -389,6 +418,8 @@ public class UsersResource {
@PUT
@Consumes("application/json")
public void resetPassword(@PathParam("username") String username, CredentialRepresentation pass) {
+ auth.requireManage();
+
UserModel user = realm.getUser(username);
if (user == null) {
throw new NotFoundException();
@@ -406,6 +437,8 @@ public class UsersResource {
@PUT
@Consumes("application/json")
public void removeTotp(@PathParam("username") String username) {
+ auth.requireManage();
+
UserModel user = realm.getUser(username);
if (user == null) {
throw new NotFoundException();
@@ -418,6 +451,8 @@ public class UsersResource {
@PUT
@Consumes("application/json")
public Response resetPasswordEmail(@PathParam("username") String username) {
+ auth.requireManage();
+
UserModel user = realm.getUser(username);
if (user == null) {
throw new NotFoundException();