Merge pull request #186 from patriot1burke/master

composite UI
This commit is contained in:
Bill Burke 2014-01-31 18:41:40 -08:00
commit 1d2d4da7ff
13 changed files with 1187 additions and 617 deletions

View file

@ -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'

View file

@ -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) {

View file

@ -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) {

View file

@ -181,6 +181,187 @@ module.factory('RealmRoles', function($resource) {
});
});
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) {
@ -194,6 +375,17 @@ module.factory('Role', function($resource) {
});
});
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',

View file

@ -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>

View file

@ -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>

View file

@ -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;
}
}

View file

@ -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;

View file

@ -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);

View file

@ -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;
}
}

View file

@ -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);
}
}

View file

@ -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,100 +47,6 @@ public class RoleContainerResource {
return roles;
}
@Path("roles/{role-name}")
@GET
@NoCache
@Produces("application/json")
public RoleRepresentation getRole(final @PathParam("role-name") String roleName) {
RoleModel roleModel = roleContainer.getRole(roleName);
if (roleModel == null || roleModel.getName().startsWith(Constants.INTERNAL_ROLE)) {
throw new NotFoundException("Could not find role: " + roleName);
}
return ModelToRepresentation.toRepresentation(roleModel);
}
@Path("roles/{role-name}")
@DELETE
@NoCache
public void deleteRole(final @PathParam("role-name") String roleName) {
RoleModel role = roleContainer.getRole(roleName);
if (role == null) {
throw new NotFoundException("Could not find role: " + roleName);
}
if (!roleContainer.removeRoleById(role.getId())) {
throw new NotFoundException();
}
}
@Path("roles/{role-name}")
@PUT
@Consumes("application/json")
public void updateRole(final @PathParam("role-name") String roleName, final RoleRepresentation rep) {
RoleModel role = roleContainer.getRole(roleName);
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());
}
@Path("roles/{role-name}/composites")
@POST
@Consumes("application/json")
public void addComposites(final @PathParam("role-name") String roleName, List<RoleRepresentation> roles) {
RoleModel role = roleContainer.getRole(roleName);
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);
}
}
@Path("roles/{role-name}/composites")
@GET
@NoCache
@Produces("application/json")
public Set<RoleRepresentation> getRoleComposites(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);
}
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;
}
@Path("roles/{role-name}/composites")
@DELETE
@Consumes("application/json")
public void deleteComposites(final @PathParam("role-name") String roleName, List<RoleRepresentation> roles) {
RoleModel role = roleContainer.getRole(roleName);
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);
}
@Path("roles")
@POST
@Consumes("application/json")
@ -153,4 +62,100 @@ public class RoleContainerResource {
role.setComposite(rep.isComposite());
return Response.created(uriInfo.getAbsolutePathBuilder().path(role.getName()).build()).build();
}
@Path("roles/{role-name}")
@GET
@NoCache
@Produces("application/json")
public RoleRepresentation getRole(final @PathParam("role-name") String roleName) {
RoleModel roleModel = roleContainer.getRole(roleName);
if (roleModel == null || roleModel.getName().startsWith(Constants.INTERNAL_ROLE)) {
throw new NotFoundException("Could not find role: " + roleName);
}
return getRole(roleModel);
}
@Path("roles/{role-name}")
@DELETE
@NoCache
public void deleteRole(final @PathParam("role-name") String roleName) {
RoleModel role = roleContainer.getRole(roleName);
if (role == null) {
throw new NotFoundException("Could not find role: " + roleName);
}
deleteRole(role);
}
@Path("roles/{role-name}")
@PUT
@Consumes("application/json")
public void updateRole(final @PathParam("role-name") String roleName, final RoleRepresentation rep) {
RoleModel role = roleContainer.getRole(roleName);
if (role == null || role.getName().startsWith(Constants.INTERNAL_ROLE)) {
throw new NotFoundException("Could not find role: " + roleName);
}
updateRole(rep, role);
}
@Path("roles/{role-name}/composites")
@POST
@Consumes("application/json")
public void addComposites(final @PathParam("role-name") String roleName, List<RoleRepresentation> roles) {
RoleModel role = roleContainer.getRole(roleName);
if (role == null || role.getName().startsWith(Constants.INTERNAL_ROLE)) {
throw new NotFoundException("Could not find role: " + roleName);
}
addComposites(roles, role);
}
@Path("roles/{role-name}/composites")
@GET
@NoCache
@Produces("application/json")
public Set<RoleRepresentation> getRoleComposites(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 getRoleComposites(role);
}
@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 getApplicationRoleComposites(appName, role);
}
@Path("roles/{role-name}/composites")
@DELETE
@Consumes("application/json")
public void deleteComposites(final @PathParam("role-name") String roleName, List<RoleRepresentation> roles) {
RoleModel role = roleContainer.getRole(roleName);
if (role == null || role.getName().startsWith(Constants.INTERNAL_ROLE)) {
throw new NotFoundException("Could not find role: " + roleName);
}
deleteComposites(roles, role);
}
}

View file

@ -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);
}
}