keycloak-uncached
Changes
admin-ui/src/main/resources/META-INF/resources/admin/partials/application-installation.html 1(+1 -0)
admin-ui/src/main/resources/META-INF/resources/admin/partials/application-scope-mappings.html 1(+1 -0)
integration/undertow/src/main/java/org/keycloak/adapters/undertow/ServletAdminActionsHandler.java 30(+24 -6)
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 bfb76f7..bce292e 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
@@ -176,6 +176,21 @@ module.config([ '$routeProvider', function($routeProvider) {
},
controller : 'UserRoleMappingCtrl'
})
+ .when('/realms/:realm/users/:user/sessions', {
+ templateUrl : 'partials/user-sessions.html',
+ resolve : {
+ realm : function(RealmLoader) {
+ return RealmLoader();
+ },
+ user : function(UserLoader) {
+ return UserLoader();
+ },
+ stats : function(UserSessionStatsLoader) {
+ return UserSessionStatsLoader();
+ }
+ },
+ controller : 'UserSessionsCtrl'
+ })
.when('/realms/:realm/users', {
templateUrl : 'partials/user-list.html',
resolve : {
@@ -292,6 +307,21 @@ module.config([ '$routeProvider', function($routeProvider) {
},
controller : 'ApplicationClaimsCtrl'
})
+ .when('/realms/:realm/applications/:application/sessions', {
+ templateUrl : 'partials/application-sessions.html',
+ resolve : {
+ realm : function(RealmLoader) {
+ return RealmLoader();
+ },
+ application : function(ApplicationLoader) {
+ return ApplicationLoader();
+ },
+ stats : function(ApplicationSessionStatsLoader) {
+ return ApplicationSessionStatsLoader();
+ }
+ },
+ controller : 'ApplicationSessionsCtrl'
+ })
.when('/realms/:realm/applications/:application/credentials', {
templateUrl : 'partials/application-credentials.html',
resolve : {
@@ -540,6 +570,18 @@ module.config([ '$routeProvider', function($routeProvider) {
},
controller : 'RealmRevocationCtrl'
})
+ .when('/realms/:realm/sessions/realm', {
+ templateUrl : 'partials/session-realm.html',
+ resolve : {
+ realm : function(RealmLoader) {
+ return RealmLoader();
+ },
+ stats : function(RealmSessionStatsLoader) {
+ return RealmSessionStatsLoader();
+ }
+ },
+ controller : 'RealmSessionStatsCtrl'
+ })
.otherwise({
templateUrl : 'partials/notfound.html'
diff --git a/admin-ui/src/main/resources/META-INF/resources/admin/js/controllers/applications.js b/admin-ui/src/main/resources/META-INF/resources/admin/js/controllers/applications.js
index 27607e9..d7416a0 100755
--- a/admin-ui/src/main/resources/META-INF/resources/admin/js/controllers/applications.js
+++ b/admin-ui/src/main/resources/META-INF/resources/admin/js/controllers/applications.js
@@ -43,6 +43,45 @@ module.controller('ApplicationCredentialsCtrl', function($scope, $location, real
});
});
+module.controller('ApplicationSessionsCtrl', function($scope, realm, stats, application,
+ ApplicationLogoutUser,
+ ApplicationLogoutAll,
+ ApplicationSessionStats,
+ ApplicationSessionStatsWithUsers,
+ $location, Dialog, Notifications) {
+ $scope.realm = realm;
+ $scope.stats = stats;
+ $scope.users = {};
+ $scope.application = application;
+
+ $scope.toDate = function(val) {
+ return new Date(val);
+ };
+
+ $scope.loadUsers = function() {
+ ApplicationSessionStatsWithUsers.get({ realm : realm.realm, application: $scope.application.name }, function(updated) {
+ $scope.stats = updated;
+ $scope.users = updated.users;
+ })
+ };
+
+ $scope.logoutAll = function() {
+ ApplicationLogoutAll.save({realm : realm.realm, application: $scope.application.name}, function () {
+ Notifications.success('Logged out all users');
+ $scope.loadUsers();
+ });
+ };
+
+ $scope.logoutUser = function(user) {
+ console.log('Trying to logout user: ' + user);
+ ApplicationLogoutUser.save({realm : realm.realm, application: $scope.application.name, user: user}, function () {
+ Notifications.success('Logged out user' + user);
+ $scope.loadUsers();
+ });
+ };
+
+});
+
module.controller('ApplicationClaimsCtrl', function($scope, realm, application, claims,
ApplicationClaims,
$http, $location, Dialog, Notifications) {
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 cb0fa24..d2e4e68 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
@@ -690,6 +690,26 @@ module.controller('RealmKeysDetailCtrl', function($scope, Realm, realm, $http, $
};
});
+module.controller('RealmSessionStatsCtrl', function($scope, realm, stats, RealmSessionStats, RealmLogoutAll, Notifications) {
+ $scope.realm = realm;
+ $scope.stats = stats;
+
+ console.log(stats);
+
+ $scope.logoutAll = function() {
+ RealmLogoutAll.save({realm : realm.realm}, function () {
+ Notifications.success('Logged out all users');
+ RealmSessionStats.get({realm: realm.realm}, function(updated) {
+ Notifications.success('Logged out all users');
+ $scope.stats = updated;
+ })
+ });
+ };
+
+
+});
+
+
module.controller('RealmRevocationCtrl', function($scope, Realm, RealmPushRevocation, realm, $http, $location, Dialog, Notifications) {
$scope.realm = angular.copy(realm);
diff --git a/admin-ui/src/main/resources/META-INF/resources/admin/js/controllers/users.js b/admin-ui/src/main/resources/META-INF/resources/admin/js/controllers/users.js
index b0048a9..178e26b 100755
--- a/admin-ui/src/main/resources/META-INF/resources/admin/js/controllers/users.js
+++ b/admin-ui/src/main/resources/META-INF/resources/admin/js/controllers/users.js
@@ -118,6 +118,35 @@ module.controller('UserRoleMappingCtrl', function($scope, $http, realm, user, ro
});
+module.controller('UserSessionsCtrl', function($scope, realm, user, stats, UserLogout, ApplicationLogoutUser, UserSessionStats, Notifications) {
+ $scope.realm = realm;
+ $scope.user = user;
+ $scope.stats = stats;
+
+ $scope.logoutAll = function() {
+ UserLogout.save({realm : realm.realm, user: user.username}, function () {
+ Notifications.success('Logged out user in all applications');
+ UserSessionStats.get({realm: realm.realm, user: user.username}, function(updated) {
+ $scope.stats = updated;
+ })
+ });
+ };
+
+ $scope.logoutApplication = function(app) {
+ console.log('log user out of app: ' + app);
+ ApplicationLogoutUser.save({realm : realm.realm, application: app, user: user.username}, function () {
+ Notifications.success('Logged out user from application');
+ UserSessionStats.get({realm: realm.realm, user: user.username}, function(updated) {
+ $scope.stats = updated;
+ })
+ });
+ };
+
+
+
+});
+
+
module.controller('UserListCtrl', function($scope, realm, User) {
$scope.realm = realm;
$scope.searchQuery = function() {
diff --git a/admin-ui/src/main/resources/META-INF/resources/admin/js/loaders.js b/admin-ui/src/main/resources/META-INF/resources/admin/js/loaders.js
index d5b3917..84f8dbc 100755
--- a/admin-ui/src/main/resources/META-INF/resources/admin/js/loaders.js
+++ b/admin-ui/src/main/resources/META-INF/resources/admin/js/loaders.js
@@ -48,20 +48,37 @@ module.factory('RealmLoader', function(Loader, Realm, $route, $q) {
});
module.factory('UserListLoader', function(Loader, User, $route, $q) {
- return Loader.query(User, function() {
- return {
- realm : $route.current.params.realm
- }
- });
+ return Loader.query(User, function() {
+ return {
+ realm : $route.current.params.realm
+ }
+ });
+});
+
+module.factory('RealmSessionStatsLoader', function(Loader, RealmSessionStats, $route, $q) {
+ return Loader.get(RealmSessionStats, function() {
+ return {
+ realm : $route.current.params.realm
+ }
+ });
});
module.factory('UserLoader', function(Loader, User, $route, $q) {
- return Loader.get(User, function() {
- return {
- realm : $route.current.params.realm,
- userId : $route.current.params.user
- }
- });
+ return Loader.get(User, function() {
+ return {
+ realm : $route.current.params.realm,
+ userId : $route.current.params.user
+ }
+ });
+});
+
+module.factory('UserSessionStatsLoader', function(Loader, UserSessionStats, $route, $q) {
+ return Loader.get(UserSessionStats, function() {
+ return {
+ realm : $route.current.params.realm,
+ user : $route.current.params.user
+ }
+ });
});
module.factory('RoleLoader', function(Loader, Role, $route, $q) {
@@ -91,6 +108,15 @@ module.factory('ApplicationRoleLoader', function(Loader, ApplicationRole, $route
});
});
+module.factory('ApplicationSessionStatsLoader', function(Loader, ApplicationSessionStats, $route, $q) {
+ return Loader.get(ApplicationSessionStats, function() {
+ return {
+ realm : $route.current.params.realm,
+ application : $route.current.params.application
+ }
+ });
+});
+
module.factory('ApplicationClaimsLoader', function(Loader, ApplicationClaims, $route, $q) {
return Loader.get(ApplicationClaims, function() {
return {
diff --git a/admin-ui/src/main/resources/META-INF/resources/admin/js/services.js b/admin-ui/src/main/resources/META-INF/resources/admin/js/services.js
index 1397eb1..cb31b5e 100755
--- a/admin-ui/src/main/resources/META-INF/resources/admin/js/services.js
+++ b/admin-ui/src/main/resources/META-INF/resources/admin/js/services.js
@@ -158,9 +158,15 @@ module.factory('User', function($resource) {
});
module.factory('UserSessionStats', function($resource) {
- return $resource('/auth/rest/admin/realms/:realm/users/:userId/session-stats', {
+ return $resource('/auth/rest/admin/realms/:realm/users/:user/session-stats', {
realm : '@realm',
- userId : '@userId'
+ user : '@user'
+ });
+});
+module.factory('UserLogout', function($resource) {
+ return $resource('/auth/rest/admin/realms/:realm/users/:user/logout', {
+ realm : '@realm',
+ user : '@user'
});
});
@@ -489,6 +495,32 @@ module.factory('ApplicationSessionStats', function($resource) {
});
});
+module.factory('ApplicationSessionStatsWithUsers', function($resource) {
+ return $resource('/auth/rest/admin/realms/:realm/applications/:application/session-stats?users=true', {
+ realm : '@realm',
+ application : "@application"
+ });
+});
+
+module.factory('ApplicationLogoutAll', function($resource) {
+ return $resource('/auth/rest/admin/realms/:realm/applications/:application/logout-all', {
+ realm : '@realm',
+ application : "@application"
+ });
+});
+module.factory('ApplicationLogoutUser', function($resource) {
+ return $resource('/auth/rest/admin/realms/:realm/applications/:application/logout-user/:user', {
+ realm : '@realm',
+ application : "@application",
+ user : "@user"
+ });
+});
+module.factory('RealmLogoutAll', function($resource) {
+ return $resource('/auth/rest/admin/realms/:realm/logout-all', {
+ realm : '@realm'
+ });
+});
+
module.factory('ApplicationPushRevocation', function($resource) {
return $resource('/auth/rest/admin/realms/:realm/applications/:application/push-revocation', {
realm : '@realm',
diff --git a/admin-ui/src/main/resources/META-INF/resources/admin/partials/application-claims.html b/admin-ui/src/main/resources/META-INF/resources/admin/partials/application-claims.html
index 2b2e34b..f33e8cd 100755
--- a/admin-ui/src/main/resources/META-INF/resources/admin/partials/application-claims.html
+++ b/admin-ui/src/main/resources/META-INF/resources/admin/partials/application-claims.html
@@ -8,6 +8,7 @@
<li class="active"><a href="#/realms/{{realm.realm}}/applications/{{application.name}}/claims">Claims</a></li>
<li><a href="#/realms/{{realm.realm}}/applications/{{application.name}}/scope-mappings">Scope</a></li>
<li><a href="#/realms/{{realm.realm}}/applications/{{application.name}}/revocation">Revocation</a></li>
+ <li><a href="#/realms/{{realm.realm}}/applications/{{application.name}}/sessions">Sessions</a></li>
</ul>
<div id="content">
<ol class="breadcrumb" data-ng-hide="create">
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 e95bcc1..b3b9839 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
@@ -8,6 +8,7 @@
<li><a href="#/realms/{{realm.realm}}/applications/{{application.name}}/claims">Claims</a></li>
<li><a href="#/realms/{{realm.realm}}/applications/{{application.name}}/scope-mappings">Scope</a></li>
<li><a href="#/realms/{{realm.realm}}/applications/{{application.name}}/revocation">Revocation</a></li>
+ <li><a href="#/realms/{{realm.realm}}/applications/{{application.name}}/sessions">Sessions</a></li>
</ul>
<div id="content">
<ol class="breadcrumb" data-ng-hide="create">
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 d8b1dc4..dc834c3 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
@@ -8,6 +8,7 @@
<li><a href="#/realms/{{realm.realm}}/applications/{{application.name}}/claims">Claims</a></li>
<li><a href="#/realms/{{realm.realm}}/applications/{{application.name}}/scope-mappings">Scope</a></li>
<li><a href="#/realms/{{realm.realm}}/applications/{{application.name}}/revocation">Revocation</a></li>
+ <li><a href="#/realms/{{realm.realm}}/applications/{{application.name}}/sessions">Sessions</a></li>
</ul>
<div id="content">
<ol class="breadcrumb" data-ng-show="create">
diff --git a/admin-ui/src/main/resources/META-INF/resources/admin/partials/application-installation.html b/admin-ui/src/main/resources/META-INF/resources/admin/partials/application-installation.html
index 2caaa81..9c527d7 100755
--- a/admin-ui/src/main/resources/META-INF/resources/admin/partials/application-installation.html
+++ b/admin-ui/src/main/resources/META-INF/resources/admin/partials/application-installation.html
@@ -9,6 +9,7 @@
<li><a href="#/realms/{{realm.realm}}/applications/{{application.name}}/claims">Claims</a></li>
<li><a href="#/realms/{{realm.realm}}/applications/{{application.name}}/scope-mappings">Scope</a></li>
<li><a href="#/realms/{{realm.realm}}/applications/{{application.name}}/revocation">Revocation</a></li>
+ <li><a href="#/realms/{{realm.realm}}/applications/{{application.name}}/sessions">Sessions</a></li>
</ul>
<div class="top-nav" data-ng-show="create">
diff --git a/admin-ui/src/main/resources/META-INF/resources/admin/partials/application-revocation.html b/admin-ui/src/main/resources/META-INF/resources/admin/partials/application-revocation.html
index 8295782..6b7e951 100755
--- a/admin-ui/src/main/resources/META-INF/resources/admin/partials/application-revocation.html
+++ b/admin-ui/src/main/resources/META-INF/resources/admin/partials/application-revocation.html
@@ -8,6 +8,7 @@
<li><a href="#/realms/{{realm.realm}}/applications/{{application.name}}/claims">Claims</a></li>
<li><a href="#/realms/{{realm.realm}}/applications/{{application.name}}/scope-mappings">Scope</a></li>
<li class="active"><a href="#/realms/{{realm.realm}}/applications/{{application.name}}/revocation">Revocation</a></li>
+ <li><a href="#/realms/{{realm.realm}}/applications/{{application.name}}/sessions">Sessions</a></li>
</ul>
<div id="content">
<ol class="breadcrumb">
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 a7bae45..8e3d603 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
@@ -8,6 +8,7 @@
<li><a href="#/realms/{{realm.realm}}/applications/{{application.name}}/claims">Claims</a></li>
<li><a href="#/realms/{{realm.realm}}/applications/{{application.name}}/scope-mappings">Scope</a></li>
<li><a href="#/realms/{{realm.realm}}/applications/{{application.name}}/revocation">Revocation</a></li>
+ <li><a href="#/realms/{{realm.realm}}/applications/{{application.name}}/sessions">Sessions</a></li>
</ul>
<div id="content">
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 49329fe..77b4065 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
@@ -9,6 +9,7 @@
<li><a href="#/realms/{{realm.realm}}/applications/{{application.name}}/claims">Claims</a></li>
<li><a href="#/realms/{{realm.realm}}/applications/{{application.name}}/scope-mappings">Scope</a></li>
<li><a href="#/realms/{{realm.realm}}/applications/{{application.name}}/revocation">Revocation</a></li>
+ <li><a href="#/realms/{{realm.realm}}/applications/{{application.name}}/sessions">Sessions</a></li>
</ul>
<div id="content">
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 5be878c..ac6dd6f 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
@@ -9,6 +9,7 @@
<li><a href="#/realms/{{realm.realm}}/applications/{{application.name}}/claims">Claims</a></li>
<li class="active"><a href="#/realms/{{realm.realm}}/applications/{{application.name}}/scope-mappings">Scope</a></li>
<li><a href="#/realms/{{realm.realm}}/applications/{{application.name}}/revocation">Revocation</a></li>
+ <li><a href="#/realms/{{realm.realm}}/applications/{{application.name}}/sessions">Sessions</a></li>
</ul>
<div id="content">
diff --git a/admin-ui/src/main/resources/META-INF/resources/admin/partials/application-sessions.html b/admin-ui/src/main/resources/META-INF/resources/admin/partials/application-sessions.html
new file mode 100755
index 0000000..129647c
--- /dev/null
+++ b/admin-ui/src/main/resources/META-INF/resources/admin/partials/application-sessions.html
@@ -0,0 +1,60 @@
+<div class="bs-sidebar col-md-3 clearfix" data-ng-include data-src="'partials/realm-menu.html'"></div>
+<div id="content-area" class="col-md-9" role="main">
+ <ul class="nav nav-tabs nav-tabs-pf">
+ <li><a href="#/realms/{{realm.realm}}/applications/{{application.name}}">Settings</a></li>
+ <li><a href="#/realms/{{realm.realm}}/applications/{{application.name}}/credentials">Credentials</a></li>
+ <li><a href="#/realms/{{realm.realm}}/applications/{{application.name}}/installation">Installation</a></li>
+ <li><a href="#/realms/{{realm.realm}}/applications/{{application.name}}/roles">Roles</a></li>
+ <li><a href="#/realms/{{realm.realm}}/applications/{{application.name}}/claims">Claims</a></li>
+ <li><a href="#/realms/{{realm.realm}}/applications/{{application.name}}/scope-mappings">Scope</a></li>
+ <li><a href="#/realms/{{realm.realm}}/applications/{{application.name}}/revocation">Revocation</a></li>
+ <li class="active"><a href="#/realms/{{realm.realm}}/applications/{{application.name}}/sessions">Sessions</a></li>
+ </ul>
+ <div id="content">
+ <ol class="breadcrumb">
+ <li><a href="#/realms/{{realm.realm}}">{{application.name}}</a></li>
+ <li class="active">Application Sessions</li>
+ </ol>
+ <h2><span>{{application.name}}</span> Sessions</h2>
+ <form class="form-horizontal" name="sessionStats">
+ <fieldset class="border-top">
+ <div class="form-group">
+ <label class="col-sm-2 control-label" for="activeSessions">Active Sessions</label>
+ <div class="col-sm-4">
+ <input class="form-control" type="text" id="activeSessions" name="activeSessions" data-ng-model="stats.activeSessions" ng-disabled="true">
+ </div>
+ </div>
+ <div class="form-group">
+ <label class="col-sm-2 control-label" for="activeUsers">Active Users</label>
+ <div class="col-sm-4">
+ <input class="form-control" type="text" id="activeUsers" name="activeUsers" data-ng-model="stats.activeUsers" ng-disabled="true">
+ </div>
+ </div>
+ </fieldset>
+ </form>
+ <table class="table" data-ng-show="stats.activeSessions > 0">
+ <thead>
+ <tr>
+ <th class="kc-table-actions" colspan="3">
+ <div class="pull-right">
+ <a class="btn btn-primary" ng-click="logoutAll()">Logout All</a>
+ <a class="btn btn-primary" ng-click="loadUsers()">Show Users</a>
+ </div>
+ </th>
+ </tr>
+ <tr>
+ <th>User</th>
+ <th>Login Time</th>
+ <th></th>
+ </tr>
+ </thead>
+ <tbody>
+ <tr data-ng-repeat="(user, data) in users">
+ <td><a href="#/realms/{{realm.realm}}/users/{{user}}">{{user}}</a></td>
+ <td>{{data.whenLoggedIn | date:'medium'}}</td>
+ <td><a ng-click="logoutUser(user)">logout</a> </td>
+ </tr>
+ </tbody>
+ </table>
+ </div>
+</div>
\ No newline at end of file
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 c290d7a..63e34da 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
@@ -4,6 +4,7 @@
<li><a href="#/realms/{{realm.realm}}/users/{{user.username}}">Attributes</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>
+ <li><a href="#/realms/{{realm.realm}}/users/{{user.username}}/sessions">Sessions</a></li>
</ul>
<div id="content">
<ol class="breadcrumb">
diff --git a/admin-ui/src/main/resources/META-INF/resources/admin/partials/session-realm.html b/admin-ui/src/main/resources/META-INF/resources/admin/partials/session-realm.html
new file mode 100755
index 0000000..27a4e4e
--- /dev/null
+++ b/admin-ui/src/main/resources/META-INF/resources/admin/partials/session-realm.html
@@ -0,0 +1,37 @@
+<div class="bs-sidebar col-md-3 clearfix" data-ng-include data-src="'partials/realm-menu.html'"></div>
+<div id="content-area" class="col-md-9" role="main">
+ <ul class="nav nav-tabs nav-tabs-pf">
+ <li><a href="#/realms/{{realm.realm}}/sessions/revocation">Revocation</a></li>
+ <li class="active"><a href="#/realms/{{realm.realm}}/sessions/realm">Realm Sessions</a></li>
+ </ul>
+ <div id="content">
+ <ol class="breadcrumb">
+ <li><a href="#/realms/{{realm.realm}}">{{realm.realm}}</a></li>
+ <li class="active">Realm Sessions</li>
+ </ol>
+ <h2><span>{{realm.realm}}</span> Sessions</h2>
+ <table class="table">
+ <thead>
+ <tr>
+ <th class="kc-table-actions" colspan="3">
+ <div class="pull-right">
+ <a class="btn btn-primary" ng-click="logoutAll()">Logout All</a>
+ </div>
+ </th>
+ </tr>
+ <tr>
+ <th>Application</th>
+ <th>Active Sessions</th>
+ <th>Active Users</th>
+ </tr>
+ </thead>
+ <tbody>
+ <tr data-ng-repeat="(application, data) in stats">
+ <td><a href="#/realms/{{realm.realm}}/applications/{{application}}/sessions">{{application}}</a></td>
+ <td>{{data.activeSessions}}</td>
+ <td>{{data.activeUsers}}</td>
+ </tr>
+ </tbody>
+ </table>
+ </div>
+</div>
\ No newline at end of file
diff --git a/admin-ui/src/main/resources/META-INF/resources/admin/partials/session-revocation.html b/admin-ui/src/main/resources/META-INF/resources/admin/partials/session-revocation.html
index e8cf513..3ca24d0 100755
--- a/admin-ui/src/main/resources/META-INF/resources/admin/partials/session-revocation.html
+++ b/admin-ui/src/main/resources/META-INF/resources/admin/partials/session-revocation.html
@@ -2,6 +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 class="active"><a href="#/realms/{{realm.realm}}/sessions/revocation">Revocation</a></li>
+ <li><a href="#/realms/{{realm.realm}}/sessions/realm">Realm Sessions</a></li>
</ul>
<div id="content">
<ol class="breadcrumb">
diff --git a/admin-ui/src/main/resources/META-INF/resources/admin/partials/user-credentials.html b/admin-ui/src/main/resources/META-INF/resources/admin/partials/user-credentials.html
index 6d0fd70..38ca069 100755
--- a/admin-ui/src/main/resources/META-INF/resources/admin/partials/user-credentials.html
+++ b/admin-ui/src/main/resources/META-INF/resources/admin/partials/user-credentials.html
@@ -5,6 +5,7 @@
<li><a href="#/realms/{{realm.realm}}/users/{{user.username}}">Attributes</a></li>
<li class="active"><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>
+ <li><a href="#/realms/{{realm.realm}}/users/{{user.username}}/sessions">Sessions</a></li>
</ul>
<div id="content">
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 4ce093a..0894d18 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
@@ -5,6 +5,7 @@
<li class="active"><a href="#/realms/{{realm.realm}}/users/{{user.username}}">Attributes</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>
+ <li><a href="#/realms/{{realm.realm}}/users/{{user.username}}/sessions">Sessions</a></li>
</ul>
<div id="content">
diff --git a/admin-ui/src/main/resources/META-INF/resources/admin/partials/user-sessions.html b/admin-ui/src/main/resources/META-INF/resources/admin/partials/user-sessions.html
new file mode 100755
index 0000000..0011ad3
--- /dev/null
+++ b/admin-ui/src/main/resources/META-INF/resources/admin/partials/user-sessions.html
@@ -0,0 +1,41 @@
+<div class="bs-sidebar col-md-3 clearfix" data-ng-include data-src="'partials/realm-menu.html'"></div>
+<div id="content-area" class="col-md-9" role="main">
+ <ul class="nav nav-tabs nav-tabs-pf">
+ <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><a href="#/realms/{{realm.realm}}/users/{{user.username}}/role-mappings">Role Mappings</a></li>
+ <li class="active"><a href="#/realms/{{realm.realm}}/users/{{user.username}}/sessions">Sessions</a></li>
+ </ul>
+ <div id="content">
+ <ol class="breadcrumb">
+ <li><a href="#/realms/{{realm.realm}}">{{realm.realm}}</a></li>
+ <li><a href="#/realms/{{realm.realm}}/users">Users</a></li>
+ <li><a href="#/realms/{{realm.realm}}/users/{{user.username}}">{{user.username}}</a></li>
+ <li class="active">User Sessions</li>
+ </ol>
+ <h2><span>{{user.username}}</span> Sessions</h2>
+ <table class="table">
+ <thead>
+ <tr>
+ <th class="kc-table-actions" colspan="3">
+ <div class="pull-right">
+ <a class="btn btn-primary" ng-click="logoutAll()">Logout</a>
+ </div>
+ </th>
+ </tr>
+ <tr>
+ <th>Application</th>
+ <th>Login Time</th>
+ <th></th>
+ </tr>
+ </thead>
+ <tbody>
+ <tr data-ng-repeat="(application, data) in stats">
+ <td><a href="#/realms/{{realm.realm}}/applications/{{application}}/sessions">{{application}}</a></td>
+ <td>{{data.whenLoggedIn | date:'medium'}}</td>
+ <td><a ng-click="logoutApplication(application)">logout</a> </td>
+ </tr>
+ </tbody>
+ </table>
+ </div>
+</div>
\ No newline at end of file
diff --git a/core/src/main/java/org/keycloak/representations/adapters/action/AdminAction.java b/core/src/main/java/org/keycloak/representations/adapters/action/AdminAction.java
index 4340114..7fcc3a0 100755
--- a/core/src/main/java/org/keycloak/representations/adapters/action/AdminAction.java
+++ b/core/src/main/java/org/keycloak/representations/adapters/action/AdminAction.java
@@ -59,5 +59,13 @@ public abstract class AdminAction {
this.resource = resource;
}
+ public String getAction() {
+ return action;
+ }
+
+ public void setAction(String action) {
+ this.action = action;
+ }
+
public abstract boolean validate();
}
diff --git a/core/src/main/java/org/keycloak/representations/adapters/action/SessionStats.java b/core/src/main/java/org/keycloak/representations/adapters/action/SessionStats.java
index b272f72..84d08c1 100755
--- a/core/src/main/java/org/keycloak/representations/adapters/action/SessionStats.java
+++ b/core/src/main/java/org/keycloak/representations/adapters/action/SessionStats.java
@@ -1,6 +1,7 @@
package org.keycloak.representations.adapters.action;
import java.util.List;
+import java.util.Map;
import java.util.Set;
/**
@@ -10,7 +11,7 @@ import java.util.Set;
public class SessionStats {
protected int activeSessions;
protected int activeUsers;
- protected Set<String> users;
+ protected Map<String, UserStats> users;
public int getActiveSessions() {
return activeSessions;
@@ -28,11 +29,11 @@ public class SessionStats {
this.activeUsers = activeUsers;
}
- public Set<String> getUsers() {
+ public Map<String, UserStats> getUsers() {
return users;
}
- public void setUsers(Set<String> users) {
+ public void setUsers(Map<String, UserStats> users) {
this.users = users;
}
}
diff --git a/core-jaxrs/src/main/java/org/keycloak/SkeletonKeyContextResolver.java b/core-jaxrs/src/main/java/org/keycloak/SkeletonKeyContextResolver.java
index 805a843..01aafd6 100755
--- a/core-jaxrs/src/main/java/org/keycloak/SkeletonKeyContextResolver.java
+++ b/core-jaxrs/src/main/java/org/keycloak/SkeletonKeyContextResolver.java
@@ -18,11 +18,11 @@ public class SkeletonKeyContextResolver implements ContextResolver<ObjectMapper>
protected ObjectMapper mapper = new ObjectMapper();
public SkeletonKeyContextResolver() {
- mapper.setSerializationInclusion(JsonSerialize.Inclusion.NON_DEFAULT);
+ mapper.setSerializationInclusion(JsonSerialize.Inclusion.NON_NULL);
}
public SkeletonKeyContextResolver(boolean indent) {
- mapper.setSerializationInclusion(JsonSerialize.Inclusion.NON_DEFAULT);
+ mapper.setSerializationInclusion(JsonSerialize.Inclusion.NON_NULL);
if (indent) {
mapper.enable(SerializationConfig.Feature.INDENT_OUTPUT);
}
diff --git a/integration/undertow/src/main/java/org/keycloak/adapters/undertow/ServletAdminActionsHandler.java b/integration/undertow/src/main/java/org/keycloak/adapters/undertow/ServletAdminActionsHandler.java
index 64ea788..092b99b 100755
--- a/integration/undertow/src/main/java/org/keycloak/adapters/undertow/ServletAdminActionsHandler.java
+++ b/integration/undertow/src/main/java/org/keycloak/adapters/undertow/ServletAdminActionsHandler.java
@@ -24,6 +24,10 @@ import org.keycloak.util.StreamUtil;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
+import java.util.HashMap;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
/**
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
@@ -133,7 +137,7 @@ public class ServletAdminActionsHandler implements HttpHandler {
protected boolean validateAction(HttpServletResponse response, AdminAction action) throws IOException {
if (!action.validate()) {
- log.warn("admin request failed, not validated");
+ log.warn("admin request failed, not validated" + action.getAction());
response.sendError(HttpServletResponse.SC_BAD_REQUEST, "Not validated");
return false;
}
@@ -160,8 +164,15 @@ public class ServletAdminActionsHandler implements HttpHandler {
SessionStats stats = new SessionStats();
stats.setActiveSessions(userSessionManagement.getActiveSessions());
stats.setActiveUsers(userSessionManagement.getActiveUsers().size());
- if (action.isListUsers()) stats.setUsers(userSessionManagement.getActiveUsers());
+ if (action.isListUsers() && userSessionManagement.getActiveSessions() > 0) {
+ Map<String, UserStats> list = new HashMap<String, UserStats>();
+ for (String user : userSessionManagement.getActiveUsers()) {
+ list.put(user, getUserStats(user));
+ }
+ stats.setUsers(list);
+ }
response.setStatus(200);
+ response.setContentType("application/json");
JsonSerialization.writeValueToStream(response.getOutputStream(), stats);
return;
}
@@ -171,16 +182,23 @@ public class ServletAdminActionsHandler implements HttpHandler {
if (token == null) return;
UserStatsAction action = JsonSerialization.readValue(token.getContent(), UserStatsAction.class);
if (!validateAction(response, action)) return;
+ String user = action.getUser();
+ UserStats stats = getUserStats(user);
+ response.setStatus(200);
+ response.setContentType("application/json");
+ JsonSerialization.writeValueToStream(response.getOutputStream(), stats);
+ return;
+ }
+
+ protected UserStats getUserStats(String user) {
UserStats stats = new UserStats();
- Long loginTime = userSessionManagement.getUserLoginTime(action.getUser());
+ Long loginTime = userSessionManagement.getUserLoginTime(user);
if (loginTime != null) {
stats.setLoggedIn(true);
stats.setWhenLoggedIn(loginTime);
} else {
stats.setLoggedIn(false);
}
- response.setStatus(200);
- JsonSerialization.writeValueToStream(response.getOutputStream(), stats);
- return;
+ return stats;
}
}
diff --git a/integration/undertow/src/main/java/org/keycloak/adapters/undertow/UserSessionManagement.java b/integration/undertow/src/main/java/org/keycloak/adapters/undertow/UserSessionManagement.java
index 1ed9133..fcf502b 100755
--- a/integration/undertow/src/main/java/org/keycloak/adapters/undertow/UserSessionManagement.java
+++ b/integration/undertow/src/main/java/org/keycloak/adapters/undertow/UserSessionManagement.java
@@ -124,8 +124,8 @@ public class UserSessionManagement implements SessionListener {
synchronized (userSessionMap) {
UserSessions sessions = userSessionMap.get(username);
if (sessions == null) {
- UserSessions session = new UserSessions();
- userSessionMap.put(username, session);
+ sessions = new UserSessions();
+ userSessionMap.put(username, sessions);
}
sessions.getSessionIds().add(sessionId);
}
diff --git a/services/src/main/java/org/keycloak/services/managers/ResourceAdminManager.java b/services/src/main/java/org/keycloak/services/managers/ResourceAdminManager.java
index f0dafea..96a49f0 100755
--- a/services/src/main/java/org/keycloak/services/managers/ResourceAdminManager.java
+++ b/services/src/main/java/org/keycloak/services/managers/ResourceAdminManager.java
@@ -17,7 +17,9 @@ import org.keycloak.representations.adapters.action.UserStatsAction;
import javax.ws.rs.client.Entity;
import javax.ws.rs.core.Response;
+import java.util.HashMap;
import java.util.List;
+import java.util.Map;
/**
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
@@ -52,6 +54,18 @@ public class ResourceAdminManager {
return null;
}
SessionStats stats = response.readEntity(SessionStats.class);
+
+ // replace with username
+ if (users && stats.getUsers() != null) {
+ Map<String, UserStats> newUsers = new HashMap<String, UserStats>();
+ for (Map.Entry<String, UserStats> entry : stats.getUsers().entrySet()) {
+ UserModel user = realm.getUserById(entry.getKey());
+ if (user == null) continue;
+ newUsers.put(user.getLoginName(), entry.getValue());
+
+ }
+ stats.setUsers(newUsers);
+ }
return stats;
} else {
logger.info("no management url.");
@@ -94,7 +108,22 @@ public class ResourceAdminManager {
}
- public void singleLogOut(RealmModel realm, String user) {
+ public void logoutUser(RealmModel realm, String user) {
+ ResteasyClient client = new ResteasyClientBuilder()
+ .disableTrustManager() // todo fix this, should have a trust manager or a good default
+ .build();
+
+ try {
+ List<ApplicationModel> resources = realm.getApplications();
+ logger.debug("logging out {0} resources ", resources.size());
+ for (ApplicationModel resource : resources) {
+ logoutApplication(realm, resource, user, client);
+ }
+ } finally {
+ client.close();
+ }
+ }
+ public void logoutAll(RealmModel realm) {
ResteasyClient client = new ResteasyClientBuilder()
.disableTrustManager() // todo fix this, should have a trust manager or a good default
.build();
@@ -103,14 +132,28 @@ public class ResourceAdminManager {
List<ApplicationModel> resources = realm.getApplications();
logger.debug("logging out {0} resources ", resources.size());
for (ApplicationModel resource : resources) {
- logoutResource(realm, resource, user, client);
+ logoutApplication(realm, resource, null, client);
}
} finally {
client.close();
}
}
- protected boolean logoutResource(RealmModel realm, ApplicationModel resource, String user, ResteasyClient client) {
+ public void logoutApplication(RealmModel realm, ApplicationModel resource, String user) {
+ ResteasyClient client = new ResteasyClientBuilder()
+ .disableTrustManager() // todo fix this, should have a trust manager or a good default
+ .build();
+
+ try {
+ logoutApplication(realm, resource, user, client);
+ } finally {
+ client.close();
+ }
+
+ }
+
+
+ protected boolean logoutApplication(RealmModel realm, ApplicationModel resource, String user, ResteasyClient client) {
String managementUrl = resource.getManagementUrl();
if (managementUrl != null) {
LogoutAction adminAction = new LogoutAction(TokenIdGenerator.generateId(), (int)(System.currentTimeMillis() / 1000) + 30, resource.getName(), user);
@@ -122,7 +165,7 @@ public class ResourceAdminManager {
logger.info("logout success.");
return success;
} else {
- logger.info("logout failure.");
+ logger.info("Can't logout" + resource.getName() + " no mgmt url.");
return false;
}
}
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 d9c8122..085bbec 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
@@ -6,7 +6,9 @@ import org.keycloak.models.ApplicationModel;
import org.keycloak.models.KeycloakSession;
import org.keycloak.models.RealmModel;
import org.keycloak.models.UserCredentialModel;
+import org.keycloak.models.UserModel;
import org.keycloak.representations.adapters.action.SessionStats;
+import org.keycloak.representations.adapters.action.UserStats;
import org.keycloak.representations.idm.ApplicationRepresentation;
import org.keycloak.representations.idm.CredentialRepresentation;
import org.keycloak.services.managers.ApplicationManager;
@@ -18,12 +20,15 @@ import org.keycloak.util.JsonSerialization;
import javax.ws.rs.Consumes;
import javax.ws.rs.DELETE;
+import javax.ws.rs.DefaultValue;
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.QueryParam;
import javax.ws.rs.core.Application;
import javax.ws.rs.core.Context;
import javax.ws.rs.core.MediaType;
@@ -38,7 +43,7 @@ import java.util.Set;
* @version $Revision: 1 $
*/
public class ApplicationResource {
- protected static final Logger logger = Logger.getLogger(RealmAdminResource.class);
+ protected static final Logger logger = Logger.getLogger(ApplicationResource.class);
protected RealmModel realm;
private RealmAuth auth;
protected ApplicationModel application;
@@ -200,10 +205,45 @@ public class ApplicationResource {
@GET
@NoCache
@Produces(MediaType.APPLICATION_JSON)
- public SessionStats getSessionStats() {
- return new ResourceAdminManager().getSessionStats(realm, application, true);
+ public SessionStats getSessionStats(@QueryParam("users") @DefaultValue("false") boolean users) {
+ logger.info("session-stats");
+ auth.requireView();
+ if (application.getManagementUrl() == null || application.getManagementUrl().trim().equals("")) {
+ logger.info("sending empty stats");
+ SessionStats stats = new SessionStats();
+ if (users) stats.setUsers(new HashMap<String, UserStats>());
+ return stats;
+ }
+ SessionStats stats = new ResourceAdminManager().getSessionStats(realm, application, users);
+ if (stats == null) {
+ logger.info("app returned null stats");
+ } else {
+ logger.info("activeUsers: " + stats.getActiveUsers());
+ logger.info("activeSessions: " + stats.getActiveSessions());
+ }
+ return stats;
+ }
+
+ @Path("logout-all")
+ @POST
+ public void logoutAll() {
+ auth.requireManage();
+ new ResourceAdminManager().logoutApplication(realm, application, null);
}
+ @Path("logout-user/{username}")
+ @POST
+ public void logout(final @PathParam("username") String username) {
+ auth.requireManage();
+ UserModel user = realm.getUser(username);
+ if (user == null) {
+ throw new NotFoundException();
+ }
+ new ResourceAdminManager().logoutApplication(realm, application, user.getId());
+ }
+
+
+
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 8c56749..c9bf4f4 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
@@ -118,12 +118,20 @@ public class RealmAdminResource {
new ResourceAdminManager().pushRealmRevocationPolicy(realm);
}
+ @Path("logout-all")
+ @POST
+ public void logoutAll() {
+ auth.requireManage();
+ new ResourceAdminManager().logoutAll(realm);
+ }
+
@Path("session-stats")
@GET
@NoCache
@Produces(MediaType.APPLICATION_JSON)
public Map<String,SessionStats> getSessionStats() {
-
+ logger.info("session-stats");
+ auth.requireView();
Map<String, SessionStats> stats = new HashMap<String, SessionStats>();
for (ApplicationModel applicationModel : realm.getApplications()) {
if (applicationModel.getManagementUrl() == null) continue;
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 605f739..e3f9bbe 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
@@ -153,6 +153,7 @@ public class UsersResource {
@NoCache
@Produces(MediaType.APPLICATION_JSON)
public Map<String,UserStats> getSessionStats(final @PathParam("username") String username) {
+ logger.info("session-stats");
auth.requireView();
UserModel user = realm.getUser(username);
if (user == null) {
@@ -162,11 +163,23 @@ public class UsersResource {
for (ApplicationModel applicationModel : realm.getApplications()) {
if (applicationModel.getManagementUrl() == null) continue;
UserStats appStats = new ResourceAdminManager().getUserStats(realm, applicationModel, user);
- stats.put(applicationModel.getName(), appStats);
+ if (appStats.isLoggedIn()) stats.put(applicationModel.getName(), appStats);
}
return stats;
}
+ @Path("{username}/logout")
+ @POST
+ public void logout(final @PathParam("username") String username) {
+ auth.requireManage();
+ UserModel user = realm.getUser(username);
+ if (user == null) {
+ throw new NotFoundException();
+ }
+ new ResourceAdminManager().logoutUser(realm, user.getId());
+ }
+
+
@Path("{username}")
@DELETE
diff --git a/services/src/main/java/org/keycloak/services/resources/TokenService.java b/services/src/main/java/org/keycloak/services/resources/TokenService.java
index bfc1f20..0cae7c2 100755
--- a/services/src/main/java/org/keycloak/services/resources/TokenService.java
+++ b/services/src/main/java/org/keycloak/services/resources/TokenService.java
@@ -5,17 +5,13 @@ import org.jboss.resteasy.logging.Logger;
import org.jboss.resteasy.spi.HttpRequest;
import org.jboss.resteasy.spi.HttpResponse;
import org.keycloak.OAuthErrorException;
-import org.keycloak.jose.jws.JWSBuilder;
import org.keycloak.jose.jws.JWSInput;
import org.keycloak.jose.jws.crypto.RSAProvider;
-import org.keycloak.models.ApplicationModel;
import org.keycloak.models.ClientModel;
-import org.keycloak.models.Constants;
import org.keycloak.models.KeycloakSession;
import org.keycloak.models.KeycloakTransaction;
import org.keycloak.models.RealmModel;
import org.keycloak.models.RequiredCredentialModel;
-import org.keycloak.models.RoleModel;
import org.keycloak.models.UserCredentialModel;
import org.keycloak.models.UserModel;
import org.keycloak.representations.AccessToken;
@@ -54,7 +50,6 @@ import javax.ws.rs.core.SecurityContext;
import javax.ws.rs.core.UriBuilder;
import javax.ws.rs.core.UriInfo;
import javax.ws.rs.ext.Providers;
-import java.security.PrivateKey;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
@@ -563,7 +558,7 @@ public class TokenService {
logger.info("Logging out: {0}", user.getLoginName());
authManager.expireIdentityCookie(realm, uriInfo);
authManager.expireRememberMeCookie(realm, uriInfo);
- resourceAdminManager.singleLogOut(realm, user.getId());
+ resourceAdminManager.logoutUser(realm, user.getId());
} else {
logger.info("No user logged in for logout");
}