Merge pull request #18 from patriot1burke/master

roles
This commit is contained in:
Bill Burke 2013-08-03 19:44:08 -07:00
commit c4c3c7f7e6
17 changed files with 468 additions and 128 deletions

View file

@ -5,6 +5,7 @@ package org.keycloak.representations.idm;
* @version $Revision: 1 $
*/
public class RoleRepresentation {
protected String id;
protected String name;
protected String description;
@ -16,6 +17,14 @@ public class RoleRepresentation {
this.description = description;
}
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getName() {
return name;
}

View file

@ -92,43 +92,42 @@ module.config([ '$routeProvider', function($routeProvider) {
},
controller : 'UserListCtrl'
})
.when('/realms/:realm/roles', {
templateUrl : 'partials/role-mapping.html',
resolve : {
realm : function(RealmLoader) {
return RealmLoader();
},
application : function() {
return null;
},
users : function() {
return null;
},
role : function() {
return null;
}
},
controller : 'RoleMappingCtrl'
}).when('/realms/:realm/roles/:role', {
templateUrl : 'partials/role-mapping.html',
resolve : {
realm : function(RealmLoader) {
return RealmLoader();
},
application : function() {
return null;
},
role : function($route) {
return $route.current.params.role;
},
users : function(RoleMappingLoader) {
return RoleMappingLoader();
}
},
controller : 'RoleMappingCtrl'
})
.when('/create/role/:realm', {
templateUrl : 'partials/role-detail.html',
resolve : {
realm : function(RealmLoader) {
return RealmLoader();
},
role : function() {
return {};
}
},
controller : 'RoleDetailCtrl'
}).when('/realms/:realm/roles/:role', {
templateUrl : 'partials/role-detail.html',
resolve : {
realm : function(RealmLoader) {
return RealmLoader();
},
role : function(RoleLoader) {
return RoleLoader();
}
},
controller : 'RoleDetailCtrl'
}).when('/realms/:realm/roles', {
templateUrl : 'partials/role-list.html',
resolve : {
realm : function(RealmLoader) {
return RealmLoader();
},
roles : function(RoleListLoader) {
return RoleListLoader();
}
},
controller : 'RoleListCtrl'
})
.when('/applications/:application/roles', {
templateUrl : 'partials/role-mapping.html',
resolve : {

View file

@ -2,7 +2,9 @@
var module = angular.module('keycloak.controllers', [ 'keycloak.services' ]);
module.controller('GlobalCtrl', function($scope, Auth, $location, Notifications) {
var realmslist = {};
module.controller('GlobalCtrl', function($scope, $http, Auth, $location, Notifications) {
$scope.addMessage = function() {
Notifications.success("test");
};
@ -14,6 +16,28 @@ module.controller('GlobalCtrl', function($scope, Auth, $location, Notifications)
}, function() {
$scope.path = $location.path().substring(1).split("/");
});
$http.get('/auth-server/rest/saas/admin/realms').success(function(data) {
var count = 0;
var showrealm = false;
var id = null;
for (var key in data) {
if (count > 0) {
showrealm = false;
break;
}
id = key;
showrealm = true;
count++;
}
if (showrealm) {
console.log('redirecting');
$location.url("/realms/" + id);
} else {
console.log('not redirecting');
}
});
});
module.controller('ApplicationListCtrl', function($scope, Application) {
@ -130,13 +154,22 @@ module.controller('ApplicationDetailCtrl', function($scope, application, Applica
module.controller('RealmListCtrl', function($scope, Realm) {
$scope.realms = Realm.get();
realmslist = $scope.realms;
});
module.controller('RealmDropdownCtrl', function($scope, Realm) {
console.log('test log writing');
realmslist = Realm.get();
$scope.realmslist = function() {
return realmslist;
};
});
module.controller('RealmDetailCtrl', function($scope, Realm, realm, $location, Dialog, Notifications) {
$scope.realm = angular.copy(realm);
$scope.create = !realm.id;
$scope.createRealm = !realm.id;
if ($scope.create) {
if ($scope.createRealm) {
$scope.realm.enabled = true;
$scope.realm.requireSsl = true;
$scope.realm.cookieLoginAllowed = true;
@ -223,15 +256,17 @@ module.controller('RealmDetailCtrl', function($scope, Realm, realm, $location, D
};
if ($scope.create) {
if ($scope.createRealm) {
Realm.save(realmCopy, function(data, headers) {
var l = headers().location;
var id = l.substring(l.lastIndexOf("/") + 1);
realmslist = Realm.get();
$location.url("/realms/" + id);
Notifications.success("Created realm");
});
} else {
Realm.update(realmCopy, function() {
realmslist = Realm.get();
$scope.changed = false;
realm = angular.copy($scope.realm);
Notifications.success("Saved changes to realm");
@ -255,6 +290,7 @@ module.controller('RealmDetailCtrl', function($scope, Realm, realm, $location, D
$scope.remove = function() {
Dialog.confirmDelete($scope.realm.name, 'realm', function() {
Realm.remove($scope.realm, function() {
realmslist = Realm.get();
$location.url("/realms");
Notifications.success("Deleted realm");
});
@ -283,6 +319,9 @@ module.controller('UserDetailCtrl', function($scope, realm, user, User, $locatio
$scope.save = function() {
if ($scope.userForm.$valid) {
User.save({
realm : realm.id
}, $scope.user, function() {
@ -324,6 +363,79 @@ module.controller('UserDetailCtrl', function($scope, realm, user, User, $locatio
};
});
module.controller('RoleListCtrl', function($scope, realm, roles) {
$scope.realm = realm;
$scope.roles = roles;
});
module.controller('RoleDetailCtrl', function($scope, realm, role, Role, $location, Dialog, Notifications) {
$scope.realm = realm;
$scope.role = angular.copy(role);
$scope.create = !role.name;
$scope.changed = $scope.create;
$scope.$watch('role', function() {
if (!angular.equals($scope.role, role)) {
$scope.changed = true;
}
}, true);
$scope.save = function() {
if ($scope.roleForm.$valid) {
if ($scope.create) {
Role.save({
realm: realm.id
}, $scope.role, function (data, headers) {
$scope.changed = false;
role = angular.copy($scope.role);
var l = headers().location;
var id = l.substring(l.lastIndexOf("/") + 1);
$location.url("/realms/" + realm.id + "/roles/" + id);
Notifications.success("Created role");
});
} else {
Role.update({
realm : realm.id,
roleId : role.id
}, $scope.role, function() {
$scope.changed = false;
role = angular.copy($scope.role);
Notifications.success("Saved changes to role");
});
}
} else {
$scope.roleForm.showErrors = true;
}
};
$scope.reset = function() {
$scope.role = angular.copy(user);
$scope.changed = false;
$scope.roleForm.showErrors = false;
};
$scope.cancel = function() {
$location.url("/realms/" + realm.id + "/roles");
};
$scope.remove = function() {
Dialog.confirmDelete($scope.role.name, 'role', function() {
$scope.role.$remove({
realm : realm.id,
role : $scope.role.name
}, function() {
$location.url("/realms/" + realm.id + "/roles");
Notifications.success("Deleted role");
});
});
};
});
module.controller('RoleMappingCtrl', function($scope, realm, User, users, role, RoleMapping, Notifications) {
$scope.realm = realm;
$scope.realmId = realm.realm || realm.id;

View file

@ -72,6 +72,24 @@ module.factory('UserLoader', function(Loader, User, $route, $q) {
});
});
module.factory('RoleLoader', function(Loader, Role, $route, $q) {
return Loader.get(Role, function() {
return {
realm : $route.current.params.realm,
roleId : $route.current.params.role
}
});
});
module.factory('RoleListLoader', function(Loader, Role, $route, $q) {
return Loader.query(Role, function() {
return {
realm : $route.current.params.realm
}
});
});
module.factory('RoleMappingLoader', function(Loader, RoleMapping, $route, $q) {
var realm = $route.current.params.realm || $route.current.params.application;

View file

@ -146,4 +146,15 @@ module.factory('User', function($resource) {
method : 'PUT'
}
});
});
module.factory('Role', function($resource) {
return $resource('/auth-server/rest/saas/admin/realms/:realm/roles/:roleId', {
realm : '@realm',
roleId : '@roleId'
}, {
update : {
method : 'PUT'
}
});
});

View file

@ -3,23 +3,29 @@
<div class="container">
<div class="nav-collapse">
<nav id="global-nav">
<div data-ng-controller="RealmDropdownCtrl">
<ul class="nav pull-left" data-ng-show="auth.loggedIn">
<li class="dropdown"><a data-toggle="dropdown" class="dropdown-toggle" href="#"> Realms <i class="caret"></i></a>
<ul class="dropdown-menu">
<li ng-repeat="(id, name) in realmslist()"><a href="#/realms/{{id}}">{{name}}</a>
</li>
</ul>
</li>
</ul>
</div>
<ul class="nav">
<li class="divider-vertical-left" data-ng-class="path[0] == '' && 'active'"><a href="#">Home</a>
</li>
<li class="divider-vertical-left" data-ng-class="path[0] == 'applications' && 'active'"
data-ng-show="auth.loggedIn"><a href="#/applications">Applications</a></li>
<li class="divider-vertical-left" data-ng-class="path[0] == 'realms' && 'active'"
data-ng-show="auth.loggedIn"><a href="#/realms">Realms</a></li>
data-ng-show="auth.loggedIn"><a href="#/create/realm">New Realm</a></li>
</ul>
<ul class="nav pull-right" data-ng-hide="auth.loggedIn">
<li><a href="/auth-server/saas/saas-login.jsp">Login</a></li>
<li><a href="/ejs-identity/api/register/system">Register</a></li>
<li><a href="/auth-server/saas/saas-register.jsp">Register</a></li>
</ul>
<ul class="nav pull-right" data-ng-show="auth.loggedIn">
<li class="dropdown"><a data-toggle="dropdown" class="dropdown-toggle" href="#"><i
class="icon-user icon-gray"></i> {{auth.user.displayName}} <i class="caret"></i></a>
class="icon-user icon-gray"></i> Welcome: <b>{{auth.user.displayName}}</b> <i class="caret"></i></a>
<ul class="dropdown-menu">
<li><a href="/auth-server/rest/saas/logout" >Sign Out</a></li> <!--data-ng-click="auth.logout()" -->
<li><a href="/auth-server/rest/saas/logout">Sign Out</a></li>
</ul>
</li>
</ul>

View file

@ -4,10 +4,10 @@
<div id="actions-bg"></div>
<div id="container-right" class="span9">
<h1 data-ng-show="create"><span class="gray">New Realm</span></h1>
<h1 data-ng-show="createRealm"><span class="gray">New Realm</span></h1>
<h1 data-ng-hide="create">
<span class="gray">{{realm.realm}}</span> configuration
<h1 data-ng-hide="createRealm">
<span class="gray">{{realm.realm}}</span>
</h1>
<div data-ng-show="realmForm.showErrors && realmForm.$error.required" class="alert alert-error">Please fill
@ -82,47 +82,7 @@
</div>
</div>
</fieldset>
<fieldset>
<legend>Roles</legend>
<div class="control-group">
<label class="control-label">Roles</label>
<div class="controls">
<span class="label" style="margin-right: 1em;"
data-ng-repeat="r in (realm.roles|orderBy:'toString()')">{{r}} <button
data-ng-click="removeRole(r)"><i class="icon-remove icon-white"></i></button></span>
<div class="input-append">
<input class="input-small" type="text" data-ng-model="newRole" placeHolder="Role"
data-kc-enter="addRole()"/>
<button class="btn" type="button" data-ng-click="addRole()">Add</button>
</div>
</div>
</div>
<div class="control-group">
<label class="control-label">Initial Roles</label>
<div class="controls">
<span class="label" style="margin-right: 1em;"
data-ng-repeat="r in (realm.initialRoles|orderBy:'toString()')">{{r}} <button
data-ng-click="removeInitialRole(r)"><i class="icon-remove icon-white"></i></button></span>
<div class="input-append">
<select style="width: auto;" data-ng-model="newInitialRole"
data-ng-click="addInitialRole()">
<option data-ng-repeat="r in (realm.roles|remove:realm.initialRoles|orderBy:'toString()')"
value="{{r}}">{{r}}
</option>
</select>
</div>
</div>
</div>
</fieldset>
<div class="form-actions" data-ng-show="create">
<div class="form-actions" data-ng-show="createRealm">
<button type="submit" data-ng-click="save()" class="btn btn-primary" data-ng-show="changed">Save
</button>
<button type="submit" data-ng-click="cancel()" class="btn" data-ng-click="cancel()"
@ -130,7 +90,7 @@
</button>
</div>
<div class="form-actions" data-ng-show="!create">
<div class="form-actions" data-ng-show="!createRealm">
<button type="submit" data-ng-click="save()" class="btn btn-primary" data-ng-show="changed">Save
changes
</button>

View file

@ -1,21 +1,21 @@
<nav id="local-nav" data-ng-controller="RealmListCtrl">
<ul class="nav nav-list">
<li>
<div>
<span class="toggle">Realms</span>
</div>
<ul>
<li data-ng-repeat="r in realms" data-ng-class="path[1] == r.id && 'active'">
<a href=#/realms/{{r.id}}>{{r.name}}</a>
<ul class="sub-items" data-ng-show="path[1] == r.id">
<li data-ng-class="!path[2] && 'active'"><a href="#/realms/{{r.id}}">Configuration</a></li>
<li data-ng-class="path[2] == 'users' && 'active'"><a href="#/realms/{{r.id}}/users">Users</a>
</li>
<li data-ng-class="path[2] == 'roles' && 'active'"><a href="#/realms/{{r.id}}/roles">Role
mapping</a></li>
</ul>
</li>
</ul>
</li>
</ul>
</nav>
<div data-ng-hide="createRealm">
<nav id="local-nav">
<ul class="nav nav-list">
<li>
<div>
<span class="toggle">Realm: </span> {{realm.realm}}
</div>
<ul>
<li>
<ul class="sub-items">
<li data-ng-class="!path[2] && 'active'"><a href="#/realms/{{realm.id}}">Settings</a>
</li>
<li data-ng-class="path[2] == 'users' && 'active'"><a href="#/realms/{{realm.id}}/users">Users</a>
</li>
<li data-ng-class="path[2] == 'roles' && 'active'"><a href="#/realms/{{realm.id}}/roles">Roles</a></li>
</ul>
</li>
</ul>
</ul>
</nav>
</div>

View file

@ -0,0 +1,62 @@
<div id="wrapper" class="container">
<div class="row">
<aside class="span3" data-ng-include data-src="'partials/realm-menu.html'"></aside>
<div id="actions-bg"></div>
<div id="container-right" class="span9">
<h1 data-ng-show="create"><span class="gray">New Role</span></h1>
<h1 data-ng-hide="create">
<span class="gray">Role {{role.name}}</span>
</h1>
<div data-ng-show="roleForm.showErrors && roleForm.$error.required" class="alert alert-error">Please fill in
all required fields
</div>
<p class="subtitle subtitle-right"><span class="required">*</span> Required fields</p>
<form class="form-horizontal" name="roleForm" novalidate>
<fieldset>
<legend>Details</legend>
<div class="control-group">
<label class="control-label" for="name">Role name <span class="required">*</span></label>
<div class="controls">
<input type="text" class="input-xlarge" id="name" name="name" data-ng-model="role.name"
autofocus required data-ng-readonly="!create">
</div>
</div>
<div class="control-group">
<label class="control-label" for="description">Description </label>
<div class="controls">
<input type="text" class="input-xlarge" id="description" name="description" data-ng-model="role.description">
</div>
</div>
</fieldset>
<div class="form-actions" data-ng-show="create">
<button type="submit" data-ng-click="save()" class="btn btn-primary" data-ng-show="changed">Save
</button>
<button type="submit" data-ng-click="cancel()" class="btn" data-ng-click="cancel()"
data-ng-show="changed">Cancel
</button>
</div>
<div class="form-actions" data-ng-show="!create">
<button type="submit" data-ng-click="save()" class="btn btn-primary" data-ng-show="changed">Save
changes
</button>
<button type="submit" data-ng-click="reset()" class="btn" data-ng-show="changed">Clear changes
</button>
<a href="#/realms/{{realm.id}}/users" data-ng-hide="changed">View users &#187;</a>
<button type="submit" data-ng-click="remove()" class="btn btn-danger" data-ng-hide="changed">
Delete
</button>
</div>
</form>
</div>
<div id="container-right-bg"></div>
</div>
</div>

View file

@ -0,0 +1,28 @@
<div id="wrapper" class="container">
<div class="row">
<aside class="span3" data-ng-include data-src="'partials/realm-menu.html'"></aside>
<div id="actions-bg"></div>
<div id="container-right" class="span9">
<a class="btn btn-small pull-right" href="#/create/role/{{realm.id}}">Add Role</a>
<h1>
<span class="gray">{{realm.realm}}</span> roles
</h1>
<table class="table table-striped table-bordered">
<thead>
<tr>
<th>Name</th>
<th>Description</th>
</tr>
</thead>
<tr data-ng-repeat="role in roles">
<td><a href="#/realms/{{realm.id}}/roles/{{role.id}}">{{role.name}}</a></td>
<td>{{role.description}}</td>
</tr>
</table>
</div>
<div id="container-right-bg"></div>
</div>
</div>

View file

@ -98,4 +98,6 @@ public interface RealmModel {
boolean isRealmAdmin(UserModel agent);
void addRealmAdmin(UserModel agent);
RoleModel getRoleById(String id);
}

View file

@ -10,4 +10,8 @@ public interface RoleModel {
String getDescription();
void setDescription(String description);
String getId();
void setName(String name);
}

View file

@ -26,6 +26,7 @@ import org.picketlink.idm.credential.TOTPCredential;
import org.picketlink.idm.credential.TOTPCredentials;
import org.picketlink.idm.credential.UsernamePasswordCredentials;
import org.picketlink.idm.credential.X509CertificateCredentials;
import org.picketlink.idm.model.IdentityType;
import org.picketlink.idm.model.sample.Grant;
import org.picketlink.idm.model.sample.Role;
import org.picketlink.idm.model.sample.SampleModel;
@ -338,6 +339,15 @@ public class RealmAdapter implements RealmModel {
return new RoleAdapter(role, getIdm());
}
@Override
public RoleModel getRoleById(String id) {
IdentityQuery<Role> query = getIdm().createIdentityQuery(Role.class);
query.setParameter(IdentityType.ID, id);
List<Role> roles = query.getResultList();
if (roles.size() == 0) return null;
return new RoleAdapter(roles.get(0), getIdm());
}
@Override
public RoleAdapter addRole(String name) {
Role role = new Role(name);

View file

@ -24,11 +24,22 @@ public class RoleAdapter implements RoleModel {
return role;
}
@Override
public String getId() {
return role.getId();
}
@Override
public String getName() {
return role.getName();
}
@Override
public void setName(String name) {
role.setName(name);
idm.update(role);
}
@Override
public String getDescription() {
Attribute<Serializable> description = role.getAttribute("description");

View file

@ -2,8 +2,11 @@ package org.keycloak.services.resources.admin;
import org.jboss.resteasy.logging.Logger;
import org.keycloak.representations.idm.RealmRepresentation;
import org.keycloak.representations.idm.RoleRepresentation;
import org.keycloak.representations.idm.UserRepresentation;
import org.keycloak.services.managers.RealmManager;
import org.keycloak.services.models.RealmModel;
import org.keycloak.services.models.RoleModel;
import org.keycloak.services.models.UserModel;
import org.keycloak.services.resources.PublicRealmResource;
import org.keycloak.services.resources.Transaction;
@ -11,9 +14,11 @@ import org.keycloak.services.resources.Transaction;
import javax.ws.rs.Consumes;
import javax.ws.rs.ForbiddenException;
import javax.ws.rs.GET;
import javax.ws.rs.InternalServerErrorException;
import javax.ws.rs.NotAuthorizedException;
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;
@ -23,6 +28,7 @@ import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
import javax.ws.rs.core.UriBuilder;
import javax.ws.rs.core.UriInfo;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@ -44,19 +50,108 @@ public class RealmAdminResource {
@GET
@Produces("application/json")
public RealmRepresentation getRealm() {
RealmRepresentation rep = new RealmRepresentation();
rep.setId(realm.getId());
rep.setRealm(realm.getName());
rep.setEnabled(realm.isEnabled());
rep.setSslNotRequired(realm.isSslNotRequired());
rep.setCookieLoginAllowed(realm.isCookieLoginAllowed());
rep.setPublicKey(realm.getPublicKeyPem());
rep.setTokenLifespan(realm.getTokenLifespan());
rep.setAccessCodeLifespan(realm.getAccessCodeLifespan());
return rep;
return new Transaction() {
@Override
protected RealmRepresentation callImpl() {
RealmRepresentation rep = new RealmRepresentation();
rep.setId(realm.getId());
rep.setRealm(realm.getName());
rep.setEnabled(realm.isEnabled());
rep.setSslNotRequired(realm.isSslNotRequired());
rep.setCookieLoginAllowed(realm.isCookieLoginAllowed());
rep.setPublicKey(realm.getPublicKeyPem());
rep.setTokenLifespan(realm.getTokenLifespan());
rep.setAccessCodeLifespan(realm.getAccessCodeLifespan());
return rep;
}
}.call();
}
@Path("roles")
@GET
@Produces("application/json")
public List<RoleRepresentation> getRoles() {
return new Transaction() {
@Override
protected List<RoleRepresentation> callImpl() {
List<RoleModel> roleModels = realm.getRoles();
List<RoleRepresentation> roles = new ArrayList<RoleRepresentation>();
for (RoleModel roleModel : roleModels) {
RoleRepresentation role = new RoleRepresentation(roleModel.getName(), roleModel.getDescription());
roles.add(role);
}
return roles;
}
}.call();
}
@Path("roles/{id}")
@GET
@Produces("application/json")
public RoleRepresentation getRole(final @PathParam("id") String id) {
return new Transaction() {
@Override
protected RoleRepresentation callImpl() {
RoleModel roleModel = realm.getRoleById(id);
if (roleModel == null) {
throw new NotFoundException();
}
RoleRepresentation rep = new RoleRepresentation(roleModel.getName(), roleModel.getDescription());
rep.setId(roleModel.getId());
return rep;
}
}.call();
}
@Path("roles/{id}")
@PUT
@Consumes("application/json")
public void updateRole(final @PathParam("id") String id, final RoleRepresentation rep) {
new Transaction() {
@Override
protected void runImpl() {
RoleModel role = realm.getRoleById(id);
if (role == null) {
throw new NotFoundException();
}
role.setName(rep.getName());
role.setDescription(rep.getDescription());
}
}.run();
}
@Path("roles")
@POST
@Consumes("application/json")
public Response createRole(final @Context UriInfo uriInfo, final RoleRepresentation rep) {
return new Transaction() {
@Override
protected Response callImpl() {
if (realm.getRole(rep.getName()) != null) {
throw new InternalServerErrorException(); // todo appropriate status here.
}
RoleModel role = realm.addRole(rep.getName());
if (role == null) {
throw new NotFoundException();
}
role.setDescription(rep.getDescription());
return Response.created(uriInfo.getAbsolutePathBuilder().path(role.getId()).build()).build();
}
}.call();
}
@Path("users")
@GET
@Produces("application/json")
public List<UserRepresentation> getUsers() {
return null;
}

View file

@ -18,7 +18,9 @@ import javax.ws.rs.POST;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import javax.ws.rs.Produces;
import javax.ws.rs.core.CacheControl;
import javax.ws.rs.core.Context;
import javax.ws.rs.core.GenericEntity;
import javax.ws.rs.core.HttpHeaders;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
@ -41,18 +43,25 @@ public class RealmsAdminResource {
this.admin = admin;
}
public static final CacheControl noCache = new CacheControl();
static {
noCache.setNoCache(true);
}
@GET
@Produces("application/json")
public Map<String, String> getRealms() {
public Response getRealms() {
return new Transaction() {
@Override
protected Map<String, String> callImpl() {
protected Response callImpl() {
logger.info(("getRealms()"));
List<RealmModel> realms = session.getRealms(admin);
Map<String, String> map = new HashMap<String, String>();
for (RealmModel realm : realms) {
map.put(realm.getId(), realm.getName());
}
return map;
return Response.ok(new GenericEntity<Map<String, String>>(map){})
.cacheControl(noCache).build();
}
}.call();
}

View file

@ -123,6 +123,10 @@ public class AdapterTest {
RoleModel role = realmModel.getRole("user");
realmModel.grantRole(user, role);
Assert.assertTrue(realmModel.hasRole(user, role));
System.out.println("Role id: " + role.getId());
role = realmModel.getRoleById(role.getId());
Assert.assertNotNull(role);
Assert.assertEquals("user", role.getName());
}