Merge pull request #371 from patriot1burke/master

keycloak.js admin login
This commit is contained in:
Bill Burke 2014-05-08 20:08:52 -04:00
commit 5568c8dc7d
33 changed files with 676 additions and 1188 deletions

View file

@ -61,12 +61,12 @@
<filter-mapping>
<filter-name>Keycloak Session Management</filter-name>
<url-pattern>/rest/*</url-pattern>
<url-pattern>/*</url-pattern>
</filter-mapping>
<filter-mapping>
<filter-name>Keycloak Client Connection Filter</filter-name>
<url-pattern>/rest/*</url-pattern>
<url-pattern>/*</url-pattern>
</filter-mapping>
<servlet-mapping>
@ -109,7 +109,7 @@
<security-constraint>
<web-resource-collection>
<web-resource-name>deny</web-resource-name>
<url-pattern>/rest/customers/*</url-pattern>
<url-pattern>/customers/*</url-pattern>
</web-resource-collection>
<auth-constraint/>
</security-constraint>

View file

@ -9,9 +9,9 @@
</head>
<body bgcolor="#E3F6CE">
<%
String logoutUri = KeycloakUriBuilder.fromUri("http://localhost:8080/app-bundle/rest/realms/demo/tokens/logout")
String logoutUri = KeycloakUriBuilder.fromUri("http://localhost:8080/app-bundle/realms/demo/tokens/logout")
.queryParam("redirect_uri", "http://localhost:8080/app-bundle").build().toString();
String acctUri = "http://localhost:8080/app-bundle/rest/realms/demo/account?referrer=customer-portal";
String acctUri = "http://localhost:8080/app-bundle/realms/demo/account?referrer=customer-portal";
IDToken idToken = CustomerDatabaseClient.getIDToken(request);
%>
<p><a href="<%=logoutUri%>">logout</a> | <a

View file

@ -22,6 +22,7 @@
<script src="lib/angular/select2.js" type="text/javascript"></script>
<script src="lib/fileupload/angular-file-upload.min.js"></script>
<script src="js/keycloak.js" type="text/javascript"></script>
<script src="js/app.js" type="text/javascript"></script>
<script src="js/controllers/realm.js" type="text/javascript"></script>
<script src="js/controllers/applications.js" type="text/javascript"></script>
@ -76,12 +77,12 @@
$.idleTimeout('#idletimeout', '#idletimeout a', {
idleAfter: 300,
pollingInterval: 60,
keepAliveURL: authUrl + '/rest/admin/keepalive',
// keepAliveURL: authUrl + '/admin/keepalive', would need to change this path
serverResponseEquals: '',
failedRequests: 1,
onTimeout: function(){
$(this).slideUp();
window.location = authUrl + '/rest/admin/logout';
logout();
},
onIdle: function(){
$(this).slideDown(); // show the warning bar

View file

@ -1,28 +1,68 @@
'use strict';
var indexUrl = window.location.href;
var consoleBaseUrl = window.location.href;
consoleBaseUrl = consoleBaseUrl.substring(0, consoleBaseUrl.indexOf("/console"));
consoleBaseUrl = consoleBaseUrl + "/console";
var configUrl = consoleBaseUrl + "/config";
var logoutUrl = consoleBaseUrl + "/logout";
var auth = {};
var logout = function(){
console.log('*** LOGOUT');
auth.loggedIn = false;
auth.authz = null;
auth.user = null;
window.location = logoutUrl;
};
var authUrl = window.location.href;
authUrl = authUrl.substring(0, authUrl.indexOf('/admin/'));
var module = angular.module('keycloak', [ 'keycloak.services', 'keycloak.loaders', 'ui.bootstrap', 'ui.select2', 'angularFileUpload' ]);
var resourceRequests = 0;
var loadingTimer = -1;
angular.element(document).ready(function ($http) {
$http.get(authUrl + '/rest/admin/whoami').success(function(data) {
var auth = {};
auth.user = data;
auth.loggedIn = true;
var keycloakAuth = new Keycloak(configUrl);
var auth = {};
auth.loggedIn = false;
keycloakAuth.init('login-required').success(function () {
auth.loggedIn = true;
auth.authz = keycloakAuth;
module.factory('Auth', function() {
return auth;
});
angular.bootstrap(document, ["keycloak"]);
}).error(function() {
var path = window.location.hash && window.location.hash.substring(1) || '/';
window.location = authUrl + '/rest/admin/login?path=' + path;
});
}).error(function () {
window.location.reload();
});
});
module.factory('authInterceptor', function($q, Auth) {
return {
request: function (config) {
var deferred = $q.defer();
if (Auth.authz.token) {
Auth.authz.updateToken(5).success(function() {
config.headers = config.headers || {};
config.headers.Authorization = 'Bearer ' + Auth.authz.token;
deferred.resolve(config);
}).error(function() {
deferred.reject('Failed to refresh token');
});
}
return deferred.promise;
}
};
});
module.config([ '$routeProvider', function($routeProvider) {
@ -675,7 +715,10 @@ module.config([ '$routeProvider', function($routeProvider) {
},
controller : 'RealmSessionStatsCtrl'
})
.when('/logout', {
templateUrl : 'partials/home.html',
controller : 'LogoutCtrl'
})
.otherwise({
templateUrl : 'partials/notfound.html'
});
@ -697,19 +740,19 @@ module.config(function($httpProvider) {
$httpProvider.defaults.transformRequest.push(spinnerFunction);
$httpProvider.responseInterceptors.push('spinnerInterceptor');
$httpProvider.interceptors.push('authInterceptor');
});
module.factory('errorInterceptor', function($q, $window, $rootScope, $location, Auth, Notifications) {
module.factory('errorInterceptor', function($q, $window, $rootScope, $location,Notifications) {
return function(promise) {
return promise.then(function(response) {
return response;
}, function(response) {
if (response.status == 401) {
console.log('session timeout?');
Auth.loggedIn = false;
window.location = authUrl + '/rest/admin/login?path=' + $location.path();
} else if (response.status == 403) {
logout();
} else if (response.status == 403) {
Notifications.error("Forbidden");
} else if (response.status == 404) {
Notifications.error("Not found");

View file

@ -361,7 +361,7 @@ module.controller('ApplicationScopeMappingCtrl', function($scope, $http, realm,
});
$scope.addRealmRole = function() {
$http.post(authUrl + '/rest/admin/realms/' + realm.realm + '/applications/' + application.name + '/scope-mappings/realm',
$http.post(authUrl + '/admin/realms/' + realm.realm + '/applications/' + application.name + '/scope-mappings/realm',
$scope.selectedRealmRoles).success(function() {
for (var i = 0; i < $scope.selectedRealmRoles.length; i++) {
var role = $scope.selectedRealmRoles[i];
@ -376,7 +376,7 @@ module.controller('ApplicationScopeMappingCtrl', function($scope, $http, realm,
};
$scope.deleteRealmRole = function() {
$http.delete(authUrl + '/rest/admin/realms/' + realm.realm + '/applications/' + application.name + '/scope-mappings/realm',
$http.delete(authUrl + '/admin/realms/' + realm.realm + '/applications/' + application.name + '/scope-mappings/realm',
{data : $scope.selectedRealmMappings, headers : {"content-type" : "application/json"}}).success(function() {
for (var i = 0; i < $scope.selectedRealmMappings.length; i++) {
var role = $scope.selectedRealmMappings[i];
@ -391,7 +391,7 @@ module.controller('ApplicationScopeMappingCtrl', function($scope, $http, realm,
};
$scope.addApplicationRole = function() {
$http.post(authUrl + '/rest/admin/realms/' + realm.realm + '/applications/' + application.name + '/scope-mappings/applications/' + $scope.targetApp.name,
$http.post(authUrl + '/admin/realms/' + realm.realm + '/applications/' + application.name + '/scope-mappings/applications/' + $scope.targetApp.name,
$scope.selectedApplicationRoles).success(function() {
for (var i = 0; i < $scope.selectedApplicationRoles.length; i++) {
var role = $scope.selectedApplicationRoles[i];
@ -406,7 +406,7 @@ module.controller('ApplicationScopeMappingCtrl', function($scope, $http, realm,
};
$scope.deleteApplicationRole = function() {
$http.delete(authUrl + '/rest/admin/realms/' + realm.realm + '/applications/' + application.name + '/scope-mappings/applications/' + $scope.targetApp.name,
$http.delete(authUrl + '/admin/realms/' + realm.realm + '/applications/' + application.name + '/scope-mappings/applications/' + $scope.targetApp.name,
{data : $scope.selectedApplicationMappings, headers : {"content-type" : "application/json"}}).success(function() {
for (var i = 0; i < $scope.selectedApplicationMappings.length; i++) {
var role = $scope.selectedApplicationMappings[i];

View file

@ -211,7 +211,7 @@ module.controller('OAuthClientScopeMappingCtrl', function($scope, $http, realm,
});
$scope.addRealmRole = function() {
$http.post(authUrl + '/rest/admin/realms/' + realm.realm + '/oauth-clients/' + oauth.id + '/scope-mappings/realm',
$http.post(authUrl + '/admin/realms/' + realm.realm + '/oauth-clients/' + oauth.id + '/scope-mappings/realm',
$scope.selectedRealmRoles).success(function() {
for (var i = 0; i < $scope.selectedRealmRoles.length; i++) {
var role = $scope.selectedRealmRoles[i];
@ -226,7 +226,7 @@ module.controller('OAuthClientScopeMappingCtrl', function($scope, $http, realm,
};
$scope.deleteRealmRole = function() {
$http.delete(authUrl + '/rest/admin/realms/' + realm.realm + '/oauth-clients/' + oauth.id + '/scope-mappings/realm',
$http.delete(authUrl + '/admin/realms/' + realm.realm + '/oauth-clients/' + oauth.id + '/scope-mappings/realm',
{data : $scope.selectedRealmMappings, headers : {"content-type" : "application/json"}}).success(function() {
for (var i = 0; i < $scope.selectedRealmMappings.length; i++) {
var role = $scope.selectedRealmMappings[i];
@ -241,7 +241,7 @@ module.controller('OAuthClientScopeMappingCtrl', function($scope, $http, realm,
};
$scope.addApplicationRole = function() {
$http.post(authUrl + '/rest/admin/realms/' + realm.realm + '/oauth-clients/' + oauth.id + '/scope-mappings/applications/' + $scope.targetApp.name,
$http.post(authUrl + '/admin/realms/' + realm.realm + '/oauth-clients/' + oauth.id + '/scope-mappings/applications/' + $scope.targetApp.name,
$scope.selectedApplicationRoles).success(function() {
for (var i = 0; i < $scope.selectedApplicationRoles.length; i++) {
var role = $scope.selectedApplicationRoles[i];
@ -256,7 +256,7 @@ module.controller('OAuthClientScopeMappingCtrl', function($scope, $http, realm,
};
$scope.deleteApplicationRole = function() {
$http.delete(authUrl + '/rest/admin/realms/' + realm.realm + '/oauth-clients/' + oauth.id + '/scope-mappings/applications/' + $scope.targetApp.name,
$http.delete(authUrl + '/admin/realms/' + realm.realm + '/oauth-clients/' + oauth.id + '/scope-mappings/applications/' + $scope.targetApp.name,
{data : $scope.selectedApplicationMappings, headers : {"content-type" : "application/json"}}).success(function() {
for (var i = 0; i < $scope.selectedApplicationMappings.length; i++) {
var role = $scope.selectedApplicationMappings[i];

View file

@ -1,12 +1,13 @@
module.controller('GlobalCtrl', function($scope, $http, Auth, Current, $location, Notifications) {
module.controller('GlobalCtrl', function($scope, $http, Auth, WhoAmI, Current, $location, Notifications) {
$scope.addMessage = function() {
Notifications.success("test");
};
$scope.authUrl = authUrl;
$scope.logout = logout;
$scope.auth = Auth;
$http.get(authUrl + '/rest/admin/whoami').success(function(data, status) {
WhoAmI.get(function(data) {
Auth.user = data;
Auth.loggedIn = true;
@ -68,10 +69,7 @@ module.controller('GlobalCtrl', function($scope, $http, Auth, Current, $location
return getAccess('manage-audit');
}
}
})
.error(function(data, status) {
Auth.loggedIn = false;
});
});
$scope.$watch(function() {
return $location.path();
@ -123,7 +121,7 @@ module.controller('RealmDropdownCtrl', function($scope, Realm, Current, Auth, $l
}
});
module.controller('RealmCreateCtrl', function($scope, Current, Realm, $upload, $http, $location, Dialog, Notifications, Auth) {
module.controller('RealmCreateCtrl', function($scope, Current, Realm, $upload, $http, WhoAmI, $location, Dialog, Notifications, Auth) {
console.log('RealmCreateCtrl');
Current.realm = null;
@ -150,7 +148,7 @@ module.controller('RealmCreateCtrl', function($scope, Current, Realm, $upload, $
for (var i = 0; i < $scope.files.length; i++) {
var $file = $scope.files[i];
$scope.upload = $upload.upload({
url: authUrl + '/rest/admin/realms', //upload.php script, node.js route, or servlet url
url: authUrl + '/admin/realms', //upload.php script, node.js route, or servlet url
// method: POST or PUT,
// headers: {'headerKey': 'headerValue'}, withCredential: true,
data: {myObj: ""},
@ -165,7 +163,8 @@ module.controller('RealmCreateCtrl', function($scope, Current, Realm, $upload, $
Realm.query(function(data) {
Current.realms = data;
$http.get(authUrl + '/rest/admin/whoami').success(function(user) {
WhoAmI.get(function(user) {
Auth.user = user;
Notifications.success("The realm has been uploaded.");
@ -202,7 +201,7 @@ module.controller('RealmCreateCtrl', function($scope, Current, Realm, $upload, $
Realm.query(function(data) {
Current.realms = data;
$http.get(authUrl + '/rest/admin/whoami').success(function(user) {
$http.get(authUrl + '/admin/whoami').success(function(user) {
Auth.user = user;
$location.url("/realms/" + realmCopy.realm);
@ -573,7 +572,7 @@ module.controller('RealmSocialCtrl', function($scope, realm, Realm, serverInfo,
var oldCopy = angular.copy($scope.realm);
$scope.changed = false;
$scope.callbackUrl = $location.absUrl().replace(/\/admin.*/, "/rest/social/callback");
$scope.callbackUrl = $location.absUrl().replace(/\/admin.*/, "/social/callback");
$scope.addProvider = function(pId) {
if (!$scope.realm.socialProviders) {

View file

@ -28,7 +28,7 @@ module.controller('UserRoleMappingCtrl', function($scope, $http, realm, user, ro
});
$scope.addRealmRole = function() {
$http.post(authUrl + '/rest/admin/realms/' + realm.realm + '/users/' + user.username + '/role-mappings/realm',
$http.post(authUrl + '/admin/realms/' + realm.realm + '/users/' + user.username + '/role-mappings/realm',
$scope.selectedRealmRoles).success(function() {
for (var i = 0; i < $scope.selectedRealmRoles.length; i++) {
var role = $scope.selectedRealmRoles[i];
@ -43,7 +43,7 @@ module.controller('UserRoleMappingCtrl', function($scope, $http, realm, user, ro
};
$scope.deleteRealmRole = function() {
$http.delete(authUrl + '/rest/admin/realms/' + realm.realm + '/users/' + user.username + '/role-mappings/realm',
$http.delete(authUrl + '/admin/realms/' + realm.realm + '/users/' + user.username + '/role-mappings/realm',
{data : $scope.selectedRealmMappings, headers : {"content-type" : "application/json"}}).success(function() {
for (var i = 0; i < $scope.selectedRealmMappings.length; i++) {
var role = $scope.selectedRealmMappings[i];
@ -58,7 +58,7 @@ module.controller('UserRoleMappingCtrl', function($scope, $http, realm, user, ro
};
$scope.addApplicationRole = function() {
$http.post(authUrl + '/rest/admin/realms/' + realm.realm + '/users/' + user.username + '/role-mappings/applications/' + $scope.application.name,
$http.post(authUrl + '/admin/realms/' + realm.realm + '/users/' + user.username + '/role-mappings/applications/' + $scope.application.name,
$scope.selectedApplicationRoles).success(function() {
for (var i = 0; i < $scope.selectedApplicationRoles.length; i++) {
var role = $scope.selectedApplicationRoles[i];
@ -73,7 +73,7 @@ module.controller('UserRoleMappingCtrl', function($scope, $http, realm, user, ro
};
$scope.deleteApplicationRole = function() {
$http.delete(authUrl + '/rest/admin/realms/' + realm.realm + '/users/' + user.username + '/role-mappings/applications/' + $scope.application.name,
$http.delete(authUrl + '/admin/realms/' + realm.realm + '/users/' + user.username + '/role-mappings/applications/' + $scope.application.name,
{data : $scope.selectedApplicationMappings, headers : {"content-type" : "application/json"}}).success(function() {
for (var i = 0; i < $scope.selectedApplicationMappings.length; i++) {
var role = $scope.selectedApplicationMappings[i];

View file

@ -127,8 +127,12 @@ module.factory('Notifications', function($rootScope, $timeout) {
return notifications;
});
module.factory('WhoAmI', function($resource) {
return $resource(consoleBaseUrl + '/whoami');
});
module.factory('Realm', function($resource) {
return $resource(authUrl + '/rest/admin/realms/:id', {
return $resource(authUrl + '/admin/realms/:id', {
id : '@realm'
}, {
update : {
@ -143,7 +147,7 @@ module.factory('Realm', function($resource) {
});
module.factory('RealmAudit', function($resource) {
return $resource(authUrl + '/rest/admin/realms/:id/audit', {
return $resource(authUrl + '/admin/realms/:id/audit', {
id : '@realm'
}, {
update : {
@ -153,17 +157,17 @@ module.factory('RealmAudit', function($resource) {
});
module.factory('RealmAuditEvents', function($resource) {
return $resource(authUrl + '/rest/admin/realms/:id/audit/events', {
return $resource(authUrl + '/admin/realms/:id/audit/events', {
id : '@realm'
});
});
module.factory('ServerInfo', function($resource) {
return $resource(authUrl + '/rest/admin/serverinfo');
return $resource(authUrl + '/admin/serverinfo');
});
module.factory('User', function($resource) {
return $resource(authUrl + '/rest/admin/realms/:realm/users/:userId', {
return $resource(authUrl + '/admin/realms/:realm/users/:userId', {
realm : '@realm',
userId : '@userId'
}, {
@ -174,13 +178,13 @@ module.factory('User', function($resource) {
});
module.factory('UserSessionStats', function($resource) {
return $resource(authUrl + '/rest/admin/realms/:realm/users/:user/session-stats', {
return $resource(authUrl + '/admin/realms/:realm/users/:user/session-stats', {
realm : '@realm',
user : '@user'
});
});
module.factory('UserLogout', function($resource) {
return $resource(authUrl + '/rest/admin/realms/:realm/users/:user/logout', {
return $resource(authUrl + '/admin/realms/:realm/users/:user/logout', {
realm : '@realm',
user : '@user'
});
@ -195,7 +199,7 @@ module.factory('UserSocialLinks', function($resource) {
module.factory('UserCredentials', function($resource) {
var credentials = {};
credentials.resetPassword = $resource(authUrl + '/rest/admin/realms/:realm/users/:userId/reset-password', {
credentials.resetPassword = $resource(authUrl + '/admin/realms/:realm/users/:userId/reset-password', {
realm : '@realm',
userId : '@userId'
}, {
@ -204,7 +208,7 @@ module.factory('UserCredentials', function($resource) {
}
}).update;
credentials.removeTotp = $resource(authUrl + '/rest/admin/realms/:realm/users/:userId/remove-totp', {
credentials.removeTotp = $resource(authUrl + '/admin/realms/:realm/users/:userId/remove-totp', {
realm : '@realm',
userId : '@userId'
}, {
@ -213,7 +217,7 @@ module.factory('UserCredentials', function($resource) {
}
}).update;
credentials.resetPasswordEmail = $resource(authUrl + '/rest/admin/realms/:realm/users/:userId/reset-password-email', {
credentials.resetPasswordEmail = $resource(authUrl + '/admin/realms/:realm/users/:userId/reset-password-email', {
realm : '@realm',
userId : '@userId'
}, {
@ -226,14 +230,14 @@ module.factory('UserCredentials', function($resource) {
});
module.factory('RealmRoleMapping', function($resource) {
return $resource(authUrl + '/rest/admin/realms/:realm/users/:userId/role-mappings/realm', {
return $resource(authUrl + '/admin/realms/:realm/users/:userId/role-mappings/realm', {
realm : '@realm',
userId : '@userId'
});
});
module.factory('ApplicationRoleMapping', function($resource) {
return $resource(authUrl + '/rest/admin/realms/:realm/users/:userId/role-mappings/applications/:application', {
return $resource(authUrl + '/admin/realms/:realm/users/:userId/role-mappings/applications/:application', {
realm : '@realm',
userId : '@userId',
application : "@application"
@ -241,14 +245,14 @@ module.factory('ApplicationRoleMapping', function($resource) {
});
module.factory('ApplicationRealmScopeMapping', function($resource) {
return $resource(authUrl + '/rest/admin/realms/:realm/applications/:application/scope-mappings/realm', {
return $resource(authUrl + '/admin/realms/:realm/applications/:application/scope-mappings/realm', {
realm : '@realm',
application : '@application'
});
});
module.factory('ApplicationApplicationScopeMapping', function($resource) {
return $resource(authUrl + '/rest/admin/realms/:realm/applications/:application/scope-mappings/applications/:targetApp', {
return $resource(authUrl + '/admin/realms/:realm/applications/:application/scope-mappings/applications/:targetApp', {
realm : '@realm',
application : '@application',
targetApp : '@targetApp'
@ -258,33 +262,33 @@ module.factory('ApplicationApplicationScopeMapping', function($resource) {
module.factory('RealmRoles', function($resource) {
return $resource(authUrl + '/rest/admin/realms/:realm/roles', {
return $resource(authUrl + '/admin/realms/:realm/roles', {
realm : '@realm'
});
});
module.factory('RoleRealmComposites', function($resource) {
return $resource(authUrl + '/rest/admin/realms/:realm/roles-by-id/:role/composites/realm', {
return $resource(authUrl + '/admin/realms/:realm/roles-by-id/:role/composites/realm', {
realm : '@realm',
role : '@role'
});
});
module.factory('RealmPushRevocation', function($resource) {
return $resource(authUrl + '/rest/admin/realms/:realm/push-revocation', {
return $resource(authUrl + '/admin/realms/:realm/push-revocation', {
realm : '@realm'
});
});
module.factory('RealmSessionStats', function($resource) {
return $resource(authUrl + '/rest/admin/realms/:realm/session-stats', {
return $resource(authUrl + '/admin/realms/:realm/session-stats', {
realm : '@realm'
});
});
module.factory('RoleApplicationComposites', function($resource) {
return $resource(authUrl + '/rest/admin/realms/:realm/roles-by-id/:role/composites/applications/:application', {
return $resource(authUrl + '/admin/realms/:realm/roles-by-id/:role/composites/applications/:application', {
realm : '@realm',
role : '@role',
application : "@application"
@ -367,7 +371,7 @@ function roleControl($scope, realm, role, roles, applications,
$scope.addRealmRole = function() {
$scope.compositeSwitchDisabled=true;
$http.post(authUrl + '/rest/admin/realms/' + realm.realm + '/roles-by-id/' + role.id + '/composites',
$http.post(authUrl + '/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];
@ -383,7 +387,7 @@ function roleControl($scope, realm, role, roles, applications,
$scope.deleteRealmRole = function() {
$scope.compositeSwitchDisabled=true;
$http.delete(authUrl + '/rest/admin/realms/' + realm.realm + '/roles-by-id/' + role.id + '/composites',
$http.delete(authUrl + '/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];
@ -399,7 +403,7 @@ function roleControl($scope, realm, role, roles, applications,
$scope.addApplicationRole = function() {
$scope.compositeSwitchDisabled=true;
$http.post(authUrl + '/rest/admin/realms/' + realm.realm + '/roles-by-id/' + role.id + '/composites',
$http.post(authUrl + '/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];
@ -415,7 +419,7 @@ function roleControl($scope, realm, role, roles, applications,
$scope.deleteApplicationRole = function() {
$scope.compositeSwitchDisabled=true;
$http.delete(authUrl + '/rest/admin/realms/' + realm.realm + '/roles-by-id/' + role.id + '/composites',
$http.delete(authUrl + '/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];
@ -466,7 +470,7 @@ function roleControl($scope, realm, role, roles, applications,
module.factory('Role', function($resource) {
return $resource(authUrl + '/rest/admin/realms/:realm/roles/:role', {
return $resource(authUrl + '/admin/realms/:realm/roles/:role', {
realm : '@realm',
role : '@role'
}, {
@ -477,7 +481,7 @@ module.factory('Role', function($resource) {
});
module.factory('RoleById', function($resource) {
return $resource(authUrl + '/rest/admin/realms/:realm/roles-by-id/:role', {
return $resource(authUrl + '/admin/realms/:realm/roles-by-id/:role', {
realm : '@realm',
role : '@role'
}, {
@ -488,7 +492,7 @@ module.factory('RoleById', function($resource) {
});
module.factory('ApplicationRole', function($resource) {
return $resource(authUrl + '/rest/admin/realms/:realm/applications/:application/roles/:role', {
return $resource(authUrl + '/admin/realms/:realm/applications/:application/roles/:role', {
realm : '@realm',
application : "@application",
role : '@role'
@ -500,7 +504,7 @@ module.factory('ApplicationRole', function($resource) {
});
module.factory('ApplicationClaims', function($resource) {
return $resource(authUrl + '/rest/admin/realms/:realm/applications/:application/claims', {
return $resource(authUrl + '/admin/realms/:realm/applications/:application/claims', {
realm : '@realm',
application : "@application"
}, {
@ -511,40 +515,40 @@ module.factory('ApplicationClaims', function($resource) {
});
module.factory('ApplicationSessionStats', function($resource) {
return $resource(authUrl + '/rest/admin/realms/:realm/applications/:application/session-stats', {
return $resource(authUrl + '/admin/realms/:realm/applications/:application/session-stats', {
realm : '@realm',
application : "@application"
});
});
module.factory('ApplicationSessionStatsWithUsers', function($resource) {
return $resource(authUrl + '/rest/admin/realms/:realm/applications/:application/session-stats?users=true', {
return $resource(authUrl + '/admin/realms/:realm/applications/:application/session-stats?users=true', {
realm : '@realm',
application : "@application"
});
});
module.factory('ApplicationLogoutAll', function($resource) {
return $resource(authUrl + '/rest/admin/realms/:realm/applications/:application/logout-all', {
return $resource(authUrl + '/admin/realms/:realm/applications/:application/logout-all', {
realm : '@realm',
application : "@application"
});
});
module.factory('ApplicationLogoutUser', function($resource) {
return $resource(authUrl + '/rest/admin/realms/:realm/applications/:application/logout-user/:user', {
return $resource(authUrl + '/admin/realms/:realm/applications/:application/logout-user/:user', {
realm : '@realm',
application : "@application",
user : "@user"
});
});
module.factory('RealmLogoutAll', function($resource) {
return $resource(authUrl + '/rest/admin/realms/:realm/logout-all', {
return $resource(authUrl + '/admin/realms/:realm/logout-all', {
realm : '@realm'
});
});
module.factory('ApplicationPushRevocation', function($resource) {
return $resource(authUrl + '/rest/admin/realms/:realm/applications/:application/push-revocation', {
return $resource(authUrl + '/admin/realms/:realm/applications/:application/push-revocation', {
realm : '@realm',
application : "@application"
});
@ -553,7 +557,7 @@ module.factory('ApplicationPushRevocation', function($resource) {
module.factory('Application', function($resource) {
return $resource(authUrl + '/rest/admin/realms/:realm/applications/:application', {
return $resource(authUrl + '/admin/realms/:realm/applications/:application', {
realm : '@realm',
application : '@application'
}, {
@ -564,7 +568,7 @@ module.factory('Application', function($resource) {
});
module.factory('ApplicationInstallation', function($resource) {
var url = authUrl + '/rest/admin/realms/:realm/applications/:application/installation/json';
var url = authUrl + '/admin/realms/:realm/applications/:application/installation/json';
return {
url : function(parameters)
{
@ -573,7 +577,7 @@ module.factory('ApplicationInstallation', function($resource) {
}
});
module.factory('ApplicationInstallationJBoss', function($resource) {
var url = authUrl + '/rest/admin/realms/:realm/applications/:application/installation/jboss';
var url = authUrl + '/admin/realms/:realm/applications/:application/installation/jboss';
return {
url : function(parameters)
{
@ -583,7 +587,7 @@ module.factory('ApplicationInstallationJBoss', function($resource) {
});
module.factory('ApplicationCredentials', function($resource) {
return $resource(authUrl + '/rest/admin/realms/:realm/applications/:application/client-secret', {
return $resource(authUrl + '/admin/realms/:realm/applications/:application/client-secret', {
realm : '@realm',
application : '@application'
}, {
@ -594,7 +598,7 @@ module.factory('ApplicationCredentials', function($resource) {
});
module.factory('ApplicationOrigins', function($resource) {
return $resource(authUrl + '/rest/admin/realms/:realm/applications/:application/allowed-origins', {
return $resource(authUrl + '/admin/realms/:realm/applications/:application/allowed-origins', {
realm : '@realm',
application : '@application'
}, {
@ -606,7 +610,7 @@ module.factory('ApplicationOrigins', function($resource) {
});
module.factory('OAuthClient', function($resource) {
return $resource(authUrl + '/rest/admin/realms/:realm/oauth-clients/:id', {
return $resource(authUrl + '/admin/realms/:realm/oauth-clients/:id', {
realm : '@realm',
id : '@id'
}, {
@ -617,7 +621,7 @@ module.factory('OAuthClient', function($resource) {
});
module.factory('OAuthClientClaims', function($resource) {
return $resource(authUrl + '/rest/admin/realms/:realm/oauth-clients/:oauth/claims', {
return $resource(authUrl + '/admin/realms/:realm/oauth-clients/:oauth/claims', {
realm : '@realm',
oauth : "@oauth"
}, {
@ -629,7 +633,7 @@ module.factory('OAuthClientClaims', function($resource) {
module.factory('OAuthClientCredentials', function($resource) {
return $resource(authUrl + '/rest/admin/realms/:realm/oauth-clients/:oauth/client-secret', {
return $resource(authUrl + '/admin/realms/:realm/oauth-clients/:oauth/client-secret', {
realm : '@realm',
oauth : '@oauth'
}, {
@ -641,14 +645,14 @@ module.factory('OAuthClientCredentials', function($resource) {
});
module.factory('OAuthClientRealmScopeMapping', function($resource) {
return $resource(authUrl + '/rest/admin/realms/:realm/oauth-clients/:oauth/scope-mappings/realm', {
return $resource(authUrl + '/admin/realms/:realm/oauth-clients/:oauth/scope-mappings/realm', {
realm : '@realm',
oauth : '@oauth'
});
});
module.factory('OAuthClientApplicationScopeMapping', function($resource) {
return $resource(authUrl + '/rest/admin/realms/:realm/oauth-clients/:oauth/scope-mappings/applications/:targetApp', {
return $resource(authUrl + '/admin/realms/:realm/oauth-clients/:oauth/scope-mappings/applications/:targetApp', {
realm : '@realm',
oauth : '@oauth',
targetApp : '@targetApp'
@ -656,8 +660,8 @@ module.factory('OAuthClientApplicationScopeMapping', function($resource) {
});
module.factory('OAuthClientInstallation', function($resource) {
var url = authUrl + '/rest/admin/realms/:realm/oauth-clients/:oauth/installation';
var resource = $resource(authUrl + '/rest/admin/realms/:realm/oauth-clients/:oauth/installation', {
var url = authUrl + '/admin/realms/:realm/oauth-clients/:oauth/installation';
var resource = $resource(authUrl + '/admin/realms/:realm/oauth-clients/:oauth/installation', {
realm : '@realm',
oauth : '@oauth'
}, {

View file

@ -19,8 +19,8 @@
{{auth.user.displayName}}<b class="caret"></b>
</a>
<ul class="dropdown-menu">
<li><a href="{{authUrl}}/rest/realms/{{auth.user.realm}}/account?referrer=admin-console">Manage Account</a></li>
<li class="separator"><a href="{{authUrl}}/rest/admin/logout">Sign Out</a></li>
<li><a href="{{authUrl}}/realms/{{auth.user.realm}}/account?referrer=security-admin-console">Manage Account</a></li>
<li class="separator"><a href="" ng-click="logout()">Sign Out</a></li>
</ul>
</li>
</ul>

View file

@ -5,7 +5,7 @@ package org.keycloak.models;
* @version $Revision: 1 $
*/
public interface Constants {
String ADMIN_CONSOLE_APPLICATION = "admin-console";
String ADMIN_CONSOLE_APPLICATION = "security-admin-console";
String ACCOUNT_MANAGEMENT_APP = "account";

View file

@ -16,6 +16,7 @@ import org.jboss.resteasy.spi.BadRequestException;
import javax.ws.rs.core.Cookie;
import javax.ws.rs.core.HttpHeaders;
import javax.ws.rs.core.NewCookie;
import javax.ws.rs.core.UriInfo;
import java.net.URI;
/**
@ -25,151 +26,32 @@ import java.net.URI;
public class AppAuthManager extends AuthenticationManager {
protected static Logger logger = Logger.getLogger(AppAuthManager.class);
private String cookieName;
private TokenManager tokenManager;
public AppAuthManager(ProviderSession providerSession, String cookieName, TokenManager tokenManager) {
public AppAuthManager(ProviderSession providerSession) {
super(providerSession);
this.cookieName = cookieName;
this.tokenManager = tokenManager;
}
public NewCookie createCookie(RealmModel realm, ClientModel client, String code, URI uri) {
JWSInput input = new JWSInput(code);
boolean verifiedCode = false;
try {
verifiedCode = RSAProvider.verify(input, realm.getPublicKey());
} catch (Exception ignored) {
logger.debug("Failed to verify signature", ignored);
}
if (!verifiedCode) {
logger.debug("unverified access code");
throw new BadRequestException("unverified access code");
}
String key = input.readContentAsString();
AccessCodeEntry accessCode = tokenManager.pullAccessCode(key);
if (accessCode == null) {
logger.debug("bad access code");
throw new BadRequestException("bad access code");
}
if (accessCode.isExpired()) {
logger.debug("access code expired");
throw new BadRequestException("access code expired");
}
if (!accessCode.getToken().isActive()) {
logger.debug("access token expired");
throw new BadRequestException("access token expired");
}
if (!accessCode.getRealm().getId().equals(realm.getId())) {
logger.debug("bad realm");
throw new BadRequestException("bad realm");
}
if (!client.getClientId().equals(accessCode.getClient().getClientId())) {
logger.debug("bad client");
throw new BadRequestException("bad client");
}
return createLoginCookie(realm, accessCode.getUser(), accessCode.getClient(), cookieName, uri.getRawPath(), false);
public UserModel authenticateRequest(RealmModel realm, UriInfo uriInfo, HttpHeaders headers) {
UserModel user = authenticateIdentityCookie(realm, uriInfo, headers);
if (user != null) return user;
return authenticateBearerToken(realm, uriInfo, headers);
}
public NewCookie createRefreshCookie(RealmModel realm, UserModel user, ClientModel client, URI uri) {
return createLoginCookie(realm, user, client, cookieName, uri.getRawPath(), false);
}
public void expireCookie(URI uri) {
expireCookie(cookieName, uri.getRawPath());
}
public Auth authenticateCookie(RealmModel realm, HttpHeaders headers) {
return authenticateCookie(realm, headers, cookieName, true);
}
public Auth authenticate(RealmModel realm, HttpHeaders headers) {
Auth auth = authenticateCookie(realm, headers);
if (auth != null) return auth;
return authenticateBearerToken(realm, headers);
}
private Auth authenticateCookie(RealmModel realm, HttpHeaders headers, String cookieName, boolean checkActive) {
logger.info("authenticateCookie");
Cookie cookie = headers.getCookies().get(cookieName);
if (cookie == null) {
logger.infov("authenticateCookie could not find cookie: {0}", cookieName);
return null;
}
String tokenString = cookie.getValue();
try {
AccessToken token = RSATokenVerifier.verifyToken(tokenString, realm.getPublicKey(), realm.getName(), checkActive);
logger.info("token verified");
if (checkActive && !token.isActive()) {
logger.info("cookie expired");
expireCookie(cookie.getName(), cookie.getPath());
return null;
}
UserModel user = realm.getUserById(token.getSubject());
if (user == null || !user.isEnabled()) {
logger.info("Unknown user in cookie");
expireCookie(cookie.getName(), cookie.getPath());
return null;
}
ClientModel client = null;
if (token.getIssuedFor() != null) {
client = realm.findClient(token.getIssuedFor());
if (client == null || !client.isEnabled()) {
logger.info("Unknown client in cookie");
expireCookie(cookie.getName(), cookie.getPath());
return null;
}
}
return new Auth(realm, user, client);
} catch (VerificationException e) {
logger.info("Failed to verify cookie", e);
expireCookie(cookie.getName(), cookie.getPath());
}
return null;
}
private Auth authenticateBearerToken(RealmModel realm, HttpHeaders headers) {
String tokenString;
public String extractAuthorizationHeaderToken(HttpHeaders headers) {
String tokenString = null;
String authHeader = headers.getRequestHeaders().getFirst(HttpHeaders.AUTHORIZATION);
if (authHeader == null) {
return null;
} else {
if (authHeader != null) {
String[] split = authHeader.trim().split("\\s+");
if (split == null || split.length != 2) throw new UnauthorizedException("Bearer");
if (!split[0].equalsIgnoreCase("Bearer")) throw new UnauthorizedException("Bearer");
tokenString = split[1];
}
return tokenString;
}
try {
AccessToken token = RSATokenVerifier.verifyToken(tokenString, realm.getPublicKey(), realm.getName());
if (!token.isActive()) {
throw new UnauthorizedException("token_expired");
}
UserModel user = realm.getUserById(token.getSubject());
if (user == null || !user.isEnabled()) {
throw new UnauthorizedException("invalid_user");
}
ClientModel client = null;
if (token.getIssuedFor() != null) {
client = realm.findClient(token.getIssuedFor());
if (client == null || !client.isEnabled()) {
throw new UnauthorizedException("invalid_user");
}
}
return new Auth(token, user, client);
} catch (VerificationException e) {
logger.error("Failed to verify token", e);
throw new UnauthorizedException("invalid_token");
}
public UserModel authenticateBearerToken(RealmModel realm, UriInfo uriInfo, HttpHeaders headers) {
String tokenString = extractAuthorizationHeaderToken(headers);
if (tokenString == null) return null;
return verifyIdentityToken(realm, uriInfo, true, tokenString);
}
}

View file

@ -66,6 +66,8 @@ public class ApplianceBootstrap {
ApplicationModel adminConsole = new ApplicationManager(manager).createApplication(realm, Constants.ADMIN_CONSOLE_APPLICATION);
adminConsole.setBaseUrl(contextPath + "/admin/index.html");
adminConsole.setEnabled(true);
adminConsole.setPublicClient(true);
adminConsole.addRedirectUri(contextPath + "/admin/" + realm.getName() + "/console/*");
realm.setAuditListeners(Collections.singleton("jboss-logging"));

View file

@ -155,6 +155,14 @@ public class AuthenticationManager {
}
String tokenString = cookie.getValue();
UserModel user = verifyIdentityToken(realm, uriInfo, checkActive, tokenString);
if (user == null) {
expireIdentityCookie(realm, uriInfo);
}
return user;
}
protected UserModel verifyIdentityToken(RealmModel realm, UriInfo uriInfo, boolean checkActive, String tokenString) {
try {
AccessToken token = RSATokenVerifier.verifyToken(tokenString, realm.getPublicKey(), realm.getName(), checkActive);
logger.info("identity token verified");
@ -173,22 +181,19 @@ public class AuthenticationManager {
UserModel user = realm.getUserById(token.getSubject());
if (user == null || !user.isEnabled() ) {
logger.info("Unknown user in identity cookie");
expireIdentityCookie(realm, uriInfo);
logger.info("Unknown user in identity token");
return null;
}
if (token.getIssuedAt() < user.getNotBefore()) {
logger.info("Stale cookie");
expireIdentityCookie(realm, uriInfo);
return null;
}
return user;
} catch (VerificationException e) {
logger.info("Failed to verify identity cookie", e);
expireCookie(cookie.getName(), cookie.getPath());
logger.info("Failed to verify identity token", e);
}
return null;
}

View file

@ -138,7 +138,7 @@ public class AccountService {
this.realm = realm;
this.application = application;
this.audit = audit;
this.authManager = new AppAuthManager(providers, KEYCLOAK_ACCOUNT_IDENTITY_COOKIE, tokenManager);
this.authManager = new AppAuthManager(providers);
this.socialRequestManager = socialRequestManager;
}
@ -148,8 +148,9 @@ public class AccountService {
account = AccountLoader.load().createAccount(uriInfo).setRealm(realm);
boolean passwordUpdateSupported = false;
auth = authManager.authenticate(realm, headers);
if (auth != null) {
UserModel user = authManager.authenticateRequest(realm, uriInfo, headers);
if (user != null) {
auth = new Auth(realm, user, application);
account.setUser(auth.getUser());
AuthenticationLinkModel authLinkModel = realm.getAuthenticationLink(auth.getUser());
@ -487,20 +488,19 @@ public class AccountService {
redirectUri = redirectUri.resolve("?referrer=" + referrer);
}
NewCookie cookie = authManager.createCookie(realm, application, code, Urls.accountBase(uriInfo.getBaseUri()).build(realm.getName()));
return Response.status(302).cookie(cookie).location(redirectUri).build();
return Response.status(302).location(redirectUri).build();
} finally {
authManager.expireCookie(Urls.accountBase(uriInfo.getBaseUri()).build(realm.getName()));
}
}
@Path("logout")
@GET
public Response logout() {
URI baseUri = Urls.accountBase(uriInfo.getBaseUri()).build(realm.getName());
authManager.expireIdentityCookie(realm, uriInfo);
authManager.expireCookie(baseUri);
return Response.status(302).location(baseUri).build();
URI redirect = Urls.accountBase(uriInfo.getBaseUri()).build(realm.getName());
return Response.status(302).location(
TokenService.logoutUrl(uriInfo).queryParam("redirect_uri", redirect.toString()).build(realm.getName())
).build();
}
private Response login(String path) {

View file

@ -1,62 +0,0 @@
package org.keycloak.services.resources;
import org.jboss.logging.Logger;
import org.keycloak.models.Config;
import org.keycloak.freemarker.Theme;
import org.keycloak.freemarker.ThemeLoader;
import javax.activation.FileTypeMap;
import javax.activation.MimetypesFileTypeMap;
import javax.ws.rs.GET;
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.io.InputStream;
import java.net.URI;
import java.net.URISyntaxException;
/**
* @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
*/
@Path("/admin")
public class AdminResource {
private static final Logger logger = Logger.getLogger(AdminResource.class);
private static FileTypeMap mimeTypes = MimetypesFileTypeMap.getDefaultFileTypeMap();
@Context
private UriInfo uriInfo;
@GET
public Response getResource() throws URISyntaxException {
String requestUri = uriInfo.getRequestUri().toString();
if (!requestUri.endsWith("/")) {
return Response.seeOther(new URI(requestUri + "/")).build();
} else {
return getResource("index.html");
}
}
@GET
@Path("/{path:.*}")
public Response getResource(@PathParam("path") String path) {
try {
Theme theme = ThemeLoader.createTheme(Config.getThemeAdmin(), Theme.Type.ADMIN);
InputStream resource = theme.getResourceAsStream(path);
if (resource != null) {
String contentType = mimeTypes.getContentType(path);
return Response.ok(resource).type(contentType).build();
} else {
return Response.status(Response.Status.NOT_FOUND).build();
}
} catch (Exception e) {
logger.warn("Failed to get theme resource", e);
return Response.serverError().build();
}
}
}

View file

@ -27,7 +27,7 @@ import org.keycloak.services.managers.BruteForceProtector;
import org.keycloak.services.managers.RealmManager;
import org.keycloak.services.managers.SocialRequestManager;
import org.keycloak.services.managers.TokenManager;
import org.keycloak.services.resources.admin.AdminService;
import org.keycloak.services.resources.admin.AdminRoot;
import org.keycloak.models.utils.ModelProviderUtils;
import org.keycloak.timer.TimerProvider;
import org.keycloak.timer.TimerProviderFactory;
@ -82,11 +82,10 @@ public class KeycloakApplication extends Application {
SocialRequestManager socialRequestManager = new SocialRequestManager();
singletons.add(new RealmsResource(tokenManager, socialRequestManager));
singletons.add(new AdminService(tokenManager));
singletons.add(new SocialResource(tokenManager, socialRequestManager));
singletons.add(new AdminRoot(tokenManager));
classes.add(SkeletonKeyContextResolver.class);
classes.add(QRCodeResource.class);
classes.add(AdminResource.class);
classes.add(ThemeResource.class);
classes.add(JsResource.class);
classes.add(WelcomeResource.class);

View file

@ -4,7 +4,7 @@ import org.jboss.logging.Logger;
import org.jboss.resteasy.annotations.cache.NoCache;
import org.keycloak.models.RealmModel;
import org.keycloak.representations.idm.PublishedRealmRepresentation;
import org.keycloak.services.resources.admin.AdminService;
import org.keycloak.services.resources.admin.AdminRoot;
import javax.ws.rs.GET;
import javax.ws.rs.PathParam;
@ -38,9 +38,9 @@ public class PublicRealmResource {
public static PublishedRealmRepresentation realmRep(RealmModel realm, UriInfo uriInfo) {
PublishedRealmRepresentation rep = new PublishedRealmRepresentation();
rep.setRealm(realm.getName());
rep.setTokenServiceUrl(TokenService.tokenServiceBaseUrl(uriInfo).build(realm.getId()).toString());
rep.setAccountServiceUrl(AccountService.accountServiceBaseUrl(uriInfo).build(realm.getId()).toString());
rep.setAdminApiUrl(AdminService.adminApiUrl(uriInfo).build(realm.getId()).toString());
rep.setTokenServiceUrl(TokenService.tokenServiceBaseUrl(uriInfo).build(realm.getName()).toString());
rep.setAccountServiceUrl(AccountService.accountServiceBaseUrl(uriInfo).build(realm.getName()).toString());
rep.setAdminApiUrl(uriInfo.getBaseUriBuilder().path(AdminRoot.class).build().toString());
rep.setPublicKeyPem(realm.getPublicKeyPem());
rep.setNotBefore(realm.getNotBefore());
return rep;

View file

@ -74,7 +74,6 @@ public class RealmsResource {
public static UriBuilder accountUrl(UriBuilder base) {
return base.path(RealmsResource.class).path(RealmsResource.class, "getAccountService");
}
@Path("{realm}/tokens")
public TokenService getTokenService(final @PathParam("realm") String name) {
RealmManager realmManager = new RealmManager(session);
@ -124,13 +123,6 @@ public class RealmsResource {
return realmResource;
}
@Path("{realm}/admin/resources")
public AdminResource adminResource() {
AdminResource adminResource = new AdminResource();
ResteasyProviderFactory.getInstance().injectProperties(adminResource);
return adminResource;
}

View file

@ -76,7 +76,7 @@ import java.util.Map.Entry;
/**
* @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
*/
@Path("/rest/social")
@Path("/social")
public class SocialResource {
protected static Logger logger = Logger.getLogger(SocialResource.class);

View file

@ -15,7 +15,7 @@ import java.io.InputStream;
/**
* @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
*/
@Path("/rest/theme")
@Path("/theme")
public class ThemeResource {
private static final Logger logger = Logger.getLogger(ThemeResource.class);

View file

@ -0,0 +1,285 @@
package org.keycloak.services.resources.admin;
import org.codehaus.jackson.annotate.JsonProperty;
import org.jboss.logging.Logger;
import org.jboss.resteasy.annotations.cache.NoCache;
import org.jboss.resteasy.spi.HttpRequest;
import org.jboss.resteasy.spi.HttpResponse;
import org.jboss.resteasy.spi.NotFoundException;
import org.jboss.resteasy.spi.ResteasyProviderFactory;
import org.jboss.resteasy.spi.UnauthorizedException;
import org.keycloak.OAuth2Constants;
import org.keycloak.freemarker.Theme;
import org.keycloak.freemarker.ThemeLoader;
import org.keycloak.jose.jws.JWSInput;
import org.keycloak.models.AdminRoles;
import org.keycloak.models.ApplicationModel;
import org.keycloak.models.Config;
import org.keycloak.models.Constants;
import org.keycloak.models.KeycloakSession;
import org.keycloak.models.RealmModel;
import org.keycloak.models.RoleModel;
import org.keycloak.models.UserModel;
import org.keycloak.provider.ProviderSession;
import org.keycloak.representations.AccessToken;
import org.keycloak.services.managers.AppAuthManager;
import org.keycloak.services.managers.ApplicationManager;
import org.keycloak.services.managers.Auth;
import org.keycloak.services.managers.RealmManager;
import org.keycloak.services.managers.TokenManager;
import org.keycloak.services.resources.KeycloakApplication;
import org.keycloak.services.resources.RealmsResource;
import org.keycloak.services.resources.TokenService;
import org.keycloak.services.resources.flows.Flows;
import org.keycloak.services.resources.flows.OAuthRedirect;
import javax.activation.FileTypeMap;
import javax.activation.MimetypesFileTypeMap;
import javax.ws.rs.GET;
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.Context;
import javax.ws.rs.core.HttpHeaders;
import javax.ws.rs.core.Response;
import javax.ws.rs.core.UriBuilder;
import javax.ws.rs.core.UriInfo;
import javax.ws.rs.ext.Providers;
import java.io.IOException;
import java.io.InputStream;
import java.net.URI;
import java.net.URISyntaxException;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
/**
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
* @version $Revision: 1 $
*/
public class AdminConsole {
protected static final Logger logger = Logger.getLogger(AdminConsole.class);
@Context
protected UriInfo uriInfo;
@Context
protected HttpRequest request;
@Context
protected HttpResponse response;
@Context
protected KeycloakSession session;
/*
@Context
protected ResourceContext resourceContext;
*/
@Context
protected Providers providers;
@Context
protected ProviderSession providerSession;
@Context
protected KeycloakApplication keycloak;
protected AppAuthManager authManager;
protected RealmModel realm;
public AdminConsole(RealmModel realm) {
this.realm = realm;
this.authManager = new AppAuthManager(providerSession);
}
public static class WhoAmI {
protected String userId;
protected String realm;
protected String displayName;
@JsonProperty("createRealm")
protected boolean createRealm;
@JsonProperty("realm_access")
protected Map<String, Set<String>> realmAccess = new HashMap<String, Set<String>>();
public WhoAmI() {
}
public WhoAmI(String userId, String realm, String displayName, boolean createRealm, Map<String, Set<String>> realmAccess) {
this.userId = userId;
this.realm = realm;
this.displayName = displayName;
this.createRealm = createRealm;
this.realmAccess = realmAccess;
}
public String getUserId() {
return userId;
}
public void setUserId(String userId) {
this.userId = userId;
}
public String getRealm() {
return realm;
}
public void setRealm(String realm) {
this.realm = realm;
}
public String getDisplayName() {
return displayName;
}
public void setDisplayName(String displayName) {
this.displayName = displayName;
}
public boolean isCreateRealm() {
return createRealm;
}
public void setCreateRealm(boolean createRealm) {
this.createRealm = createRealm;
}
public Map<String, Set<String>> getRealmAccess() {
return realmAccess;
}
public void setRealmAccess(Map<String, Set<String>> realmAccess) {
this.realmAccess = realmAccess;
}
}
@Path("config")
@GET
@Produces("application/json")
@NoCache
public ApplicationManager.InstallationAdapterConfig config() {
ApplicationModel consoleApp = realm.getApplicationByName(Constants.ADMIN_CONSOLE_APPLICATION);
if (consoleApp == null) {
throw new NotFoundException("Could not find admin console application");
}
return new ApplicationManager().toInstallationRepresentation(realm, consoleApp, keycloak.getBaseUri(uriInfo));
}
@Path("whoami")
@GET
@Produces("application/json")
@NoCache
public Response whoAmI(final @Context HttpHeaders headers) {
RealmManager realmManager = new RealmManager(session);
UserModel user = authManager.authenticateBearerToken(realm, uriInfo, headers);
if (user == null) {
return Response.status(401).build();
}
String displayName;
if (user.getFirstName() != null || user.getLastName() != null) {
displayName = user.getFirstName();
if (user.getLastName() != null) {
displayName = displayName != null ? displayName + " " + user.getLastName() : user.getLastName();
}
} else {
displayName = user.getLoginName();
}
RealmModel masterRealm = getAdminstrationRealm(realmManager);
if (masterRealm == null)
throw new NotFoundException("No realm found");
boolean createRealm = false;
if (realm.equals(masterRealm)) {
createRealm = masterRealm.hasRole(user, masterRealm.getRole(AdminRoles.CREATE_REALM));
}
Map<String, Set<String>> realmAccess = new HashMap<String, Set<String>>();
addRealmAdminAccess(realmAccess, realm.getRoleMappings(user));
return Response.ok(new WhoAmI(user.getId(), realm.getName(), displayName, createRealm, realmAccess)).build();
}
private void addRealmAdminAccess(Map<String, Set<String>> realmAdminAccess, Set<RoleModel> roles) {
for (RoleModel r : roles) {
if (r.getContainer() instanceof ApplicationModel) {
ApplicationModel app = (ApplicationModel) r.getContainer();
if (app.getName().endsWith(AdminRoles.APP_SUFFIX)) {
String realm = app.getName().substring(0, app.getName().length() - AdminRoles.APP_SUFFIX.length());
if (!realmAdminAccess.containsKey(realm)) {
realmAdminAccess.put(realm, new HashSet<String>());
}
realmAdminAccess.get(realm).add(r.getName());
}
}
if (r.isComposite()) {
addRealmAdminAccess(realmAdminAccess, r.getComposites());
}
}
}
@Path("logout")
@GET
@NoCache
public Response logout() {
URI redirect = AdminRoot.adminConsoleUrl(uriInfo).path("index.html").build(realm.getName());
return Response.status(302).location(
TokenService.logoutUrl(uriInfo).queryParam("redirect_uri", redirect.toString()).build(realm.getName())
).build();
}
protected RealmModel getAdminstrationRealm(RealmManager realmManager) {
return realmManager.getKeycloakAdminstrationRealm();
}
private static FileTypeMap mimeTypes = MimetypesFileTypeMap.getDefaultFileTypeMap();
@GET
public Response getMainPage() throws URISyntaxException {
return Response.status(302).location(
AdminRoot.adminConsoleUrl(uriInfo).path("index.html").build(realm.getName())
).build();
}
@GET
@Path("js/keycloak.js")
@Produces("text/javascript")
public Response getKeycloakJs() {
InputStream inputStream = getClass().getClassLoader().getResourceAsStream("keycloak.js");
if (inputStream != null) {
return Response.ok(inputStream).build();
} else {
return Response.status(Response.Status.NOT_FOUND).build();
}
}
@GET
@Path("{path:.+}")
public Response getResource(@PathParam("path") String path) {
try {
Theme theme = ThemeLoader.createTheme(Config.getThemeAdmin(), Theme.Type.ADMIN);
InputStream resource = theme.getResourceAsStream(path);
if (resource != null) {
String contentType = mimeTypes.getContentType(path);
return Response.ok(resource).type(contentType).build();
} else {
return Response.status(Response.Status.NOT_FOUND).build();
}
} catch (Exception e) {
logger.warn("Failed to get theme resource", e);
return Response.serverError().build();
}
}
}

View file

@ -0,0 +1,162 @@
package org.keycloak.services.resources.admin;
import org.jboss.logging.Logger;
import org.jboss.resteasy.spi.NotFoundException;
import org.jboss.resteasy.spi.ResteasyProviderFactory;
import org.jboss.resteasy.spi.UnauthorizedException;
import org.keycloak.jose.jws.JWSInput;
import org.keycloak.models.ApplicationModel;
import org.keycloak.models.Constants;
import org.keycloak.models.KeycloakSession;
import org.keycloak.models.RealmModel;
import org.keycloak.models.UserModel;
import org.keycloak.provider.ProviderSession;
import org.keycloak.representations.AccessToken;
import org.keycloak.services.managers.AppAuthManager;
import org.keycloak.services.managers.Auth;
import org.keycloak.services.managers.RealmManager;
import org.keycloak.services.managers.TokenManager;
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import javax.ws.rs.core.Context;
import javax.ws.rs.core.HttpHeaders;
import javax.ws.rs.core.Response;
import javax.ws.rs.core.UriBuilder;
import javax.ws.rs.core.UriInfo;
import java.io.IOException;
/**
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
* @version $Revision: 1 $
*/
@Path("/admin")
public class AdminRoot {
protected static final Logger logger = Logger.getLogger(AdminRoot.class);
@Context
protected UriInfo uriInfo;
protected AppAuthManager authManager;
protected TokenManager tokenManager;
@Context
protected KeycloakSession session;
public AdminRoot(TokenManager tokenManager) {
this.tokenManager = tokenManager;
this.authManager = new AppAuthManager(null);
}
public static UriBuilder adminBaseUrl(UriInfo uriInfo) {
return adminBaseUrl(uriInfo.getBaseUriBuilder());
}
public static UriBuilder adminBaseUrl(UriBuilder base) {
return base.path(AdminRoot.class);
}
@GET
public Response masterRealmAdminConsoleRedirect() {
RealmModel master = new RealmManager(session).getKeycloakAdminstrationRealm();
return Response.status(302).location(
uriInfo.getBaseUriBuilder().path(AdminRoot.class).path(AdminRoot.class, "getAdminConsole").path("index.html").build(master.getName())
).build();
}
@Path("index.html")
@GET
public Response masterRealmAdminConsoleRedirectHtml() {
return masterRealmAdminConsoleRedirect();
}
protected RealmModel locateRealm(String name, RealmManager realmManager) {
RealmModel realm = realmManager.getRealmByName(name);
if (realm == null) {
throw new NotFoundException("Realm " + name + " not found");
}
return realm;
}
public static UriBuilder adminConsoleUrl(UriInfo uriInfo) {
return adminConsoleUrl(uriInfo.getBaseUriBuilder());
}
public static UriBuilder adminConsoleUrl(UriBuilder base) {
return adminBaseUrl(base).path(AdminRoot.class, "getAdminConsole");
}
@Path("{realm}/console")
public AdminConsole getAdminConsole(final @PathParam("realm") String name) {
logger.info("*** get console for realm: " + name);
RealmManager realmManager = new RealmManager(session);
RealmModel realm = locateRealm(name, realmManager);
AdminConsole service = new AdminConsole(realm);
ResteasyProviderFactory.getInstance().injectProperties(service);
logger.info("returning AdminConsole");
return service;
}
protected Auth authenticateRealmAdminRequest(HttpHeaders headers) {
String tokenString = authManager.extractAuthorizationHeaderToken(headers);
if (tokenString == null) throw new UnauthorizedException("Bearer");
JWSInput input = new JWSInput(tokenString);
AccessToken token;
try {
token = input.readJsonContent(AccessToken.class);
} catch (IOException e) {
throw new UnauthorizedException("Bearer token format error");
}
String realmName = token.getAudience();
RealmManager realmManager = new RealmManager(session);
RealmModel realm = realmManager.getRealmByName(realmName);
if (realm == null) {
throw new UnauthorizedException("Unknown realm in token");
}
UserModel user = authManager.authenticateBearerToken(realm, uriInfo, headers);
if (user == null) {
logger.debug("Token not valid");
throw new UnauthorizedException("Bearer");
}
ApplicationModel consoleApp = realm.getApplicationByName(Constants.ADMIN_CONSOLE_APPLICATION);
if (consoleApp == null) {
throw new NotFoundException("Could not find admin console application");
}
Auth auth = new Auth(realm, user, consoleApp);
return auth;
}
public static UriBuilder realmsUrl(UriInfo uriInfo) {
return realmsUrl(uriInfo.getBaseUriBuilder());
}
public static UriBuilder realmsUrl(UriBuilder base) {
return adminBaseUrl(base).path(AdminRoot.class, "getRealmsAdmin");
}
@Path("realms")
public RealmsAdminResource getRealmsAdmin(@Context final HttpHeaders headers) {
Auth auth = authenticateRealmAdminRequest(headers);
RealmsAdminResource adminResource = new RealmsAdminResource(auth, tokenManager);
ResteasyProviderFactory.getInstance().injectProperties(adminResource);
//resourceContext.initResource(adminResource);
return adminResource;
}
@Path("serverinfo")
public ServerInfoAdminResource getServerInfo(@Context final HttpHeaders headers) {
ServerInfoAdminResource adminResource = new ServerInfoAdminResource();
ResteasyProviderFactory.getInstance().injectProperties(adminResource);
//resourceContext.initResource(adminResource);
return adminResource;
}
}

View file

@ -1,409 +0,0 @@
package org.keycloak.services.resources.admin;
import org.codehaus.jackson.annotate.JsonProperty;
import org.jboss.logging.Logger;
import org.jboss.resteasy.annotations.cache.NoCache;
import org.jboss.resteasy.spi.HttpRequest;
import org.jboss.resteasy.spi.HttpResponse;
import org.jboss.resteasy.spi.NotFoundException;
import org.jboss.resteasy.spi.ResteasyProviderFactory;
import org.jboss.resteasy.spi.UnauthorizedException;
import org.keycloak.OAuth2Constants;
import org.keycloak.models.AdminRoles;
import org.keycloak.models.ApplicationModel;
import org.keycloak.models.Config;
import org.keycloak.models.Constants;
import org.keycloak.models.KeycloakSession;
import org.keycloak.models.RealmModel;
import org.keycloak.models.RoleModel;
import org.keycloak.models.UserModel;
import org.keycloak.provider.ProviderSession;
import org.keycloak.services.managers.AppAuthManager;
import org.keycloak.services.managers.Auth;
import org.keycloak.services.managers.RealmManager;
import org.keycloak.services.managers.TokenManager;
import org.keycloak.services.resources.TokenService;
import org.keycloak.services.resources.flows.Flows;
import org.keycloak.services.resources.flows.OAuthRedirect;
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.QueryParam;
import javax.ws.rs.core.Context;
import javax.ws.rs.core.HttpHeaders;
import javax.ws.rs.core.NewCookie;
import javax.ws.rs.core.Response;
import javax.ws.rs.core.UriBuilder;
import javax.ws.rs.core.UriInfo;
import javax.ws.rs.ext.Providers;
import java.net.URI;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
/**
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
* @version $Revision: 1 $
*/
@Path("/rest/admin")
public class AdminService {
protected static final Logger logger = Logger.getLogger(AdminService.class);
@Context
protected UriInfo uriInfo;
@Context
protected HttpRequest request;
@Context
protected HttpResponse response;
@Context
protected KeycloakSession session;
/*
@Context
protected ResourceContext resourceContext;
*/
@Context
protected Providers providers;
@Context
protected ProviderSession providerSession;
protected String adminPath = "/admin/";
protected AppAuthManager authManager;
protected TokenManager tokenManager;
public AdminService(TokenManager tokenManager) {
this.tokenManager = tokenManager;
this.authManager = new AppAuthManager(providerSession, "KEYCLOAK_ADMIN_CONSOLE_IDENTITY", tokenManager);
}
public static UriBuilder adminApiUrl(UriInfo uriInfo) {
UriBuilder base = uriInfo.getBaseUriBuilder().path(AdminService.class).path(AdminService.class, "getRealmsAdmin").path(RealmsAdminResource.class, "getRealmAdmin");
return base;
}
public static class WhoAmI {
protected String userId;
protected String realm;
protected String displayName;
@JsonProperty("createRealm")
protected boolean createRealm;
@JsonProperty("realm_access")
protected Map<String, Set<String>> realmAccess = new HashMap<String, Set<String>>();
public WhoAmI() {
}
public WhoAmI(String userId, String realm, String displayName, boolean createRealm, Map<String, Set<String>> realmAccess) {
this.userId = userId;
this.realm = realm;
this.displayName = displayName;
this.createRealm = createRealm;
this.realmAccess = realmAccess;
}
public String getUserId() {
return userId;
}
public void setUserId(String userId) {
this.userId = userId;
}
public String getRealm() {
return realm;
}
public void setRealm(String realm) {
this.realm = realm;
}
public String getDisplayName() {
return displayName;
}
public void setDisplayName(String displayName) {
this.displayName = displayName;
}
public boolean isCreateRealm() {
return createRealm;
}
public void setCreateRealm(boolean createRealm) {
this.createRealm = createRealm;
}
public Map<String, Set<String>> getRealmAccess() {
return realmAccess;
}
public void setRealmAccess(Map<String, Set<String>> realmAccess) {
this.realmAccess = realmAccess;
}
}
@Path("keepalive")
@GET
@NoCache
public Response keepalive(final @Context HttpHeaders headers) {
logger.debug("keepalive");
RealmManager realmManager = new RealmManager(session);
RealmModel realm = getAdminstrationRealm(realmManager);
if (realm == null)
throw new NotFoundException("No realm found");
Auth auth = authManager.authenticateCookie(realm, headers);
if (auth == null) {
return Response.status(401).build();
}
NewCookie refreshCookie = authManager.createRefreshCookie(realm, auth.getUser(), auth.getClient(), AdminService.saasCookiePath(uriInfo).build());
return Response.noContent().cookie(refreshCookie).build();
}
@Path("whoami")
@GET
@Produces("application/json")
@NoCache
public Response whoAmI(final @Context HttpHeaders headers) {
RealmManager realmManager = new RealmManager(session);
RealmModel realm = getAdminstrationRealm(realmManager);
if (realm == null)
throw new NotFoundException("No realm found");
Auth auth = authManager.authenticateCookie(realm, headers);
if (auth == null) {
logger.debug("No auth cookie");
return Response.status(401).build();
}
UserModel user = auth.getUser();
if (user == null) {
return Response.status(401).build();
}
String displayName;
if (user.getFirstName() != null || user.getLastName() != null) {
displayName = user.getFirstName();
if (user.getLastName() != null) {
displayName = displayName != null ? displayName + " " + user.getLastName() : user.getLastName();
}
} else {
displayName = user.getLoginName();
}
boolean createRealm = realm.hasRole(user, realm.getRole(AdminRoles.CREATE_REALM));
Map<String, Set<String>> realmAccess = new HashMap<String, Set<String>>();
addRealmAdminAccess(realmAccess, auth.getRealm().getRoleMappings(auth.getUser()));
return Response.ok(new WhoAmI(user.getId(), Config.getAdminRealm(), displayName, createRealm, realmAccess)).build();
}
private void addRealmAdminAccess(Map<String, Set<String>> realmAdminAccess, Set<RoleModel> roles) {
for (RoleModel r : roles) {
if (r.getContainer() instanceof ApplicationModel) {
ApplicationModel app = (ApplicationModel) r.getContainer();
if (app.getName().endsWith(AdminRoles.APP_SUFFIX)) {
String realm = app.getName().substring(0, app.getName().length() - AdminRoles.APP_SUFFIX.length());
if (!realmAdminAccess.containsKey(realm)) {
realmAdminAccess.put(realm, new HashSet<String>());
}
realmAdminAccess.get(realm).add(r.getName());
}
}
if (r.isComposite()) {
addRealmAdminAccess(realmAdminAccess, r.getComposites());
}
}
}
@Path("isLoggedIn.js")
@GET
@Produces("application/javascript")
@NoCache
public String isLoggedIn(final @Context HttpHeaders headers) {
logger.debug("WHOAMI Javascript start.");
RealmManager realmManager = new RealmManager(session);
RealmModel realm = getAdminstrationRealm(realmManager);
if (realm == null) {
return "var keycloakCookieLoggedIn = false;";
}
UserModel user = authManager.authenticateCookie(realm, headers).getUser();
if (user == null) {
return "var keycloakCookieLoggedIn = false;";
}
logger.debug("WHOAMI: " + user.getLoginName());
return "var keycloakCookieLoggedIn = true;";
}
public static UriBuilder contextRoot(UriInfo uriInfo) {
return UriBuilder.fromUri(uriInfo.getBaseUri()).replacePath("/auth");
}
public static UriBuilder saasCookiePath(UriInfo uriInfo) {
return UriBuilder.fromUri(uriInfo.getBaseUri()).path(AdminService.class);
}
@Path("realms")
public RealmsAdminResource getRealmsAdmin(@Context final HttpHeaders headers) {
RealmManager realmManager = new RealmManager(session);
RealmModel adminRealm = getAdminstrationRealm(realmManager);
if (adminRealm == null)
throw new NotFoundException("Admin realm not found");
Auth auth = authManager.authenticate(adminRealm, headers);
if (auth == null) {
throw new UnauthorizedException("Bearer");
}
RealmsAdminResource adminResource = new RealmsAdminResource(auth, tokenManager);
ResteasyProviderFactory.getInstance().injectProperties(adminResource);
//resourceContext.initResource(adminResource);
return adminResource;
}
@Path("serverinfo")
public ServerInfoAdminResource getServerInfo(@Context final HttpHeaders headers) {
RealmManager realmManager = new RealmManager(session);
RealmModel adminRealm = getAdminstrationRealm(realmManager);
if (adminRealm == null)
throw new NotFoundException("Admin realm not found");
Auth auth = authManager.authenticate(adminRealm, headers);
UserModel admin = auth.getUser();
if (admin == null) {
throw new UnauthorizedException("Bearer");
}
ApplicationModel adminConsole = adminRealm.getApplicationNameMap().get(Constants.ADMIN_CONSOLE_APPLICATION);
if (adminConsole == null) {
throw new NotFoundException("Admin console application not found");
}
ServerInfoAdminResource adminResource = new ServerInfoAdminResource();
ResteasyProviderFactory.getInstance().injectProperties(adminResource);
//resourceContext.initResource(adminResource);
return adminResource;
}
private void expireCookie() {
authManager.expireCookie(AdminService.saasCookiePath(uriInfo).build());
}
@Path("login")
@GET
@NoCache
public Response loginPage(@QueryParam("path") String path) {
logger.debug("loginPage ********************** <---");
expireCookie();
OAuthRedirect oauth = new OAuthRedirect();
String authUrl = TokenService.loginPageUrl(uriInfo).build(Config.getAdminRealm()).toString();
logger.debugv("authUrl: {0}", authUrl);
oauth.setAuthUrl(authUrl);
oauth.setClientId(Constants.ADMIN_CONSOLE_APPLICATION);
UriBuilder redirectBuilder = uriInfo.getBaseUriBuilder().path(AdminService.class).path(AdminService.class, "loginRedirect");
if (path != null) {
redirectBuilder.queryParam("path", path);
}
URI redirectUri = redirectBuilder.build();
logger.debugv("redirectUri: {0}", redirectUri.toString());
oauth.setStateCookiePath(redirectUri.getRawPath());
return oauth.redirect(uriInfo, redirectUri.toString());
}
@Path("login-error")
@GET
@NoCache
public Response errorOnLoginRedirect(@QueryParam ("error") String message) {
RealmManager realmManager = new RealmManager(session);
RealmModel realm = getAdminstrationRealm(realmManager);
return Flows.forms(realm, uriInfo).setError(message).createErrorPage();
}
protected Response redirectOnLoginError(String message) {
URI uri = uriInfo.getBaseUriBuilder().path(AdminService.class).path(AdminService.class, "errorOnLoginRedirect").queryParam(OAuth2Constants.ERROR, message).build();
URI logout = TokenService.logoutUrl(uriInfo).queryParam(OAuth2Constants.REDIRECT_URI, uri.toString()).build(Config.getAdminRealm());
return Response.status(302).location(logout).build();
}
@Path("login-redirect")
@GET
@NoCache
public Response loginRedirect(@QueryParam("code") String code,
@QueryParam("state") String state,
@QueryParam("error") String error,
@QueryParam("path") String path,
@Context HttpHeaders headers
) {
try {
logger.info("loginRedirect ********************** <---");
if (error != null) {
logger.debug("error from oauth");
return redirectOnLoginError(error);
}
RealmManager realmManager = new RealmManager(session);
RealmModel adminRealm = getAdminstrationRealm(realmManager);
if (!adminRealm.isEnabled()) {
logger.debug("realm not enabled");
return redirectOnLoginError("realm not enabled");
}
ApplicationModel adminConsole = adminRealm.getApplicationNameMap().get(Constants.ADMIN_CONSOLE_APPLICATION);
if (!adminConsole.isEnabled()) {
logger.debug("admin app not enabled");
return redirectOnLoginError("admin app not enabled");
}
if (code == null) {
logger.debug("code not specified");
return redirectOnLoginError("invalid login data");
}
if (state == null) {
logger.debug("state not specified");
return redirectOnLoginError("invalid login data");
}
new OAuthRedirect().checkStateCookie(uriInfo, headers);
logger.debug("loginRedirect SUCCESS");
NewCookie cookie = authManager.createCookie(adminRealm, adminConsole, code, AdminService.saasCookiePath(uriInfo).build());
URI redirectUri = UriBuilder.fromUri(uriInfo.getBaseUri()).path(adminPath).build();
if (path != null) {
redirectUri = redirectUri.resolve("#" + UriBuilder.fromPath(path).build().toString());
}
return Response.status(302).cookie(cookie).location(redirectUri).build();
} finally {
expireCookie();
}
}
@Path("logout")
@GET
@NoCache
public Response logout() {
RealmManager realmManager = new RealmManager(session);
RealmModel realm = getAdminstrationRealm(realmManager);
expireCookie();
authManager.expireIdentityCookie(realm, uriInfo);
return Response.status(302).location(uriInfo.getBaseUriBuilder().path(AdminService.class).path(AdminService.class, "loginPage").build()).build();
}
@Path("logout-cookie")
@GET
@NoCache
public void logoutCookie() {
logger.debug("*** logoutCookie");
expireCookie();
}
protected RealmModel getAdminstrationRealm(RealmManager realmManager) {
return realmManager.getKeycloakAdminstrationRealm();
}
}

View file

@ -1,410 +0,0 @@
package org.keycloak.services.resources.admin;
import org.codehaus.jackson.annotate.JsonProperty;
import org.jboss.logging.Logger;
import org.jboss.resteasy.annotations.cache.NoCache;
import org.jboss.resteasy.spi.HttpRequest;
import org.jboss.resteasy.spi.HttpResponse;
import org.jboss.resteasy.spi.NotFoundException;
import org.jboss.resteasy.spi.ResteasyProviderFactory;
import org.jboss.resteasy.spi.UnauthorizedException;
import org.keycloak.OAuth2Constants;
import org.keycloak.models.AdminRoles;
import org.keycloak.models.ApplicationModel;
import org.keycloak.models.Config;
import org.keycloak.models.Constants;
import org.keycloak.models.KeycloakSession;
import org.keycloak.models.RealmModel;
import org.keycloak.models.RoleModel;
import org.keycloak.models.UserModel;
import org.keycloak.provider.ProviderSession;
import org.keycloak.services.managers.AppAuthManager;
import org.keycloak.services.managers.Auth;
import org.keycloak.services.managers.RealmManager;
import org.keycloak.services.managers.TokenManager;
import org.keycloak.services.resources.TokenService;
import org.keycloak.services.resources.flows.Flows;
import org.keycloak.services.resources.flows.OAuthRedirect;
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.QueryParam;
import javax.ws.rs.core.Context;
import javax.ws.rs.core.HttpHeaders;
import javax.ws.rs.core.NewCookie;
import javax.ws.rs.core.Response;
import javax.ws.rs.core.UriBuilder;
import javax.ws.rs.core.UriInfo;
import javax.ws.rs.ext.Providers;
import java.net.URI;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
/**
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
* @version $Revision: 1 $
*/
public class ConsoleLogin {
protected static final Logger logger = Logger.getLogger(ConsoleLogin.class);
@Context
protected UriInfo uriInfo;
@Context
protected HttpRequest request;
@Context
protected HttpResponse response;
@Context
protected KeycloakSession session;
/*
@Context
protected ResourceContext resourceContext;
*/
@Context
protected Providers providers;
@Context
protected ProviderSession providerSession;
protected String adminPath = "/admin/";
protected AppAuthManager authManager;
protected TokenManager tokenManager;
protected RealmModel realm;
public ConsoleLogin(TokenManager tokenManager, RealmModel realm) {
this.realm = realm;
this.tokenManager = tokenManager;
this.authManager = new AppAuthManager(providerSession, "KEYCLOAK_ADMIN_CONSOLE_IDENTITY", tokenManager);
}
public static UriBuilder adminApiUrl(UriInfo uriInfo) {
UriBuilder base = uriInfo.getBaseUriBuilder().path(ConsoleLogin.class).path(ConsoleLogin.class, "getRealmsAdmin").path(RealmsAdminResource.class, "getRealmAdmin");
return base;
}
public static class WhoAmI {
protected String userId;
protected String realm;
protected String displayName;
@JsonProperty("createRealm")
protected boolean createRealm;
@JsonProperty("realm_access")
protected Map<String, Set<String>> realmAccess = new HashMap<String, Set<String>>();
public WhoAmI() {
}
public WhoAmI(String userId, String realm, String displayName, boolean createRealm, Map<String, Set<String>> realmAccess) {
this.userId = userId;
this.realm = realm;
this.displayName = displayName;
this.createRealm = createRealm;
this.realmAccess = realmAccess;
}
public String getUserId() {
return userId;
}
public void setUserId(String userId) {
this.userId = userId;
}
public String getRealm() {
return realm;
}
public void setRealm(String realm) {
this.realm = realm;
}
public String getDisplayName() {
return displayName;
}
public void setDisplayName(String displayName) {
this.displayName = displayName;
}
public boolean isCreateRealm() {
return createRealm;
}
public void setCreateRealm(boolean createRealm) {
this.createRealm = createRealm;
}
public Map<String, Set<String>> getRealmAccess() {
return realmAccess;
}
public void setRealmAccess(Map<String, Set<String>> realmAccess) {
this.realmAccess = realmAccess;
}
}
@Path("keepalive")
@GET
@NoCache
public Response keepalive(final @Context HttpHeaders headers) {
logger.debug("keepalive");
RealmManager realmManager = new RealmManager(session);
RealmModel realm = getAdminstrationRealm(realmManager);
if (realm == null)
throw new NotFoundException("No realm found");
Auth auth = authManager.authenticateCookie(realm, headers);
if (auth == null) {
return Response.status(401).build();
}
NewCookie refreshCookie = authManager.createRefreshCookie(realm, auth.getUser(), auth.getClient(), ConsoleLogin.saasCookiePath(uriInfo).build());
return Response.noContent().cookie(refreshCookie).build();
}
@Path("whoami")
@GET
@Produces("application/json")
@NoCache
public Response whoAmI(final @Context HttpHeaders headers) {
RealmManager realmManager = new RealmManager(session);
RealmModel realm = getAdminstrationRealm(realmManager);
if (realm == null)
throw new NotFoundException("No realm found");
Auth auth = authManager.authenticateCookie(realm, headers);
if (auth == null) {
logger.debug("No auth cookie");
return Response.status(401).build();
}
UserModel user = auth.getUser();
if (user == null) {
return Response.status(401).build();
}
String displayName;
if (user.getFirstName() != null || user.getLastName() != null) {
displayName = user.getFirstName();
if (user.getLastName() != null) {
displayName = displayName != null ? displayName + " " + user.getLastName() : user.getLastName();
}
} else {
displayName = user.getLoginName();
}
boolean createRealm = realm.hasRole(user, realm.getRole(AdminRoles.CREATE_REALM));
Map<String, Set<String>> realmAccess = new HashMap<String, Set<String>>();
addRealmAdminAccess(realmAccess, auth.getRealm().getRoleMappings(auth.getUser()));
return Response.ok(new WhoAmI(user.getId(), Config.getAdminRealm(), displayName, createRealm, realmAccess)).build();
}
private void addRealmAdminAccess(Map<String, Set<String>> realmAdminAccess, Set<RoleModel> roles) {
for (RoleModel r : roles) {
if (r.getContainer() instanceof ApplicationModel) {
ApplicationModel app = (ApplicationModel) r.getContainer();
if (app.getName().endsWith(AdminRoles.APP_SUFFIX)) {
String realm = app.getName().substring(0, app.getName().length() - AdminRoles.APP_SUFFIX.length());
if (!realmAdminAccess.containsKey(realm)) {
realmAdminAccess.put(realm, new HashSet<String>());
}
realmAdminAccess.get(realm).add(r.getName());
}
}
if (r.isComposite()) {
addRealmAdminAccess(realmAdminAccess, r.getComposites());
}
}
}
@Path("isLoggedIn.js")
@GET
@Produces("application/javascript")
@NoCache
public String isLoggedIn(final @Context HttpHeaders headers) {
logger.debug("WHOAMI Javascript start.");
RealmManager realmManager = new RealmManager(session);
RealmModel realm = getAdminstrationRealm(realmManager);
if (realm == null) {
return "var keycloakCookieLoggedIn = false;";
}
UserModel user = authManager.authenticateCookie(realm, headers).getUser();
if (user == null) {
return "var keycloakCookieLoggedIn = false;";
}
logger.debug("WHOAMI: " + user.getLoginName());
return "var keycloakCookieLoggedIn = true;";
}
public static UriBuilder contextRoot(UriInfo uriInfo) {
return UriBuilder.fromUri(uriInfo.getBaseUri()).replacePath("/auth");
}
public static UriBuilder saasCookiePath(UriInfo uriInfo) {
return UriBuilder.fromUri(uriInfo.getBaseUri()).path(ConsoleLogin.class);
}
@Path("realms")
public RealmsAdminResource getRealmsAdmin(@Context final HttpHeaders headers) {
RealmManager realmManager = new RealmManager(session);
RealmModel adminRealm = getAdminstrationRealm(realmManager);
if (adminRealm == null)
throw new NotFoundException("Admin realm not found");
Auth auth = authManager.authenticate(adminRealm, headers);
if (auth == null) {
throw new UnauthorizedException("Bearer");
}
RealmsAdminResource adminResource = new RealmsAdminResource(auth, tokenManager);
ResteasyProviderFactory.getInstance().injectProperties(adminResource);
//resourceContext.initResource(adminResource);
return adminResource;
}
@Path("serverinfo")
public ServerInfoAdminResource getServerInfo(@Context final HttpHeaders headers) {
RealmManager realmManager = new RealmManager(session);
RealmModel adminRealm = getAdminstrationRealm(realmManager);
if (adminRealm == null)
throw new NotFoundException("Admin realm not found");
Auth auth = authManager.authenticate(adminRealm, headers);
UserModel admin = auth.getUser();
if (admin == null) {
throw new UnauthorizedException("Bearer");
}
ApplicationModel adminConsole = adminRealm.getApplicationNameMap().get(Constants.ADMIN_CONSOLE_APPLICATION);
if (adminConsole == null) {
throw new NotFoundException("Admin console application not found");
}
ServerInfoAdminResource adminResource = new ServerInfoAdminResource();
ResteasyProviderFactory.getInstance().injectProperties(adminResource);
//resourceContext.initResource(adminResource);
return adminResource;
}
private void expireCookie() {
authManager.expireCookie(ConsoleLogin.saasCookiePath(uriInfo).build());
}
@Path("login")
@GET
@NoCache
public Response loginPage(@QueryParam("path") String path) {
logger.debug("loginPage ********************** <---");
expireCookie();
OAuthRedirect oauth = new OAuthRedirect();
String authUrl = TokenService.loginPageUrl(uriInfo).build(Config.getAdminRealm()).toString();
logger.debugv("authUrl: {0}", authUrl);
oauth.setAuthUrl(authUrl);
oauth.setClientId(Constants.ADMIN_CONSOLE_APPLICATION);
UriBuilder redirectBuilder = uriInfo.getBaseUriBuilder().path(ConsoleLogin.class).path(ConsoleLogin.class, "loginRedirect");
if (path != null) {
redirectBuilder.queryParam("path", path);
}
URI redirectUri = redirectBuilder.build();
logger.debugv("redirectUri: {0}", redirectUri.toString());
oauth.setStateCookiePath(redirectUri.getRawPath());
return oauth.redirect(uriInfo, redirectUri.toString());
}
@Path("login-error")
@GET
@NoCache
public Response errorOnLoginRedirect(@QueryParam ("error") String message) {
RealmManager realmManager = new RealmManager(session);
RealmModel realm = getAdminstrationRealm(realmManager);
return Flows.forms(realm, uriInfo).setError(message).createErrorPage();
}
protected Response redirectOnLoginError(String message) {
URI uri = uriInfo.getBaseUriBuilder().path(ConsoleLogin.class).path(ConsoleLogin.class, "errorOnLoginRedirect").queryParam(OAuth2Constants.ERROR, message).build();
URI logout = TokenService.logoutUrl(uriInfo).queryParam(OAuth2Constants.REDIRECT_URI, uri.toString()).build(Config.getAdminRealm());
return Response.status(302).location(logout).build();
}
@Path("login-redirect")
@GET
@NoCache
public Response loginRedirect(@QueryParam("code") String code,
@QueryParam("state") String state,
@QueryParam("error") String error,
@QueryParam("path") String path,
@Context HttpHeaders headers
) {
try {
logger.info("loginRedirect ********************** <---");
if (error != null) {
logger.debug("error from oauth");
return redirectOnLoginError(error);
}
RealmManager realmManager = new RealmManager(session);
RealmModel adminRealm = getAdminstrationRealm(realmManager);
if (!adminRealm.isEnabled()) {
logger.debug("realm not enabled");
return redirectOnLoginError("realm not enabled");
}
ApplicationModel adminConsole = adminRealm.getApplicationNameMap().get(Constants.ADMIN_CONSOLE_APPLICATION);
if (!adminConsole.isEnabled()) {
logger.debug("admin app not enabled");
return redirectOnLoginError("admin app not enabled");
}
if (code == null) {
logger.debug("code not specified");
return redirectOnLoginError("invalid login data");
}
if (state == null) {
logger.debug("state not specified");
return redirectOnLoginError("invalid login data");
}
new OAuthRedirect().checkStateCookie(uriInfo, headers);
logger.debug("loginRedirect SUCCESS");
NewCookie cookie = authManager.createCookie(adminRealm, adminConsole, code, ConsoleLogin.saasCookiePath(uriInfo).build());
URI redirectUri = UriBuilder.fromUri(uriInfo.getBaseUri()).path(adminPath).build();
if (path != null) {
redirectUri = redirectUri.resolve("#" + UriBuilder.fromPath(path).build().toString());
}
return Response.status(302).cookie(cookie).location(redirectUri).build();
} finally {
expireCookie();
}
}
@Path("logout")
@GET
@NoCache
public Response logout() {
RealmManager realmManager = new RealmManager(session);
RealmModel realm = getAdminstrationRealm(realmManager);
expireCookie();
authManager.expireIdentityCookie(realm, uriInfo);
return Response.status(302).location(uriInfo.getBaseUriBuilder().path(ConsoleLogin.class).path(ConsoleLogin.class, "loginPage").build()).build();
}
@Path("logout-cookie")
@GET
@NoCache
public void logoutCookie() {
logger.debug("*** logoutCookie");
expireCookie();
}
protected RealmModel getAdminstrationRealm(RealmManager realmManager) {
return realmManager.getKeycloakAdminstrationRealm();
}
}

View file

@ -72,44 +72,48 @@ public class RealmsAdminResource {
@NoCache
@Produces("application/json")
public List<RealmRepresentation> getRealms() {
logger.debug(("getRealms()"));
List<RealmModel> realms = session.getRealms();
RealmManager realmManager = new RealmManager(session);
List<RealmRepresentation> reps = new ArrayList<RealmRepresentation>();
for (RealmModel realm : realms) {
if (auth.hasAppRole(realm.getAdminApp(), AdminRoles.MANAGE_REALM)) {
reps.add(ModelToRepresentation.toRepresentation(realm));
} else if (auth.hasOneOfAppRole(realm.getAdminApp(), AdminRoles.ALL_REALM_ROLES)) {
RealmRepresentation rep = new RealmRepresentation();
rep.setRealm(realm.getName());
reps.add(rep);
if (auth.getRealm().equals(realmManager.getKeycloakAdminstrationRealm())) {
List<RealmModel> realms = session.getRealms();
for (RealmModel realm : realms) {
addRealmRep(reps, realm);
}
} else {
addRealmRep(reps, auth.getRealm());
}
logger.debug(("getRealms()"));
return reps;
}
public static UriBuilder realmUrl(UriInfo uriInfo) {
return realmsUrl(uriInfo).path("{id}");
}
public static UriBuilder realmsUrl(UriInfo uriInfo) {
return uriInfo.getBaseUriBuilder().path(AdminService.class).path(AdminService.class, "getRealmsAdmin");
protected void addRealmRep(List<RealmRepresentation> reps, RealmModel realm) {
if (auth.hasAppRole(realm.getAdminApp(), AdminRoles.MANAGE_REALM)) {
reps.add(ModelToRepresentation.toRepresentation(realm));
} else if (auth.hasOneOfAppRole(realm.getAdminApp(), AdminRoles.ALL_REALM_ROLES)) {
RealmRepresentation rep = new RealmRepresentation();
rep.setRealm(realm.getName());
reps.add(rep);
}
}
@POST
@Consumes("application/json")
public Response importRealm(@Context final UriInfo uriInfo, final RealmRepresentation rep) {
RealmManager realmManager = new RealmManager(session);
if (!auth.getRealm().equals(realmManager.getKeycloakAdminstrationRealm())) {
throw new ForbiddenException();
}
if (!auth.hasRealmRole(AdminRoles.CREATE_REALM)) {
throw new ForbiddenException();
}
logger.debugv("importRealm: {0}", rep.getRealm());
RealmManager realmManager = new RealmManager(session);
try {
RealmModel realm = realmManager.importRealm(rep);
grantPermissionsToRealmCreator(realm);
URI location = realmUrl(uriInfo).build(realm.getName());
URI location = AdminRoot.realmsUrl(uriInfo).path(realm.getName()).build();
logger.debugv("imported realm success, sending back: {0}", location.toString());
return Response.created(location).build();
} catch (ModelDuplicateException e) {
@ -120,6 +124,10 @@ public class RealmsAdminResource {
@POST
@Consumes(MediaType.MULTIPART_FORM_DATA)
public Response uploadRealm(@Context final UriInfo uriInfo, MultipartFormDataInput input) throws IOException {
RealmManager realmManager = new RealmManager(session);
if (!auth.getRealm().equals(realmManager.getKeycloakAdminstrationRealm())) {
throw new ForbiddenException();
}
if (!auth.hasRealmRole(AdminRoles.CREATE_REALM)) {
throw new ForbiddenException();
}
@ -127,7 +135,6 @@ public class RealmsAdminResource {
Map<String, List<InputPart>> uploadForm = input.getFormDataMap();
List<InputPart> inputParts = uploadForm.get("file");
RealmManager realmManager = new RealmManager(session);
for (InputPart inputPart : inputParts) {
inputPart.setMediaType(MediaType.APPLICATION_JSON_TYPE);
RealmRepresentation rep = inputPart.getBody(new GenericType<RealmRepresentation>() {
@ -143,7 +150,7 @@ public class RealmsAdminResource {
grantPermissionsToRealmCreator(realm);
if (inputParts.size() == 1) {
URI location = realmUrl(uriInfo).build(realm.getName());
URI location = AdminRoot.realmsUrl(uriInfo).path(realm.getName()).build();
return Response.created(location).build();
}
}
@ -172,6 +179,10 @@ public class RealmsAdminResource {
RealmModel realm = realmManager.getRealmByName(name);
if (realm == null) throw new NotFoundException("{realm} = " + name);
if (!auth.getRealm().equals(realmManager.getKeycloakAdminstrationRealm())
&& !auth.getRealm().equals(realm)) {
throw new ForbiddenException();
}
RealmAuth realmAuth = new RealmAuth(auth, realm.getAdminApp());
RealmAdminResource adminResource = new RealmAdminResource(realmAuth, realm, tokenManager);

View file

@ -23,14 +23,12 @@ package org.keycloak.services.resources.flows;
import org.keycloak.services.resources.AccountService;
import org.keycloak.services.resources.ThemeResource;
import org.keycloak.services.resources.admin.AdminService;
import org.keycloak.services.resources.RealmsResource;
import org.keycloak.services.resources.RequiredActionsService;
import org.keycloak.services.resources.SocialResource;
import org.keycloak.services.resources.TokenService;
import javax.ws.rs.core.UriBuilder;
import javax.ws.rs.core.UriInfo;
import java.net.URI;
/**
@ -146,26 +144,6 @@ public class Urls {
return tokenBase(baseUri).path(TokenService.class, "accessCodeToToken").build(realmId);
}
private static UriBuilder saasBase(URI baseUri) {
return UriBuilder.fromUri(baseUri).path(AdminService.class);
}
public static URI saasLoginAction(URI baseUri) {
return saasBase(baseUri).path(AdminService.class, "processLogin").build();
}
public static URI saasLoginPage(URI baseUri) {
return saasBase(baseUri).path(AdminService.class, "loginPage").build();
}
public static URI saasRegisterAction(URI baseUri) {
return saasBase(baseUri).path(AdminService.class, "processRegister").build();
}
public static URI saasRegisterPage(URI baseUri) {
return saasBase(baseUri).path(AdminService.class, "registerPage").build();
}
public static UriBuilder socialBase(URI baseUri) {
return UriBuilder.fromUri(baseUri).path(SocialResource.class);
}

View file

@ -170,6 +170,9 @@ public class AssertEvents implements TestRule, AuditListenerFactory {
return new AuditListener() {
@Override
public void onEvent(Event event) {
if (event == null) {
throw new RuntimeException("Added null event");
}
events.add(event);
}

View file

@ -42,6 +42,7 @@ import org.keycloak.models.utils.TimeBasedOTP;
import org.keycloak.representations.idm.CredentialRepresentation;
import org.keycloak.services.managers.RealmManager;
import org.keycloak.services.resources.AccountService;
import org.keycloak.services.resources.RealmsResource;
import org.keycloak.testsuite.AssertEvents;
import org.keycloak.testsuite.OAuthClient;
import org.keycloak.testsuite.Retry;
@ -92,7 +93,9 @@ public class AccountTest {
}
});
public static String ACCOUNT_REDIRECT = AccountService.loginRedirectUrl(UriBuilder.fromUri("http://localhost:8081/auth")).build("test").toString();
private static final UriBuilder BASE = UriBuilder.fromUri("http://localhost:8081/auth");
private static final String ACCOUNT_URL = RealmsResource.accountUrl(BASE.clone()).build("test").toString();
public static String ACCOUNT_REDIRECT = AccountService.loginRedirectUrl(BASE.clone()).build("test").toString();
@Rule
public AssertEvents events = new AssertEvents(keycloakRule);
@ -209,6 +212,8 @@ public class AccountTest {
changePasswordPage.logout();
events.expectLogout().detail(Details.REDIRECT_URI, ACCOUNT_URL).assertEvent();
loginPage.open();
loginPage.login("test-user@localhost", "password");
@ -378,8 +383,6 @@ public class AccountTest {
logPage.open();
e.add(events.poll());
Collections.reverse(e);
Assert.assertTrue(logPage.isCurrent());

View file

@ -188,10 +188,6 @@ public class RequiredActionTotpSetupTest {
accountTotpPage.open();
accountTotpPage.assertCurrent();
events.expectLogin().user(userId).detail(Details.AUTH_METHOD, "sso").client("account")
.detail(Details.REDIRECT_URI, AccountService.loginRedirectUrl(UriBuilder.fromUri("http://localhost:8081/auth")).queryParam("path", "totp").build("test").toString())
.removeDetail(Details.USERNAME).assertEvent();
// Remove google authentificator
accountTotpPage.removeTotp();

View file

@ -36,6 +36,8 @@ import org.keycloak.representations.idm.RealmRepresentation;
import org.keycloak.services.managers.RealmManager;
import org.keycloak.services.managers.TokenManager;
import org.keycloak.services.resources.TokenService;
import org.keycloak.services.resources.admin.AdminRoot;
import org.keycloak.services.resources.admin.RealmAdminResource;
import org.keycloak.testsuite.OAuthClient;
import org.keycloak.testsuite.pages.LoginPage;
import org.keycloak.testsuite.rule.AbstractKeycloakRule;
@ -123,7 +125,8 @@ public class AdapterTest {
// View stats
Client client = ClientBuilder.newClient();
WebTarget adminTarget = client.target("http://localhost:8081/auth/rest/admin/realms/demo");
UriBuilder authBase = UriBuilder.fromUri("http://localhost:8081/auth");
WebTarget adminTarget = client.target(AdminRoot.realmsUrl(authBase)).path("demo");
Map<String, SessionStats> stats = adminTarget.path("session-stats").request()
.header(HttpHeaders.AUTHORIZATION, "Bearer " + adminToken)
.get(new GenericType<Map<String, SessionStats>>(){});

View file

@ -36,6 +36,7 @@ import org.keycloak.representations.idm.RealmRepresentation;
import org.keycloak.services.managers.RealmManager;
import org.keycloak.services.managers.TokenManager;
import org.keycloak.services.resources.TokenService;
import org.keycloak.services.resources.admin.AdminRoot;
import org.keycloak.testsuite.OAuthClient;
import org.keycloak.testsuite.pages.LoginPage;
import org.keycloak.testsuite.rule.AbstractKeycloakRule;
@ -126,7 +127,8 @@ public class RelativeUriAdapterTest {
// View stats
Client client = ClientBuilder.newClient();
WebTarget adminTarget = client.target("http://localhost:8081/auth/rest/admin/realms/demo");
UriBuilder authBase = UriBuilder.fromUri("http://localhost:8081/auth");
WebTarget adminTarget = client.target(AdminRoot.realmsUrl(authBase)).path("demo");
Map<String, SessionStats> stats = adminTarget.path("session-stats").request()
.header(HttpHeaders.AUTHORIZATION, "Bearer " + adminToken)
.get(new GenericType<Map<String, SessionStats>>(){});

View file

@ -92,7 +92,6 @@ public class SSOTest {
Assert.assertTrue(profilePage.isCurrent());
events.expectLogin().detail(Details.AUTH_METHOD, "sso").removeDetail(Details.USERNAME).client("test-app").assertEvent();
events.expectLogin().detail(Details.AUTH_METHOD, "sso").removeDetail(Details.USERNAME).client("account").detail(Details.REDIRECT_URI, AccountService.loginRedirectUrl(UriBuilder.fromUri("http://localhost:8081/auth")).build("test").toString()).assertEvent();
}
}