keycloak.js login for admin

This commit is contained in:
Bill Burke 2014-05-08 19:55:57 -04:00
parent d523242dbb
commit 2d949b63b5
33 changed files with 676 additions and 1188 deletions

View file

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

View file

@ -9,9 +9,9 @@
</head> </head>
<body bgcolor="#E3F6CE"> <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(); .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); IDToken idToken = CustomerDatabaseClient.getIDToken(request);
%> %>
<p><a href="<%=logoutUri%>">logout</a> | <a <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/angular/select2.js" type="text/javascript"></script>
<script src="lib/fileupload/angular-file-upload.min.js"></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/app.js" type="text/javascript"></script>
<script src="js/controllers/realm.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> <script src="js/controllers/applications.js" type="text/javascript"></script>
@ -76,12 +77,12 @@
$.idleTimeout('#idletimeout', '#idletimeout a', { $.idleTimeout('#idletimeout', '#idletimeout a', {
idleAfter: 300, idleAfter: 300,
pollingInterval: 60, pollingInterval: 60,
keepAliveURL: authUrl + '/rest/admin/keepalive', // keepAliveURL: authUrl + '/admin/keepalive', would need to change this path
serverResponseEquals: '', serverResponseEquals: '',
failedRequests: 1, failedRequests: 1,
onTimeout: function(){ onTimeout: function(){
$(this).slideUp(); $(this).slideUp();
window.location = authUrl + '/rest/admin/logout'; logout();
}, },
onIdle: function(){ onIdle: function(){
$(this).slideDown(); // show the warning bar $(this).slideDown(); // show the warning bar

View file

@ -1,28 +1,68 @@
'use strict'; '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; var authUrl = window.location.href;
authUrl = authUrl.substring(0, authUrl.indexOf('/admin/')); authUrl = authUrl.substring(0, authUrl.indexOf('/admin/'));
var module = angular.module('keycloak', [ 'keycloak.services', 'keycloak.loaders', 'ui.bootstrap', 'ui.select2', 'angularFileUpload' ]); var module = angular.module('keycloak', [ 'keycloak.services', 'keycloak.loaders', 'ui.bootstrap', 'ui.select2', 'angularFileUpload' ]);
var resourceRequests = 0; var resourceRequests = 0;
var loadingTimer = -1; var loadingTimer = -1;
angular.element(document).ready(function ($http) { angular.element(document).ready(function ($http) {
$http.get(authUrl + '/rest/admin/whoami').success(function(data) { var keycloakAuth = new Keycloak(configUrl);
var auth = {}; var auth = {};
auth.user = data; auth.loggedIn = false;
auth.loggedIn = true;
keycloakAuth.init('login-required').success(function () {
auth.loggedIn = true;
auth.authz = keycloakAuth;
module.factory('Auth', function() { module.factory('Auth', function() {
return auth; return auth;
}); });
angular.bootstrap(document, ["keycloak"]); angular.bootstrap(document, ["keycloak"]);
}).error(function() { }).error(function () {
var path = window.location.hash && window.location.hash.substring(1) || '/'; window.location.reload();
window.location = authUrl + '/rest/admin/login?path=' + path; });
});
}); });
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) { module.config([ '$routeProvider', function($routeProvider) {
@ -660,7 +700,10 @@ module.config([ '$routeProvider', function($routeProvider) {
}, },
controller : 'RealmSessionStatsCtrl' controller : 'RealmSessionStatsCtrl'
}) })
.when('/logout', {
templateUrl : 'partials/home.html',
controller : 'LogoutCtrl'
})
.otherwise({ .otherwise({
templateUrl : 'partials/notfound.html' templateUrl : 'partials/notfound.html'
}); });
@ -682,19 +725,19 @@ module.config(function($httpProvider) {
$httpProvider.defaults.transformRequest.push(spinnerFunction); $httpProvider.defaults.transformRequest.push(spinnerFunction);
$httpProvider.responseInterceptors.push('spinnerInterceptor'); $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 function(promise) {
return promise.then(function(response) { return promise.then(function(response) {
return response; return response;
}, function(response) { }, function(response) {
if (response.status == 401) { if (response.status == 401) {
console.log('session timeout?'); console.log('session timeout?');
Auth.loggedIn = false; logout();
window.location = authUrl + '/rest/admin/login?path=' + $location.path(); } else if (response.status == 403) {
} else if (response.status == 403) {
Notifications.error("Forbidden"); Notifications.error("Forbidden");
} else if (response.status == 404) { } else if (response.status == 404) {
Notifications.error("Not found"); Notifications.error("Not found");

View file

@ -361,7 +361,7 @@ module.controller('ApplicationScopeMappingCtrl', function($scope, $http, realm,
}); });
$scope.addRealmRole = function() { $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() { $scope.selectedRealmRoles).success(function() {
for (var i = 0; i < $scope.selectedRealmRoles.length; i++) { for (var i = 0; i < $scope.selectedRealmRoles.length; i++) {
var role = $scope.selectedRealmRoles[i]; var role = $scope.selectedRealmRoles[i];
@ -376,7 +376,7 @@ module.controller('ApplicationScopeMappingCtrl', function($scope, $http, realm,
}; };
$scope.deleteRealmRole = function() { $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() { {data : $scope.selectedRealmMappings, headers : {"content-type" : "application/json"}}).success(function() {
for (var i = 0; i < $scope.selectedRealmMappings.length; i++) { for (var i = 0; i < $scope.selectedRealmMappings.length; i++) {
var role = $scope.selectedRealmMappings[i]; var role = $scope.selectedRealmMappings[i];
@ -391,7 +391,7 @@ module.controller('ApplicationScopeMappingCtrl', function($scope, $http, realm,
}; };
$scope.addApplicationRole = function() { $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() { $scope.selectedApplicationRoles).success(function() {
for (var i = 0; i < $scope.selectedApplicationRoles.length; i++) { for (var i = 0; i < $scope.selectedApplicationRoles.length; i++) {
var role = $scope.selectedApplicationRoles[i]; var role = $scope.selectedApplicationRoles[i];
@ -406,7 +406,7 @@ module.controller('ApplicationScopeMappingCtrl', function($scope, $http, realm,
}; };
$scope.deleteApplicationRole = function() { $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() { {data : $scope.selectedApplicationMappings, headers : {"content-type" : "application/json"}}).success(function() {
for (var i = 0; i < $scope.selectedApplicationMappings.length; i++) { for (var i = 0; i < $scope.selectedApplicationMappings.length; i++) {
var role = $scope.selectedApplicationMappings[i]; var role = $scope.selectedApplicationMappings[i];

View file

@ -211,7 +211,7 @@ module.controller('OAuthClientScopeMappingCtrl', function($scope, $http, realm,
}); });
$scope.addRealmRole = function() { $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() { $scope.selectedRealmRoles).success(function() {
for (var i = 0; i < $scope.selectedRealmRoles.length; i++) { for (var i = 0; i < $scope.selectedRealmRoles.length; i++) {
var role = $scope.selectedRealmRoles[i]; var role = $scope.selectedRealmRoles[i];
@ -226,7 +226,7 @@ module.controller('OAuthClientScopeMappingCtrl', function($scope, $http, realm,
}; };
$scope.deleteRealmRole = function() { $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() { {data : $scope.selectedRealmMappings, headers : {"content-type" : "application/json"}}).success(function() {
for (var i = 0; i < $scope.selectedRealmMappings.length; i++) { for (var i = 0; i < $scope.selectedRealmMappings.length; i++) {
var role = $scope.selectedRealmMappings[i]; var role = $scope.selectedRealmMappings[i];
@ -241,7 +241,7 @@ module.controller('OAuthClientScopeMappingCtrl', function($scope, $http, realm,
}; };
$scope.addApplicationRole = function() { $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() { $scope.selectedApplicationRoles).success(function() {
for (var i = 0; i < $scope.selectedApplicationRoles.length; i++) { for (var i = 0; i < $scope.selectedApplicationRoles.length; i++) {
var role = $scope.selectedApplicationRoles[i]; var role = $scope.selectedApplicationRoles[i];
@ -256,7 +256,7 @@ module.controller('OAuthClientScopeMappingCtrl', function($scope, $http, realm,
}; };
$scope.deleteApplicationRole = function() { $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() { {data : $scope.selectedApplicationMappings, headers : {"content-type" : "application/json"}}).success(function() {
for (var i = 0; i < $scope.selectedApplicationMappings.length; i++) { for (var i = 0; i < $scope.selectedApplicationMappings.length; i++) {
var role = $scope.selectedApplicationMappings[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() { $scope.addMessage = function() {
Notifications.success("test"); Notifications.success("test");
}; };
$scope.authUrl = authUrl; $scope.authUrl = authUrl;
$scope.logout = logout;
$scope.auth = Auth; $scope.auth = Auth;
$http.get(authUrl + '/rest/admin/whoami').success(function(data, status) { WhoAmI.get(function(data) {
Auth.user = data; Auth.user = data;
Auth.loggedIn = true; Auth.loggedIn = true;
@ -68,10 +69,7 @@ module.controller('GlobalCtrl', function($scope, $http, Auth, Current, $location
return getAccess('manage-audit'); return getAccess('manage-audit');
} }
} }
}) });
.error(function(data, status) {
Auth.loggedIn = false;
});
$scope.$watch(function() { $scope.$watch(function() {
return $location.path(); 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'); console.log('RealmCreateCtrl');
Current.realm = null; Current.realm = null;
@ -150,7 +148,7 @@ module.controller('RealmCreateCtrl', function($scope, Current, Realm, $upload, $
for (var i = 0; i < $scope.files.length; i++) { for (var i = 0; i < $scope.files.length; i++) {
var $file = $scope.files[i]; var $file = $scope.files[i];
$scope.upload = $upload.upload({ $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, // method: POST or PUT,
// headers: {'headerKey': 'headerValue'}, withCredential: true, // headers: {'headerKey': 'headerValue'}, withCredential: true,
data: {myObj: ""}, data: {myObj: ""},
@ -165,7 +163,8 @@ module.controller('RealmCreateCtrl', function($scope, Current, Realm, $upload, $
Realm.query(function(data) { Realm.query(function(data) {
Current.realms = data; Current.realms = data;
$http.get(authUrl + '/rest/admin/whoami').success(function(user) {
WhoAmI.get(function(user) {
Auth.user = user; Auth.user = user;
Notifications.success("The realm has been uploaded."); Notifications.success("The realm has been uploaded.");
@ -202,7 +201,7 @@ module.controller('RealmCreateCtrl', function($scope, Current, Realm, $upload, $
Realm.query(function(data) { Realm.query(function(data) {
Current.realms = data; Current.realms = data;
$http.get(authUrl + '/rest/admin/whoami').success(function(user) { $http.get(authUrl + '/admin/whoami').success(function(user) {
Auth.user = user; Auth.user = user;
$location.url("/realms/" + realmCopy.realm); $location.url("/realms/" + realmCopy.realm);
@ -573,7 +572,7 @@ module.controller('RealmSocialCtrl', function($scope, realm, Realm, serverInfo,
var oldCopy = angular.copy($scope.realm); var oldCopy = angular.copy($scope.realm);
$scope.changed = false; $scope.changed = false;
$scope.callbackUrl = $location.absUrl().replace(/\/admin.*/, "/rest/social/callback"); $scope.callbackUrl = $location.absUrl().replace(/\/admin.*/, "/social/callback");
$scope.addProvider = function(pId) { $scope.addProvider = function(pId) {
if (!$scope.realm.socialProviders) { if (!$scope.realm.socialProviders) {

View file

@ -28,7 +28,7 @@ module.controller('UserRoleMappingCtrl', function($scope, $http, realm, user, ro
}); });
$scope.addRealmRole = function() { $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() { $scope.selectedRealmRoles).success(function() {
for (var i = 0; i < $scope.selectedRealmRoles.length; i++) { for (var i = 0; i < $scope.selectedRealmRoles.length; i++) {
var role = $scope.selectedRealmRoles[i]; var role = $scope.selectedRealmRoles[i];
@ -43,7 +43,7 @@ module.controller('UserRoleMappingCtrl', function($scope, $http, realm, user, ro
}; };
$scope.deleteRealmRole = function() { $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() { {data : $scope.selectedRealmMappings, headers : {"content-type" : "application/json"}}).success(function() {
for (var i = 0; i < $scope.selectedRealmMappings.length; i++) { for (var i = 0; i < $scope.selectedRealmMappings.length; i++) {
var role = $scope.selectedRealmMappings[i]; var role = $scope.selectedRealmMappings[i];
@ -58,7 +58,7 @@ module.controller('UserRoleMappingCtrl', function($scope, $http, realm, user, ro
}; };
$scope.addApplicationRole = function() { $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() { $scope.selectedApplicationRoles).success(function() {
for (var i = 0; i < $scope.selectedApplicationRoles.length; i++) { for (var i = 0; i < $scope.selectedApplicationRoles.length; i++) {
var role = $scope.selectedApplicationRoles[i]; var role = $scope.selectedApplicationRoles[i];
@ -73,7 +73,7 @@ module.controller('UserRoleMappingCtrl', function($scope, $http, realm, user, ro
}; };
$scope.deleteApplicationRole = function() { $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() { {data : $scope.selectedApplicationMappings, headers : {"content-type" : "application/json"}}).success(function() {
for (var i = 0; i < $scope.selectedApplicationMappings.length; i++) { for (var i = 0; i < $scope.selectedApplicationMappings.length; i++) {
var role = $scope.selectedApplicationMappings[i]; var role = $scope.selectedApplicationMappings[i];

View file

@ -127,8 +127,12 @@ module.factory('Notifications', function($rootScope, $timeout) {
return notifications; return notifications;
}); });
module.factory('WhoAmI', function($resource) {
return $resource(consoleBaseUrl + '/whoami');
});
module.factory('Realm', function($resource) { module.factory('Realm', function($resource) {
return $resource(authUrl + '/rest/admin/realms/:id', { return $resource(authUrl + '/admin/realms/:id', {
id : '@realm' id : '@realm'
}, { }, {
update : { update : {
@ -143,7 +147,7 @@ module.factory('Realm', function($resource) {
}); });
module.factory('RealmAudit', function($resource) { module.factory('RealmAudit', function($resource) {
return $resource(authUrl + '/rest/admin/realms/:id/audit', { return $resource(authUrl + '/admin/realms/:id/audit', {
id : '@realm' id : '@realm'
}, { }, {
update : { update : {
@ -153,17 +157,17 @@ module.factory('RealmAudit', function($resource) {
}); });
module.factory('RealmAuditEvents', 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' id : '@realm'
}); });
}); });
module.factory('ServerInfo', function($resource) { module.factory('ServerInfo', function($resource) {
return $resource(authUrl + '/rest/admin/serverinfo'); return $resource(authUrl + '/admin/serverinfo');
}); });
module.factory('User', function($resource) { module.factory('User', function($resource) {
return $resource(authUrl + '/rest/admin/realms/:realm/users/:userId', { return $resource(authUrl + '/admin/realms/:realm/users/:userId', {
realm : '@realm', realm : '@realm',
userId : '@userId' userId : '@userId'
}, { }, {
@ -174,13 +178,13 @@ module.factory('User', function($resource) {
}); });
module.factory('UserSessionStats', 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', realm : '@realm',
user : '@user' user : '@user'
}); });
}); });
module.factory('UserLogout', function($resource) { 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', realm : '@realm',
user : '@user' user : '@user'
}); });
@ -189,7 +193,7 @@ module.factory('UserLogout', function($resource) {
module.factory('UserCredentials', function($resource) { module.factory('UserCredentials', function($resource) {
var credentials = {}; 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', realm : '@realm',
userId : '@userId' userId : '@userId'
}, { }, {
@ -198,7 +202,7 @@ module.factory('UserCredentials', function($resource) {
} }
}).update; }).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', realm : '@realm',
userId : '@userId' userId : '@userId'
}, { }, {
@ -207,7 +211,7 @@ module.factory('UserCredentials', function($resource) {
} }
}).update; }).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', realm : '@realm',
userId : '@userId' userId : '@userId'
}, { }, {
@ -220,14 +224,14 @@ module.factory('UserCredentials', function($resource) {
}); });
module.factory('RealmRoleMapping', 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', realm : '@realm',
userId : '@userId' userId : '@userId'
}); });
}); });
module.factory('ApplicationRoleMapping', function($resource) { 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', realm : '@realm',
userId : '@userId', userId : '@userId',
application : "@application" application : "@application"
@ -235,14 +239,14 @@ module.factory('ApplicationRoleMapping', function($resource) {
}); });
module.factory('ApplicationRealmScopeMapping', 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', realm : '@realm',
application : '@application' application : '@application'
}); });
}); });
module.factory('ApplicationApplicationScopeMapping', function($resource) { 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', realm : '@realm',
application : '@application', application : '@application',
targetApp : '@targetApp' targetApp : '@targetApp'
@ -252,33 +256,33 @@ module.factory('ApplicationApplicationScopeMapping', function($resource) {
module.factory('RealmRoles', function($resource) { module.factory('RealmRoles', function($resource) {
return $resource(authUrl + '/rest/admin/realms/:realm/roles', { return $resource(authUrl + '/admin/realms/:realm/roles', {
realm : '@realm' realm : '@realm'
}); });
}); });
module.factory('RoleRealmComposites', function($resource) { 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', realm : '@realm',
role : '@role' role : '@role'
}); });
}); });
module.factory('RealmPushRevocation', function($resource) { module.factory('RealmPushRevocation', function($resource) {
return $resource(authUrl + '/rest/admin/realms/:realm/push-revocation', { return $resource(authUrl + '/admin/realms/:realm/push-revocation', {
realm : '@realm' realm : '@realm'
}); });
}); });
module.factory('RealmSessionStats', function($resource) { module.factory('RealmSessionStats', function($resource) {
return $resource(authUrl + '/rest/admin/realms/:realm/session-stats', { return $resource(authUrl + '/admin/realms/:realm/session-stats', {
realm : '@realm' realm : '@realm'
}); });
}); });
module.factory('RoleApplicationComposites', function($resource) { 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', realm : '@realm',
role : '@role', role : '@role',
application : "@application" application : "@application"
@ -361,7 +365,7 @@ function roleControl($scope, realm, role, roles, applications,
$scope.addRealmRole = function() { $scope.addRealmRole = function() {
$scope.compositeSwitchDisabled=true; $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() { $scope.selectedRealmRoles).success(function() {
for (var i = 0; i < $scope.selectedRealmRoles.length; i++) { for (var i = 0; i < $scope.selectedRealmRoles.length; i++) {
var role = $scope.selectedRealmRoles[i]; var role = $scope.selectedRealmRoles[i];
@ -377,7 +381,7 @@ function roleControl($scope, realm, role, roles, applications,
$scope.deleteRealmRole = function() { $scope.deleteRealmRole = function() {
$scope.compositeSwitchDisabled=true; $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() { {data : $scope.selectedRealmMappings, headers : {"content-type" : "application/json"}}).success(function() {
for (var i = 0; i < $scope.selectedRealmMappings.length; i++) { for (var i = 0; i < $scope.selectedRealmMappings.length; i++) {
var role = $scope.selectedRealmMappings[i]; var role = $scope.selectedRealmMappings[i];
@ -393,7 +397,7 @@ function roleControl($scope, realm, role, roles, applications,
$scope.addApplicationRole = function() { $scope.addApplicationRole = function() {
$scope.compositeSwitchDisabled=true; $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() { $scope.selectedApplicationRoles).success(function() {
for (var i = 0; i < $scope.selectedApplicationRoles.length; i++) { for (var i = 0; i < $scope.selectedApplicationRoles.length; i++) {
var role = $scope.selectedApplicationRoles[i]; var role = $scope.selectedApplicationRoles[i];
@ -409,7 +413,7 @@ function roleControl($scope, realm, role, roles, applications,
$scope.deleteApplicationRole = function() { $scope.deleteApplicationRole = function() {
$scope.compositeSwitchDisabled=true; $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() { {data : $scope.selectedApplicationMappings, headers : {"content-type" : "application/json"}}).success(function() {
for (var i = 0; i < $scope.selectedApplicationMappings.length; i++) { for (var i = 0; i < $scope.selectedApplicationMappings.length; i++) {
var role = $scope.selectedApplicationMappings[i]; var role = $scope.selectedApplicationMappings[i];
@ -460,7 +464,7 @@ function roleControl($scope, realm, role, roles, applications,
module.factory('Role', function($resource) { module.factory('Role', function($resource) {
return $resource(authUrl + '/rest/admin/realms/:realm/roles/:role', { return $resource(authUrl + '/admin/realms/:realm/roles/:role', {
realm : '@realm', realm : '@realm',
role : '@role' role : '@role'
}, { }, {
@ -471,7 +475,7 @@ module.factory('Role', function($resource) {
}); });
module.factory('RoleById', 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', realm : '@realm',
role : '@role' role : '@role'
}, { }, {
@ -482,7 +486,7 @@ module.factory('RoleById', function($resource) {
}); });
module.factory('ApplicationRole', 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', realm : '@realm',
application : "@application", application : "@application",
role : '@role' role : '@role'
@ -494,7 +498,7 @@ module.factory('ApplicationRole', function($resource) {
}); });
module.factory('ApplicationClaims', 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', realm : '@realm',
application : "@application" application : "@application"
}, { }, {
@ -505,40 +509,40 @@ module.factory('ApplicationClaims', function($resource) {
}); });
module.factory('ApplicationSessionStats', 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', realm : '@realm',
application : "@application" application : "@application"
}); });
}); });
module.factory('ApplicationSessionStatsWithUsers', function($resource) { 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', realm : '@realm',
application : "@application" application : "@application"
}); });
}); });
module.factory('ApplicationLogoutAll', function($resource) { 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', realm : '@realm',
application : "@application" application : "@application"
}); });
}); });
module.factory('ApplicationLogoutUser', function($resource) { 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', realm : '@realm',
application : "@application", application : "@application",
user : "@user" user : "@user"
}); });
}); });
module.factory('RealmLogoutAll', function($resource) { module.factory('RealmLogoutAll', function($resource) {
return $resource(authUrl + '/rest/admin/realms/:realm/logout-all', { return $resource(authUrl + '/admin/realms/:realm/logout-all', {
realm : '@realm' realm : '@realm'
}); });
}); });
module.factory('ApplicationPushRevocation', function($resource) { 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', realm : '@realm',
application : "@application" application : "@application"
}); });
@ -547,7 +551,7 @@ module.factory('ApplicationPushRevocation', function($resource) {
module.factory('Application', 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', realm : '@realm',
application : '@application' application : '@application'
}, { }, {
@ -558,7 +562,7 @@ module.factory('Application', function($resource) {
}); });
module.factory('ApplicationInstallation', 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 { return {
url : function(parameters) url : function(parameters)
{ {
@ -567,7 +571,7 @@ module.factory('ApplicationInstallation', function($resource) {
} }
}); });
module.factory('ApplicationInstallationJBoss', 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 { return {
url : function(parameters) url : function(parameters)
{ {
@ -577,7 +581,7 @@ module.factory('ApplicationInstallationJBoss', function($resource) {
}); });
module.factory('ApplicationCredentials', 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', realm : '@realm',
application : '@application' application : '@application'
}, { }, {
@ -588,7 +592,7 @@ module.factory('ApplicationCredentials', function($resource) {
}); });
module.factory('ApplicationOrigins', 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', realm : '@realm',
application : '@application' application : '@application'
}, { }, {
@ -600,7 +604,7 @@ module.factory('ApplicationOrigins', function($resource) {
}); });
module.factory('OAuthClient', 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', realm : '@realm',
id : '@id' id : '@id'
}, { }, {
@ -611,7 +615,7 @@ module.factory('OAuthClient', function($resource) {
}); });
module.factory('OAuthClientClaims', 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', realm : '@realm',
oauth : "@oauth" oauth : "@oauth"
}, { }, {
@ -623,7 +627,7 @@ module.factory('OAuthClientClaims', function($resource) {
module.factory('OAuthClientCredentials', 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', realm : '@realm',
oauth : '@oauth' oauth : '@oauth'
}, { }, {
@ -635,14 +639,14 @@ module.factory('OAuthClientCredentials', function($resource) {
}); });
module.factory('OAuthClientRealmScopeMapping', 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', realm : '@realm',
oauth : '@oauth' oauth : '@oauth'
}); });
}); });
module.factory('OAuthClientApplicationScopeMapping', function($resource) { 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', realm : '@realm',
oauth : '@oauth', oauth : '@oauth',
targetApp : '@targetApp' targetApp : '@targetApp'
@ -650,8 +654,8 @@ module.factory('OAuthClientApplicationScopeMapping', function($resource) {
}); });
module.factory('OAuthClientInstallation', function($resource) { module.factory('OAuthClientInstallation', function($resource) {
var url = authUrl + '/rest/admin/realms/:realm/oauth-clients/:oauth/installation'; var url = authUrl + '/admin/realms/:realm/oauth-clients/:oauth/installation';
var resource = $resource(authUrl + '/rest/admin/realms/:realm/oauth-clients/:oauth/installation', { var resource = $resource(authUrl + '/admin/realms/:realm/oauth-clients/:oauth/installation', {
realm : '@realm', realm : '@realm',
oauth : '@oauth' oauth : '@oauth'
}, { }, {

View file

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

View file

@ -5,7 +5,7 @@ package org.keycloak.models;
* @version $Revision: 1 $ * @version $Revision: 1 $
*/ */
public interface Constants { public interface Constants {
String ADMIN_CONSOLE_APPLICATION = "admin-console"; String ADMIN_CONSOLE_APPLICATION = "security-admin-console";
String ACCOUNT_MANAGEMENT_APP = "account"; 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.Cookie;
import javax.ws.rs.core.HttpHeaders; import javax.ws.rs.core.HttpHeaders;
import javax.ws.rs.core.NewCookie; import javax.ws.rs.core.NewCookie;
import javax.ws.rs.core.UriInfo;
import java.net.URI; import java.net.URI;
/** /**
@ -25,151 +26,32 @@ import java.net.URI;
public class AppAuthManager extends AuthenticationManager { public class AppAuthManager extends AuthenticationManager {
protected static Logger logger = Logger.getLogger(AppAuthManager.class); protected static Logger logger = Logger.getLogger(AppAuthManager.class);
private String cookieName; public AppAuthManager(ProviderSession providerSession) {
private TokenManager tokenManager;
public AppAuthManager(ProviderSession providerSession, String cookieName, TokenManager tokenManager) {
super(providerSession); super(providerSession);
this.cookieName = cookieName;
this.tokenManager = tokenManager;
} }
public NewCookie createCookie(RealmModel realm, ClientModel client, String code, URI uri) { public UserModel authenticateRequest(RealmModel realm, UriInfo uriInfo, HttpHeaders headers) {
JWSInput input = new JWSInput(code); UserModel user = authenticateIdentityCookie(realm, uriInfo, headers);
boolean verifiedCode = false; if (user != null) return user;
try { return authenticateBearerToken(realm, uriInfo, headers);
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 NewCookie createRefreshCookie(RealmModel realm, UserModel user, ClientModel client, URI uri) { public String extractAuthorizationHeaderToken(HttpHeaders headers) {
return createLoginCookie(realm, user, client, cookieName, uri.getRawPath(), false); String tokenString = null;
}
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;
String authHeader = headers.getRequestHeaders().getFirst(HttpHeaders.AUTHORIZATION); String authHeader = headers.getRequestHeaders().getFirst(HttpHeaders.AUTHORIZATION);
if (authHeader == null) { if (authHeader != null) {
return null;
} else {
String[] split = authHeader.trim().split("\\s+"); String[] split = authHeader.trim().split("\\s+");
if (split == null || split.length != 2) throw new UnauthorizedException("Bearer"); if (split == null || split.length != 2) throw new UnauthorizedException("Bearer");
if (!split[0].equalsIgnoreCase("Bearer")) throw new UnauthorizedException("Bearer"); if (!split[0].equalsIgnoreCase("Bearer")) throw new UnauthorizedException("Bearer");
tokenString = split[1]; tokenString = split[1];
} }
return tokenString;
}
try { public UserModel authenticateBearerToken(RealmModel realm, UriInfo uriInfo, HttpHeaders headers) {
AccessToken token = RSATokenVerifier.verifyToken(tokenString, realm.getPublicKey(), realm.getName()); String tokenString = extractAuthorizationHeaderToken(headers);
if (!token.isActive()) { if (tokenString == null) return null;
throw new UnauthorizedException("token_expired"); return verifyIdentityToken(realm, uriInfo, true, tokenString);
}
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");
}
} }
} }

View file

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

View file

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

View file

@ -138,7 +138,7 @@ public class AccountService {
this.realm = realm; this.realm = realm;
this.application = application; this.application = application;
this.audit = audit; this.audit = audit;
this.authManager = new AppAuthManager(providers, KEYCLOAK_ACCOUNT_IDENTITY_COOKIE, tokenManager); this.authManager = new AppAuthManager(providers);
this.socialRequestManager = socialRequestManager; this.socialRequestManager = socialRequestManager;
} }
@ -148,8 +148,9 @@ public class AccountService {
account = AccountLoader.load().createAccount(uriInfo).setRealm(realm); account = AccountLoader.load().createAccount(uriInfo).setRealm(realm);
boolean passwordUpdateSupported = false; boolean passwordUpdateSupported = false;
auth = authManager.authenticate(realm, headers); UserModel user = authManager.authenticateRequest(realm, uriInfo, headers);
if (auth != null) { if (user != null) {
auth = new Auth(realm, user, application);
account.setUser(auth.getUser()); account.setUser(auth.getUser());
AuthenticationLinkModel authLinkModel = realm.getAuthenticationLink(auth.getUser()); AuthenticationLinkModel authLinkModel = realm.getAuthenticationLink(auth.getUser());
@ -481,20 +482,19 @@ public class AccountService {
redirectUri = redirectUri.resolve("?referrer=" + referrer); redirectUri = redirectUri.resolve("?referrer=" + referrer);
} }
NewCookie cookie = authManager.createCookie(realm, application, code, Urls.accountBase(uriInfo.getBaseUri()).build(realm.getName())); return Response.status(302).location(redirectUri).build();
return Response.status(302).cookie(cookie).location(redirectUri).build();
} finally { } finally {
authManager.expireCookie(Urls.accountBase(uriInfo.getBaseUri()).build(realm.getName()));
} }
} }
@Path("logout") @Path("logout")
@GET @GET
public Response logout() { public Response logout() {
URI baseUri = Urls.accountBase(uriInfo.getBaseUri()).build(realm.getName()); URI redirect = Urls.accountBase(uriInfo.getBaseUri()).build(realm.getName());
authManager.expireIdentityCookie(realm, uriInfo);
authManager.expireCookie(baseUri); return Response.status(302).location(
return Response.status(302).location(baseUri).build(); TokenService.logoutUrl(uriInfo).queryParam("redirect_uri", redirect.toString()).build(realm.getName())
).build();
} }
private Response login(String path) { 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.RealmManager;
import org.keycloak.services.managers.SocialRequestManager; import org.keycloak.services.managers.SocialRequestManager;
import org.keycloak.services.managers.TokenManager; 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.models.utils.ModelProviderUtils;
import org.keycloak.timer.TimerProvider; import org.keycloak.timer.TimerProvider;
import org.keycloak.timer.TimerProviderFactory; import org.keycloak.timer.TimerProviderFactory;
@ -82,11 +82,10 @@ public class KeycloakApplication extends Application {
SocialRequestManager socialRequestManager = new SocialRequestManager(); SocialRequestManager socialRequestManager = new SocialRequestManager();
singletons.add(new RealmsResource(tokenManager, socialRequestManager)); singletons.add(new RealmsResource(tokenManager, socialRequestManager));
singletons.add(new AdminService(tokenManager));
singletons.add(new SocialResource(tokenManager, socialRequestManager)); singletons.add(new SocialResource(tokenManager, socialRequestManager));
singletons.add(new AdminRoot(tokenManager));
classes.add(SkeletonKeyContextResolver.class); classes.add(SkeletonKeyContextResolver.class);
classes.add(QRCodeResource.class); classes.add(QRCodeResource.class);
classes.add(AdminResource.class);
classes.add(ThemeResource.class); classes.add(ThemeResource.class);
classes.add(JsResource.class); classes.add(JsResource.class);
classes.add(WelcomeResource.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.jboss.resteasy.annotations.cache.NoCache;
import org.keycloak.models.RealmModel; import org.keycloak.models.RealmModel;
import org.keycloak.representations.idm.PublishedRealmRepresentation; 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.GET;
import javax.ws.rs.PathParam; import javax.ws.rs.PathParam;
@ -38,9 +38,9 @@ public class PublicRealmResource {
public static PublishedRealmRepresentation realmRep(RealmModel realm, UriInfo uriInfo) { public static PublishedRealmRepresentation realmRep(RealmModel realm, UriInfo uriInfo) {
PublishedRealmRepresentation rep = new PublishedRealmRepresentation(); PublishedRealmRepresentation rep = new PublishedRealmRepresentation();
rep.setRealm(realm.getName()); rep.setRealm(realm.getName());
rep.setTokenServiceUrl(TokenService.tokenServiceBaseUrl(uriInfo).build(realm.getId()).toString()); rep.setTokenServiceUrl(TokenService.tokenServiceBaseUrl(uriInfo).build(realm.getName()).toString());
rep.setAccountServiceUrl(AccountService.accountServiceBaseUrl(uriInfo).build(realm.getId()).toString()); rep.setAccountServiceUrl(AccountService.accountServiceBaseUrl(uriInfo).build(realm.getName()).toString());
rep.setAdminApiUrl(AdminService.adminApiUrl(uriInfo).build(realm.getId()).toString()); rep.setAdminApiUrl(uriInfo.getBaseUriBuilder().path(AdminRoot.class).build().toString());
rep.setPublicKeyPem(realm.getPublicKeyPem()); rep.setPublicKeyPem(realm.getPublicKeyPem());
rep.setNotBefore(realm.getNotBefore()); rep.setNotBefore(realm.getNotBefore());
return rep; return rep;

View file

@ -74,7 +74,6 @@ public class RealmsResource {
public static UriBuilder accountUrl(UriBuilder base) { public static UriBuilder accountUrl(UriBuilder base) {
return base.path(RealmsResource.class).path(RealmsResource.class, "getAccountService"); return base.path(RealmsResource.class).path(RealmsResource.class, "getAccountService");
} }
@Path("{realm}/tokens") @Path("{realm}/tokens")
public TokenService getTokenService(final @PathParam("realm") String name) { public TokenService getTokenService(final @PathParam("realm") String name) {
RealmManager realmManager = new RealmManager(session); RealmManager realmManager = new RealmManager(session);
@ -124,13 +123,6 @@ public class RealmsResource {
return realmResource; 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> * @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
*/ */
@Path("/rest/social") @Path("/social")
public class SocialResource { public class SocialResource {
protected static Logger logger = Logger.getLogger(SocialResource.class); 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> * @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
*/ */
@Path("/rest/theme") @Path("/theme")
public class ThemeResource { public class ThemeResource {
private static final Logger logger = Logger.getLogger(ThemeResource.class); 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 @NoCache
@Produces("application/json") @Produces("application/json")
public List<RealmRepresentation> getRealms() { public List<RealmRepresentation> getRealms() {
logger.debug(("getRealms()")); RealmManager realmManager = new RealmManager(session);
List<RealmModel> realms = session.getRealms();
List<RealmRepresentation> reps = new ArrayList<RealmRepresentation>(); List<RealmRepresentation> reps = new ArrayList<RealmRepresentation>();
for (RealmModel realm : realms) { if (auth.getRealm().equals(realmManager.getKeycloakAdminstrationRealm())) {
if (auth.hasAppRole(realm.getAdminApp(), AdminRoles.MANAGE_REALM)) { List<RealmModel> realms = session.getRealms();
reps.add(ModelToRepresentation.toRepresentation(realm)); for (RealmModel realm : realms) {
} else if (auth.hasOneOfAppRole(realm.getAdminApp(), AdminRoles.ALL_REALM_ROLES)) { addRealmRep(reps, realm);
RealmRepresentation rep = new RealmRepresentation();
rep.setRealm(realm.getName());
reps.add(rep);
} }
} else {
addRealmRep(reps, auth.getRealm());
} }
logger.debug(("getRealms()"));
return reps; return reps;
} }
public static UriBuilder realmUrl(UriInfo uriInfo) { protected void addRealmRep(List<RealmRepresentation> reps, RealmModel realm) {
return realmsUrl(uriInfo).path("{id}"); if (auth.hasAppRole(realm.getAdminApp(), AdminRoles.MANAGE_REALM)) {
} reps.add(ModelToRepresentation.toRepresentation(realm));
} else if (auth.hasOneOfAppRole(realm.getAdminApp(), AdminRoles.ALL_REALM_ROLES)) {
public static UriBuilder realmsUrl(UriInfo uriInfo) { RealmRepresentation rep = new RealmRepresentation();
return uriInfo.getBaseUriBuilder().path(AdminService.class).path(AdminService.class, "getRealmsAdmin"); rep.setRealm(realm.getName());
reps.add(rep);
}
} }
@POST @POST
@Consumes("application/json") @Consumes("application/json")
public Response importRealm(@Context final UriInfo uriInfo, final RealmRepresentation rep) { 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)) { if (!auth.hasRealmRole(AdminRoles.CREATE_REALM)) {
throw new ForbiddenException(); throw new ForbiddenException();
} }
logger.debugv("importRealm: {0}", rep.getRealm()); logger.debugv("importRealm: {0}", rep.getRealm());
RealmManager realmManager = new RealmManager(session);
try { try {
RealmModel realm = realmManager.importRealm(rep); RealmModel realm = realmManager.importRealm(rep);
grantPermissionsToRealmCreator(realm); 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()); logger.debugv("imported realm success, sending back: {0}", location.toString());
return Response.created(location).build(); return Response.created(location).build();
} catch (ModelDuplicateException e) { } catch (ModelDuplicateException e) {
@ -120,6 +124,10 @@ public class RealmsAdminResource {
@POST @POST
@Consumes(MediaType.MULTIPART_FORM_DATA) @Consumes(MediaType.MULTIPART_FORM_DATA)
public Response uploadRealm(@Context final UriInfo uriInfo, MultipartFormDataInput input) throws IOException { 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)) { if (!auth.hasRealmRole(AdminRoles.CREATE_REALM)) {
throw new ForbiddenException(); throw new ForbiddenException();
} }
@ -127,7 +135,6 @@ public class RealmsAdminResource {
Map<String, List<InputPart>> uploadForm = input.getFormDataMap(); Map<String, List<InputPart>> uploadForm = input.getFormDataMap();
List<InputPart> inputParts = uploadForm.get("file"); List<InputPart> inputParts = uploadForm.get("file");
RealmManager realmManager = new RealmManager(session);
for (InputPart inputPart : inputParts) { for (InputPart inputPart : inputParts) {
inputPart.setMediaType(MediaType.APPLICATION_JSON_TYPE); inputPart.setMediaType(MediaType.APPLICATION_JSON_TYPE);
RealmRepresentation rep = inputPart.getBody(new GenericType<RealmRepresentation>() { RealmRepresentation rep = inputPart.getBody(new GenericType<RealmRepresentation>() {
@ -143,7 +150,7 @@ public class RealmsAdminResource {
grantPermissionsToRealmCreator(realm); grantPermissionsToRealmCreator(realm);
if (inputParts.size() == 1) { 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(); return Response.created(location).build();
} }
} }
@ -172,6 +179,10 @@ public class RealmsAdminResource {
RealmModel realm = realmManager.getRealmByName(name); RealmModel realm = realmManager.getRealmByName(name);
if (realm == null) throw new NotFoundException("{realm} = " + 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()); RealmAuth realmAuth = new RealmAuth(auth, realm.getAdminApp());
RealmAdminResource adminResource = new RealmAdminResource(realmAuth, realm, tokenManager); 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.AccountService;
import org.keycloak.services.resources.ThemeResource; import org.keycloak.services.resources.ThemeResource;
import org.keycloak.services.resources.admin.AdminService;
import org.keycloak.services.resources.RealmsResource; import org.keycloak.services.resources.RealmsResource;
import org.keycloak.services.resources.RequiredActionsService; import org.keycloak.services.resources.RequiredActionsService;
import org.keycloak.services.resources.SocialResource; import org.keycloak.services.resources.SocialResource;
import org.keycloak.services.resources.TokenService; import org.keycloak.services.resources.TokenService;
import javax.ws.rs.core.UriBuilder; import javax.ws.rs.core.UriBuilder;
import javax.ws.rs.core.UriInfo;
import java.net.URI; import java.net.URI;
/** /**
@ -146,26 +144,6 @@ public class Urls {
return tokenBase(baseUri).path(TokenService.class, "accessCodeToToken").build(realmId); 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) { public static UriBuilder socialBase(URI baseUri) {
return UriBuilder.fromUri(baseUri).path(SocialResource.class); return UriBuilder.fromUri(baseUri).path(SocialResource.class);
} }

View file

@ -170,6 +170,9 @@ public class AssertEvents implements TestRule, AuditListenerFactory {
return new AuditListener() { return new AuditListener() {
@Override @Override
public void onEvent(Event event) { public void onEvent(Event event) {
if (event == null) {
throw new RuntimeException("Added null event");
}
events.add(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.representations.idm.CredentialRepresentation;
import org.keycloak.services.managers.RealmManager; import org.keycloak.services.managers.RealmManager;
import org.keycloak.services.resources.AccountService; import org.keycloak.services.resources.AccountService;
import org.keycloak.services.resources.RealmsResource;
import org.keycloak.testsuite.AssertEvents; import org.keycloak.testsuite.AssertEvents;
import org.keycloak.testsuite.OAuthClient; import org.keycloak.testsuite.OAuthClient;
import org.keycloak.testsuite.Retry; 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 @Rule
public AssertEvents events = new AssertEvents(keycloakRule); public AssertEvents events = new AssertEvents(keycloakRule);
@ -209,6 +212,8 @@ public class AccountTest {
changePasswordPage.logout(); changePasswordPage.logout();
events.expectLogout().detail(Details.REDIRECT_URI, ACCOUNT_URL).assertEvent();
loginPage.open(); loginPage.open();
loginPage.login("test-user@localhost", "password"); loginPage.login("test-user@localhost", "password");
@ -378,8 +383,6 @@ public class AccountTest {
logPage.open(); logPage.open();
e.add(events.poll());
Collections.reverse(e); Collections.reverse(e);
Assert.assertTrue(logPage.isCurrent()); Assert.assertTrue(logPage.isCurrent());

View file

@ -188,10 +188,6 @@ public class RequiredActionTotpSetupTest {
accountTotpPage.open(); accountTotpPage.open();
accountTotpPage.assertCurrent(); 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 // Remove google authentificator
accountTotpPage.removeTotp(); 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.RealmManager;
import org.keycloak.services.managers.TokenManager; import org.keycloak.services.managers.TokenManager;
import org.keycloak.services.resources.TokenService; 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.OAuthClient;
import org.keycloak.testsuite.pages.LoginPage; import org.keycloak.testsuite.pages.LoginPage;
import org.keycloak.testsuite.rule.AbstractKeycloakRule; import org.keycloak.testsuite.rule.AbstractKeycloakRule;
@ -123,7 +125,8 @@ public class AdapterTest {
// View stats // View stats
Client client = ClientBuilder.newClient(); 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() Map<String, SessionStats> stats = adminTarget.path("session-stats").request()
.header(HttpHeaders.AUTHORIZATION, "Bearer " + adminToken) .header(HttpHeaders.AUTHORIZATION, "Bearer " + adminToken)
.get(new GenericType<Map<String, SessionStats>>(){}); .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.RealmManager;
import org.keycloak.services.managers.TokenManager; import org.keycloak.services.managers.TokenManager;
import org.keycloak.services.resources.TokenService; import org.keycloak.services.resources.TokenService;
import org.keycloak.services.resources.admin.AdminRoot;
import org.keycloak.testsuite.OAuthClient; import org.keycloak.testsuite.OAuthClient;
import org.keycloak.testsuite.pages.LoginPage; import org.keycloak.testsuite.pages.LoginPage;
import org.keycloak.testsuite.rule.AbstractKeycloakRule; import org.keycloak.testsuite.rule.AbstractKeycloakRule;
@ -126,7 +127,8 @@ public class RelativeUriAdapterTest {
// View stats // View stats
Client client = ClientBuilder.newClient(); 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() Map<String, SessionStats> stats = adminTarget.path("session-stats").request()
.header(HttpHeaders.AUTHORIZATION, "Bearer " + adminToken) .header(HttpHeaders.AUTHORIZATION, "Bearer " + adminToken)
.get(new GenericType<Map<String, SessionStats>>(){}); .get(new GenericType<Map<String, SessionStats>>(){});

View file

@ -92,7 +92,6 @@ public class SSOTest {
Assert.assertTrue(profilePage.isCurrent()); 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("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();
} }
} }