admin cors support

This commit is contained in:
Bill Burke 2014-05-23 16:02:14 -04:00
commit 54cc095ff5
29 changed files with 425 additions and 473 deletions

View file

@ -48,12 +48,12 @@
"name": "js-console",
"enabled": true,
"publicClient": true,
"baseUrl": "http://localhost/js-console",
"baseUrl": "http://localhost:8080/js-console",
"redirectUris": [
"http://localhost/js-console/*"
"http://localhost:8080/js-console/*"
],
"webOrigins": [
"http://localhost"
"http://localhost:8080"
]
}
],

View file

@ -1,13 +1,13 @@
<html>
<head>
<script src="//localhost:8081/auth/js/keycloak.js"></script>
<script src="//localhost:8080/auth/js/keycloak.js"></script>
</head>
<body>
<div>
<button onclick="keycloak.login()">Login</button>
<button onclick="keycloak.logout()">Logout</button>
<button onclick="refreshToken()">Refresh Token</button>
<button onclick="refreshToken(9999)">Refresh Token</button>
<button onclick="refreshToken(30)">Refresh Token (if <30s validity)</button>
<button onclick="loadProfile()">Get Profile</button>
<button onclick="output(keycloak.tokenParsed)">Show Token</button>

View file

@ -1,8 +1,8 @@
{
"realm" : "example",
"realm-public-key" : "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCrVrCuTtArbgaZzL1hvh0xtL5mc7o0NqPVnYXkLvgcwiC3BjLGw1tGEGoJaXDuSaRllobm53JBhjx33UNv+5z/UMG4kytBWxheNVKnL6GgqlNabMaFfPLPCF8kAgKnsi79NMo+n6KnSY8YeUmec/p2vjO2NjsSAVcWEQMVhJ31LwIDAQAB",
"auth-server-url" : "http://localhost:8081/auth",
"auth-server-url" : "http://localhost:8080/auth",
"ssl-not-required" : true,
"resource" : "js-console",
"public-client" : true
}
}

View file

@ -151,7 +151,7 @@ public class ModelImporter {
}
}
logger.infof("%d roles imported: ", roles);
logger.infof("%d roles imported: ", roles.size());
if (logger.isDebugEnabled()) {
logger.debug("Imported roles: " + roles);
}
@ -225,7 +225,7 @@ public class ModelImporter {
addScopes(realm, client, clientEntity);
}
logger.infof("OAuth clients imported: " + clients);
logger.info("OAuth clients imported: " + clients);
}
protected ApplicationModel findApplicationById(KeycloakSession keycloakSession, String applicationId) {

View file

@ -38,7 +38,7 @@
</style>
</head>
<body class="admin-console" data-ng-controller="GlobalCtrl" data-ng-cloak>
<body class="admin-console" data-ng-controller="GlobalCtrl" data-ng-cloak data-ng-show="auth.user">
<div id="idletimeout">
You will be logged off in <strong><span></span> seconds</strong> due to inactivity.

View file

@ -1,6 +1,5 @@
'use strict';
var indexUrl = window.location.href;
var consoleBaseUrl = window.location.href;
consoleBaseUrl = consoleBaseUrl.substring(0, consoleBaseUrl.indexOf("/console"));
consoleBaseUrl = consoleBaseUrl + "/console";
@ -23,14 +22,12 @@ var loadingTimer = -1;
angular.element(document).ready(function ($http) {
var keycloakAuth = new Keycloak(configUrl);
auth.loggedIn = false;
keycloakAuth.onAuthLogout = function() {
location.reload();
}
keycloakAuth.init({ onLoad: 'login-required' }).success(function () {
auth.loggedIn = true;
auth.authz = keycloakAuth;
module.factory('Auth', function() {
return auth;

View file

@ -195,7 +195,7 @@ module.controller('ApplicationInstallationCtrl', function($scope, realm, applica
});
module.controller('ApplicationDetailCtrl', function($scope, $document, realm, application, Application, $location, Dialog, Notifications) {
module.controller('ApplicationDetailCtrl', function($scope, realm, application, Application, $location, Dialog, Notifications) {
console.log('ApplicationDetailCtrl');
$scope.clientTypes = [
@ -263,21 +263,10 @@ module.controller('ApplicationDetailCtrl', function($scope, $document, realm, ap
}
$scope.save = function() {
if ($scope.create) {
if (!$scope.application.bearerOnly && (!$scope.application.redirectUris || $scope.application.redirectUris.length == 0)) {
Notifications.error("You must specify at least one redirect uri");
} else {
// automatically add redirects to web origins
var parser = document.createElement('a');
var originSet = {};
for (var i = 0; i < $scope.application.redirectUris.length; i++) {
parser.href = $scope.application.redirectUris[i];
var origin = parser.protocol + "//" + parser.host;
originSet[origin] = true;
}
for (var key in originSet) {
$scope.application.webOrigins.push(key);
}
if (!$scope.application.bearerOnly && (!$scope.application.redirectUris || $scope.application.redirectUris.length == 0)) {
Notifications.error("You must specify at least one redirect uri");
} else {
if ($scope.create) {
Application.save({
realm: realm.realm,
application: ''
@ -288,16 +277,16 @@ module.controller('ApplicationDetailCtrl', function($scope, $document, realm, ap
$location.url("/realms/" + realm.realm + "/applications/" + id);
Notifications.success("The application has been created.");
});
} else {
Application.update({
realm : realm.realm,
application : application.name
}, $scope.application, function() {
$scope.changed = false;
application = angular.copy($scope.application);
Notifications.success("Your changes have been saved to the application.");
});
}
} else {
Application.update({
realm : realm.realm,
application : application.name
}, $scope.application, function() {
$scope.changed = false;
application = angular.copy($scope.application);
Notifications.success("Your changes have been saved to the application.");
});
}
};
@ -342,195 +331,71 @@ module.controller('ApplicationScopeMappingCtrl', function($scope, $http, realm,
$scope.applicationMappings = [];
$scope.dummymodel = [];
function updateRealmRoles() {
$scope.realmRoles = ApplicationAvailableRealmScopeMapping.query({realm : realm.realm, application : application.name});
$scope.realmMappings = ApplicationRealmScopeMapping.query({realm : realm.realm, application : application.name});
$scope.realmComposite = ApplicationCompositeRealmScopeMapping.query({realm : realm.realm, application : application.name});
}
$scope.realmMappings = ApplicationRealmScopeMapping.query({realm : realm.realm, application : application.name}, function(){
for (var i = 0; i < $scope.realmMappings.length; i++) {
var role = $scope.realmMappings[i];
for (var j = 0; j < $scope.realmRoles.length; j++) {
var realmRole = $scope.realmRoles[j];
if (realmRole.id == role.id) {
var idx = $scope.realmRoles.indexOf(realmRole);
if (idx != -1) {
$scope.realmRoles.splice(idx, 1);
break;
}
}
}
}
});
$scope.addRealmRole = function() {
$http.post(authUrl + '/admin/realms/' + realm.realm + '/applications/' + application.name + '/scope-mappings/realm',
$scope.selectedRealmRoles).success(function() {
for (var i = 0; i < $scope.selectedRealmRoles.length; i++) {
var role = $scope.selectedRealmRoles[i];
var idx = $scope.realmRoles.indexOf($scope.selectedRealmRoles[i]);
if (idx != -1) {
$scope.realmRoles.splice(idx, 1);
$scope.realmMappings.push(role);
}
}
$scope.selectRealmRoles = [];
});
};
$scope.deleteRealmRole = function() {
$http.delete(authUrl + '/admin/realms/' + realm.realm + '/applications/' + application.name + '/scope-mappings/realm',
{data : $scope.selectedRealmMappings, headers : {"content-type" : "application/json"}}).success(function() {
for (var i = 0; i < $scope.selectedRealmMappings.length; i++) {
var role = $scope.selectedRealmMappings[i];
var idx = $scope.realmMappings.indexOf($scope.selectedRealmMappings[i]);
if (idx != -1) {
$scope.realmMappings.splice(idx, 1);
$scope.realmRoles.push(role);
}
}
$scope.selectedRealmMappings = [];
});
};
$scope.addApplicationRole = function() {
$http.post(authUrl + '/admin/realms/' + realm.realm + '/applications/' + application.name + '/scope-mappings/applications/' + $scope.targetApp.name,
$scope.selectedApplicationRoles).success(function() {
for (var i = 0; i < $scope.selectedApplicationRoles.length; i++) {
var role = $scope.selectedApplicationRoles[i];
var idx = $scope.applicationRoles.indexOf($scope.selectedApplicationRoles[i]);
if (idx != -1) {
$scope.applicationRoles.splice(idx, 1);
$scope.applicationMappings.push(role);
}
}
$scope.selectedApplicationRoles = [];
});
};
$scope.deleteApplicationRole = function() {
$http.delete(authUrl + '/admin/realms/' + realm.realm + '/applications/' + application.name + '/scope-mappings/applications/' + $scope.targetApp.name,
{data : $scope.selectedApplicationMappings, headers : {"content-type" : "application/json"}}).success(function() {
for (var i = 0; i < $scope.selectedApplicationMappings.length; i++) {
var role = $scope.selectedApplicationMappings[i];
var idx = $scope.applicationMappings.indexOf($scope.selectedApplicationMappings[i]);
if (idx != -1) {
$scope.applicationMappings.splice(idx, 1);
$scope.applicationRoles.push(role);
}
}
$scope.selectedApplicationMappings = [];
});
};
$scope.changeApplication = function() {
function updateAppRoles() {
if ($scope.targetApp) {
$scope.applicationRoles = ApplicationRole.query({realm : realm.realm, application : $scope.targetApp.name}, function() {
$scope.applicationMappings = ApplicationApplicationScopeMapping.query({realm : realm.realm, application : application.name, targetApp : $scope.targetApp.name}, function(){
for (var i = 0; i < $scope.applicationMappings.length; i++) {
var role = $scope.applicationMappings[i];
for (var j = 0; j < $scope.applicationRoles.length; j++) {
var realmRole = $scope.applicationRoles[j];
if (realmRole.id == role.id) {
var idx = $scope.applicationRoles.indexOf(realmRole);
if (idx != -1) {
$scope.applicationRoles.splice(idx, 1);
break;
}
}
}
}
});
}
);
} else {
$scope.applicationRoles = null;
}
};
$scope.realmMappings = ApplicationRealmScopeMapping.query({realm : realm.realm, application : application.name});
$scope.realmRoles = ApplicationAvailableRealmScopeMapping.query({realm : realm.realm, application : application.name});
$scope.realmComposite = ApplicationCompositeRealmScopeMapping.query({realm : realm.realm, application : application.name});
$scope.addRealmRole = function() {
$http.post(authUrl + '/admin/realms/' + realm.realm + '/applications/' + application.name + '/scope-mappings/realm',
$scope.selectedRealmRoles).success(function() {
$scope.realmMappings = ApplicationRealmScopeMapping.query({realm : realm.realm, application : application.name});
$scope.realmRoles = ApplicationAvailableRealmScopeMapping.query({realm : realm.realm, application : application.name});
$scope.realmComposite = ApplicationCompositeRealmScopeMapping.query({realm : realm.realm, application : application.name});
$scope.selectedRealmMappings = [];
$scope.selectRealmRoles = [];
if ($scope.targetApp) {
console.log('load available');
$scope.applicationMappings = ApplicationApplicationScopeMapping.query({realm : realm.realm, application : application.name, targetApp : $scope.targetApp.name});
$scope.applicationRoles = ApplicationAvailableApplicationScopeMapping.query({realm : realm.realm, application : application.name, targetApp : $scope.targetApp.name});
$scope.applicationComposite = ApplicationCompositeApplicationScopeMapping.query({realm : realm.realm, application : application.name, targetApp : $scope.targetApp.name});
$scope.selectedApplicationRoles = [];
$scope.selectedApplicationMappings = [];
}
});
};
$scope.deleteRealmRole = function() {
$http.delete(authUrl + '/admin/realms/' + realm.realm + '/applications/' + application.name + '/scope-mappings/realm',
{data : $scope.selectedRealmMappings, headers : {"content-type" : "application/json"}}).success(function() {
$scope.realmMappings = ApplicationRealmScopeMapping.query({realm : realm.realm, application : application.name});
$scope.realmRoles = ApplicationAvailableRealmScopeMapping.query({realm : realm.realm, application : application.name});
$scope.realmComposite = ApplicationCompositeRealmScopeMapping.query({realm : realm.realm, application : application.name});
$scope.selectedRealmMappings = [];
$scope.selectRealmRoles = [];
if ($scope.targetApp) {
console.log('load available');
$scope.applicationMappings = ApplicationApplicationScopeMapping.query({realm : realm.realm, application : application.name, targetApp : $scope.targetApp.name});
$scope.applicationRoles = ApplicationAvailableApplicationScopeMapping.query({realm : realm.realm, application : application.name, targetApp : $scope.targetApp.name});
$scope.applicationComposite = ApplicationCompositeApplicationScopeMapping.query({realm : realm.realm, application : application.name, targetApp : $scope.targetApp.name});
$scope.selectedApplicationRoles = [];
$scope.selectedApplicationMappings = [];
}
});
};
$scope.addApplicationRole = function() {
$http.post(authUrl + '/admin/realms/' + realm.realm + '/applications/' + application.name + '/scope-mappings/applications/' + $scope.targetApp.name,
$scope.selectedApplicationRoles).success(function() {
$scope.applicationMappings = ApplicationRoleMapping.query({realm : realm.realm, userId : user.username, application : $scope.application.name});
$scope.applicationRoles = AvailableApplicationRoleMapping.query({realm : realm.realm, userId : user.username, application : $scope.application.name});
$scope.applicationComposite = CompositeApplicationRoleMapping.query({realm : realm.realm, userId : user.username, application : $scope.application.name});
$scope.selectedApplicationRoles = [];
$scope.selectedApplicationMappings = [];
});
};
$scope.deleteApplicationRole = function() {
$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() {
$scope.applicationMappings = ApplicationRoleMapping.query({realm : realm.realm, userId : user.username, application : $scope.application.name});
$scope.applicationRoles = AvailableApplicationRoleMapping.query({realm : realm.realm, userId : user.username, application : $scope.application.name});
$scope.applicationComposite = CompositeApplicationRoleMapping.query({realm : realm.realm, userId : user.username, application : $scope.application.name});
$scope.selectedApplicationRoles = [];
$scope.selectedApplicationMappings = [];
});
};
$scope.changeApplication = function() {
console.log('changeApplication');
if ($scope.targetApp) {
console.log('load available');
$scope.applicationMappings = ApplicationApplicationScopeMapping.query({realm : realm.realm, application : application.name, targetApp : $scope.targetApp.name});
console.debug($scope.targetApp.name);
$scope.applicationRoles = ApplicationAvailableApplicationScopeMapping.query({realm : realm.realm, application : application.name, targetApp : $scope.targetApp.name});
$scope.applicationMappings = ApplicationApplicationScopeMapping.query({realm : realm.realm, application : application.name, targetApp : $scope.targetApp.name});
$scope.applicationComposite = ApplicationCompositeApplicationScopeMapping.query({realm : realm.realm, application : application.name, targetApp : $scope.targetApp.name});
} else {
$scope.applicationRoles = null;
$scope.applicationMappings = null;
$scope.applicationComposite = null;
}
$scope.selectedApplicationRoles = [];
$scope.selectedApplicationMappings = [];
}
$scope.addRealmRole = function() {
$http.post(authUrl + '/admin/realms/' + realm.realm + '/applications/' + application.name + '/scope-mappings/realm', $scope.selectedRealmRoles)
.success(updateRealmRoles);
};
$scope.deleteRealmRole = function() {
$http.delete(authUrl + '/admin/realms/' + realm.realm + '/applications/' + application.name + '/scope-mappings/realm',
{data : $scope.selectedRealmMappings, headers : {"content-type" : "application/json"}})
.success(updateRealmRoles);
};
$scope.addApplicationRole = function() {
$http.post(authUrl + '/admin/realms/' + realm.realm + '/applications/' + application.name + '/scope-mappings/applications/' + $scope.targetApp.name,
$scope.selectedApplicationRoles).success(updateAppRoles);
};
$scope.deleteApplicationRole = function() {
$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(updateAppRoles);
};
$scope.changeApplication = function() {
updateAppRoles();
};
$scope.addRealmRole = function() {
$http.post(authUrl + '/admin/realms/' + realm.realm + '/applications/' + application.name + '/scope-mappings/realm',
$scope.selectedRealmRoles).success(updateRealmRoles);
};
$scope.deleteRealmRole = function() {
$http.delete(authUrl + '/admin/realms/' + realm.realm + '/applications/' + application.name + '/scope-mappings/realm',
{data : $scope.selectedRealmMappings, headers : {"content-type" : "application/json"}}).success(updateRealmRoles);
};
$scope.addApplicationRole = function() {
$http.post(authUrl + '/admin/realms/' + realm.realm + '/applications/' + application.name + '/scope-mappings/applications/' + $scope.targetApp.name,
$scope.selectedApplicationRoles).success(updateAppRoles);
};
$scope.deleteApplicationRole = function() {
$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(updateAppRoles);
};
updateRealmRoles();
});
module.controller('ApplicationRevocationCtrl', function($scope, realm, application, Application, ApplicationPushRevocation, $location, Dialog, Notifications) {

View file

@ -133,25 +133,29 @@ module.controller('OAuthClientDetailCtrl', function($scope, realm, oauth, OAuthC
}
$scope.save = function() {
if ($scope.create) {
OAuthClient.save({
realm: realm.realm
}, $scope.oauth, function (data, headers) {
$scope.changed = false;
var l = headers().location;
var id = l.substring(l.lastIndexOf("/") + 1);
$location.url("/realms/" + realm.realm + "/oauth-clients/" + id);
Notifications.success("The oauth client has been created.");
});
if (!$scope.oauth.redirectUris || $scope.oauth.redirectUris.length == 0) {
Notifications.error("You must specify at least one redirect uri");
} else {
OAuthClient.update({
realm : realm.realm,
id : oauth.id
}, $scope.oauth, function() {
$scope.changed = false;
oauth = angular.copy($scope.oauth);
Notifications.success("Your changes have been saved to the oauth client.");
});
if ($scope.create) {
OAuthClient.save({
realm: realm.realm
}, $scope.oauth, function (data, headers) {
$scope.changed = false;
var l = headers().location;
var id = l.substring(l.lastIndexOf("/") + 1);
$location.url("/realms/" + realm.realm + "/oauth-clients/" + id);
Notifications.success("The oauth client has been created.");
});
} else {
OAuthClient.update({
realm : realm.realm,
id : oauth.id
}, $scope.oauth, function() {
$scope.changed = false;
oauth = angular.copy($scope.oauth);
Notifications.success("Your changes have been saved to the oauth client.");
});
}
}
};

View file

@ -107,7 +107,7 @@ module.controller('UserSessionsCtrl', function($scope, realm, user, sessions, Us
$scope.logoutAll = function() {
UserLogout.save({realm : realm.realm, user: user.username}, function () {
Notifications.success('Logged out user in all applications');
UserSessions.get({realm: realm.realm, user: user.username}, function(updated) {
UserSessions.query({realm: realm.realm, user: user.username}, function(updated) {
$scope.sessions = updated;
})
});
@ -116,9 +116,9 @@ module.controller('UserSessionsCtrl', function($scope, realm, user, sessions, Us
$scope.logoutSession = function(sessionId) {
console.log('here in logoutSession');
UserSessionLogout.delete({realm : realm.realm, session: sessionId}, function() {
Notifications.success('Logged out session');
UserSessions.get({realm: realm.realm, user: user.username}, function(updated) {
UserSessions.query({realm: realm.realm, user: user.username}, function(updated) {
$scope.sessions = updated;
Notifications.success('Logged out session');
})
});
}

View file

@ -77,8 +77,6 @@ module.service('Dialog', function($modal) {
}
dialog.confirm = function(title, message, success, cancel) {
var title = title;
var msg = '<span class="primary">' + message + '"</span>';
var btns = {
ok: {
label: title,
@ -90,7 +88,7 @@ module.service('Dialog', function($modal) {
}
}
openDialog(title, msg, btns).then(success).reject(cancel);
openDialog(title, message, btns).then(success, cancel);
}
return dialog

View file

@ -92,30 +92,24 @@
</div>
<div class="form-group" data-ng-show="!application.bearerOnly && !create">
<label class="col-sm-2 control-label" for="newWebOrigin">Web Origin</label>
<div class="col-sm-6">
<div ng-repeat="webOrigin in application.webOrigins" class="row kc-item-deletable">
<div class="col-sm-8">
<input class="form-control kc-button-control"
type="text" data-ng-class="{'input-below':!$first}"
name="webOrigin" id="webOrigin"
data-ng-model="webOrigin" readonly/>
</div>
<div class="col-sm-2">
<button class="btn btn-danger"
type="button" data-ng-click="deleteWebOrigin($index)">Delete</button>
</div>
<div class="col-sm-4 multiple" ng-repeat="webOrigin in application.webOrigins">
<div class="input-group kc-item-deletable">
<input class="form-control" type="text" data-ng-class="{'input-below':!$first}"
name="webOrigin" id="webOrigin" data-ng-model="webOrigin" readonly />
<span class="input-group-btn">
<button class="btn btn-default" type="button" data-ng-click="deleteWebOrigin($index)">
Delete</button>
</span>
</div>
<div class="row">
<div class="col-sm-8">
<input class="form-control kc-button-control"
type="text" name="newWebOrigin" id="newWebOrigin"
placeholder="New Web Origin..." data-ng-model="newWebOrigin"
data-ng-class="{'input-below':application.webOrigins.length}"/>
</div>
<div class="col-sm-2">
<button class="btn btn-primary"
data-ng-click="addWebOrigin()" ng-show="newWebOrigin.length > 0">Add</button>
</div>
</div>
<div class="col-sm-4 multiple">
<div class="input-group">
<input class="form-control" type="text" name="newWebOrigin" id="newWebOrigin"
placeholder="New Web Origin..." data-ng-model="newWebOrigin"
data-ng-class="{'input-below':application.webOrigins.length}" />
<span class="input-group-btn">
<button class="btn btn-default" data-ng-click="addWebOrigin()" ng-show="newWebOrigin.length > 0">Add</button>
</span>
</div>
</div>
</div>

View file

@ -12,7 +12,7 @@
</div>
<div class="collapse navbar-collapse navbar-collapse-1">
<div class="container">
<ul class="nav navbar-nav navbar-utility" data-ng-show="auth.loggedIn">
<ul class="nav navbar-nav navbar-utility" data-ng-show="auth.user">
<li class="dropdown">
<a data-toggle="dropdown" class="dropdown-toggle" href="#">
<span class="pficon pficon-user"></span>
@ -36,9 +36,9 @@
</li>
</ul>
</li>
<li class="active pull-right" data-ng-show="auth.loggedIn && access.createRealm">
<li class="active pull-right" data-ng-show="auth.user && access.createRealm">
<a class="button primary" href="#/create/realm" data-ng-class="path[0] == 'create' && path[1] == 'realm' && 'active'"
data-ng-show="auth.loggedIn">Add Realm</a>
data-ng-show="auth.user">Add Realm</a>
</li>
</ul>
</div>

View file

@ -77,26 +77,24 @@
</div>
<div class="form-group">
<label class="col-sm-2 control-label" for="newWebOrigin">Web Origin</label>
<div class="col-sm-6">
<div ng-repeat="webOrigin in oauth.webOrigins" class="kc-item-deletable row">
<div class="col-sm-8">
<input class="form-control" type="text" data-ng-class="{'input-below':!$first}"
name="webOrigin" id="webOrigin" data-ng-model="webOrigin" readonly />
</div>
<div class="col-sm-2">
<button class="btn btn-danger" type="button" data-ng-click="deleteWebOrigin($index)">
<div class="col-sm-4 multiple" ng-repeat="webOrigin in oauth.webOrigins">
<div class="input-group kc-item-deletable">
<input class="form-control" type="text" data-ng-class="{'input-below':!$first}"
name="webOrigin" id="webOrigin" data-ng-model="webOrigin" readonly />
<span class="input-group-btn">
<button class="btn btn-default" type="button" data-ng-click="deleteWebOrigin($index)">
Delete</button>
</div>
</span>
</div>
<div class="row">
<div class="col-sm-8">
<input class="form-control" type="text" name="newWebOrigin" id="newWebOrigin"
placeholder="New Web Origin..." data-ng-model="newWebOrigin"
data-ng-class="{'input-below':oauth.webOrigins.length}" />
</div>
<div class="col-sm-2">
<button class="btn btn-primary" data-ng-click="addWebOrigin()" ng-show="newWebOrigin.length > 0">Add</button>
</div>
</div>
<div class="col-sm-4 multiple">
<div class="input-group">
<input class="form-control" type="text" name="newWebOrigin" id="newWebOrigin"
placeholder="New Web Origin..." data-ng-model="newWebOrigin"
data-ng-class="{'input-below':oauth.webOrigins.length}" />
<span class="input-group-btn">
<button class="btn btn-default" data-ng-click="addWebOrigin()" ng-show="newWebOrigin.length > 0">Add</button>
</span>
</div>
</div>
</div>

View file

@ -1,5 +1,5 @@
<ul data-ng-hide="createRealm">
<li data-ng-show="access.viewRealm" data-ng-class="((!path[2] || path[1] == 'role' || path[2] == 'roles' || path[2] == 'token-settings' ||
<li data-ng-show="access.viewRealm" data-ng-class="((!path[2] || path[1] == 'role' || path[2] == 'roles' ||
path[2] == 'social-settings' || path[2] == 'required-credentials' || path[2] == 'default-roles' || path[2] == 'registration-settings' ||
path[2] == 'keys-settings' || path[2] == 'smtp-settings' || path[2] == 'ldap-settings' || path[2] == 'auth-settings') && path[3] != 'applications') && 'active'">
<a href="#/realms/{{realm.realm}}">Settings</a>
@ -8,6 +8,6 @@
</li>
<li data-ng-show="access.viewApplications" data-ng-class="(path[2] == 'applications' || path[1] == 'application' || path[3] == 'applications') && 'active'"><a href="#/realms/{{realm.realm}}/applications">Applications</a></li>
<li data-ng-show="access.viewClients" data-ng-class="(path[2] == 'oauth-clients' || path[1] == 'oauth-client') && 'active'"><a href="#/realms/{{realm.realm}}/oauth-clients">OAuth Clients</a></li>
<li data-ng-show="access.viewRealm" data-ng-class="(path[2] == 'sessions') && 'active'"><a href="#/realms/{{realm.realm}}/sessions/realm">Sessions and Tokens</a></li>
<li data-ng-show="access.viewRealm" data-ng-class="(path[2] == 'sessions' || path[2] == 'token-settings') && 'active'"><a href="#/realms/{{realm.realm}}/sessions/realm">Sessions and Tokens</a></li>
<li data-ng-show="access.viewAudit" data-ng-class="(path[2] == 'audit' || path[2] == 'audit-settings') && 'active'"><a href="#/realms/{{realm.realm}}/audit">Audit</a></li>
</ul>

View file

@ -38,19 +38,18 @@
<td>{{session.ipAddress}}</td>
<td>{{session.start | date:'medium'}}</td>
<td>{{session.lastAccess | date:'medium'}}</td>
<td><ul style="list-style: none; ">
<li data-ng-repeat="app in session.applications">
<td>
<div data-ng-repeat="app in session.applications">
<a href="#/realms/{{realm.realm}}/applications/{{app}}/sessions">{{app}}</a>
</li>
</div>
</ul>
</td>
<td><ul style="list-style: none; ">
<li data-ng-repeat="(clientId, clientName) in session.clients">
<td>
<div data-ng-repeat="(clientId, clientName) in session.clients">
<a href="#/realms/{{realm.realm}}/oauth-clients/{{clientId}}">{{clientName}}</a>
</li>
</ul>
</div>
</td>
<td><a ng-click="logoutSession(session.id)">logout</a> </td>
<td><a href="" ng-click="logoutSession(session.id)">logout</a> </td>
</tr>
</tbody>
</table>

View file

@ -29,6 +29,10 @@ var Keycloak = function (config) {
if (initOptions.checkLoginIframeInterval) {
loginIframe.interval = initOptions.checkLoginIframeInterval;
}
if (initOptions.onLoad === 'login-required') {
kc.loginRequired = true;
}
}
var promise = createPromise();
@ -374,6 +378,9 @@ var Keycloak = function (config) {
if (kc.token) {
setToken(null, null);
kc.onAuthLogout && kc.onAuthLogout();
if (kc.loginRequired) {
kc.login();
}
}
}
@ -531,7 +538,7 @@ var Keycloak = function (config) {
loginIframe.iframe = iframe;
}
var src = getRealmUrl() + '/login-status-iframe.html?client_id=' + encodeURIComponent(kc.clientId);
var src = getRealmUrl() + '/login-status-iframe.html?client_id=' + encodeURIComponent(kc.clientId) + '&origin=' + window.location.origin;
iframe.setAttribute('src', src );
iframe.style.display = 'none';
document.body.appendChild(iframe);

41
pom.xml
View file

@ -12,6 +12,8 @@
<packaging>pom</packaging>
<properties>
<bouncycastle.version>1.46</bouncycastle.version>
<jackson.version>1.9.12</jackson.version>
<keycloak.apache.httpcomponents.version>4.1.2</keycloak.apache.httpcomponents.version>
<resteasy.version>2.3.7.Final</resteasy.version>
<resteasy.version.eap.6.3>2.3.7.Final</resteasy.version.eap.6.3>
@ -33,6 +35,13 @@
<slf4j.version>1.5.10</slf4j.version>
<jboss.version>7.1.1.Final</jboss.version>
<wildfly.version>8.0.0.Final</wildfly.version>
<servlet.api.30.version>1.0.1.Final</servlet.api.30.version>
<google.zxing.version>2.2</google.zxing.version>
<google.client.version>1.14.1-beta</google.client.version>
<winzipaes.version>1.0.1</winzipaes.version>
<freemarker.version>2.3.19</freemarker.version>
<twitter4j.version>3.0.5</twitter4j.version>
<selenium.version>2.35.0</selenium.version>
<!-- maven-compiler-plugin -->
<maven.compiler.target>1.6</maven.compiler.target>
@ -109,12 +118,12 @@
<dependency>
<groupId>org.bouncycastle</groupId>
<artifactId>bcprov-jdk16</artifactId>
<version>1.46</version>
<version>${bouncycastle.version}</version>
</dependency>
<dependency>
<groupId>org.bouncycastle</groupId>
<artifactId>bcmail-jdk16</artifactId>
<version>1.46</version>
<version>${bouncycastle.version}</version>
</dependency>
<dependency>
<groupId>net.iharder</groupId>
@ -179,27 +188,27 @@
<dependency>
<groupId>org.codehaus.jackson</groupId>
<artifactId>jackson-core-asl</artifactId>
<version>1.9.12</version>
<version>${jackson.version}</version>
</dependency>
<dependency>
<groupId>org.codehaus.jackson</groupId>
<artifactId>jackson-mapper-asl</artifactId>
<version>1.9.12</version>
<version>${jackson.version}</version>
</dependency>
<dependency>
<groupId>org.codehaus.jackson</groupId>
<artifactId>jackson-xc</artifactId>
<version>1.9.12</version>
<version>${jackson.version}</version>
</dependency>
<dependency>
<groupId>org.codehaus.jackson</groupId>
<artifactId>jackson-jaxrs</artifactId>
<version>1.9.12</version>
<version>${jackson.version}</version>
</dependency>
<dependency>
<groupId>org.jboss.spec.javax.servlet</groupId>
<artifactId>jboss-servlet-api_3.0_spec</artifactId>
<version>1.0.1.Final</version>
<version>${servlet.api.30.version}</version>
</dependency>
<dependency>
<groupId>org.jboss.spec.javax.servlet</groupId>
@ -282,19 +291,19 @@
<dependency>
<groupId>com.google.api-client</groupId>
<artifactId>google-api-client</artifactId>
<version>1.14.1-beta</version>
<version>${google.client.version}</version>
</dependency>
<dependency>
<groupId>org.freemarker</groupId>
<artifactId>freemarker</artifactId>
<version>2.3.19</version>
<version>${freemarker.version}</version>
</dependency>
<!-- Google+ -->
<dependency>
<groupId>com.google.http-client</groupId>
<artifactId>google-http-client-jackson</artifactId>
<version>1.14.1-beta</version>
<version>${google.client.version}</version>
</dependency>
<dependency>
<groupId>com.google.apis</groupId>
@ -306,19 +315,19 @@
<dependency>
<groupId>org.twitter4j</groupId>
<artifactId>twitter4j-core</artifactId>
<version>3.0.5</version>
<version>${twitter4j.version}</version>
</dependency>
<!-- QR Code Generator -->
<dependency>
<groupId>com.google.zxing</groupId>
<artifactId>core</artifactId>
<version>2.2</version>
<version>${google.zxing.version}</version>
</dependency>
<dependency>
<groupId>com.google.zxing</groupId>
<artifactId>javase</artifactId>
<version>2.2</version>
<version>${google.zxing.version}</version>
</dependency>
<!-- Email Test Servers -->
@ -332,19 +341,19 @@
<dependency>
<groupId>de.idyl</groupId>
<artifactId>winzipaes</artifactId>
<version>1.0.1</version>
<version>${winzipaes.version}</version>
</dependency>
<!-- Selenium -->
<dependency>
<groupId>org.seleniumhq.selenium</groupId>
<artifactId>selenium-java</artifactId>
<version>2.35.0</version>
<version>${selenium.version}</version>
</dependency>
<dependency>
<groupId>org.seleniumhq.selenium</groupId>
<artifactId>selenium-chrome-driver</artifactId>
<version>2.35.0</version>
<version>${selenium.version}</version>
<scope>test</scope>
</dependency>
<dependency>

View file

@ -20,7 +20,9 @@
"theme": {
"default": "keycloak",
"dir": "${jboss.server.config.dir}/themes"
"folder": {
"dir": "${jboss.server.config.dir}/themes"
}
},
"login-forms": {

View file

@ -25,7 +25,6 @@
<properties>
<property name="hibernate.hbm2ddl.auto" value="update" />
<property name="jboss.as.jpa.managed" value="false" />
</properties>
</persistence-unit>
@ -37,7 +36,6 @@
<properties>
<property name="hibernate.hbm2ddl.auto" value="update" />
<property name="jboss.as.jpa.managed" value="false" />
</properties>
</persistence-unit>

View file

@ -3,7 +3,6 @@ package org.keycloak.services.managers;
import org.jboss.logging.Logger;
import org.jboss.resteasy.spi.UnauthorizedException;
import org.keycloak.models.RealmModel;
import org.keycloak.models.UserModel;
import org.keycloak.provider.ProviderSession;
import javax.ws.rs.core.Cookie;
@ -21,18 +20,16 @@ public class AppAuthManager extends AuthenticationManager {
super(providerSession);
}
public AuthResult authenticateRequest(RealmModel realm, UriInfo uriInfo, HttpHeaders headers) {
AuthResult authResult = authenticateIdentityCookie(realm, uriInfo, headers);
if (authResult != null) {
Cookie remember = headers.getCookies().get(AuthenticationManager.KEYCLOAK_REMEMBER_ME);
boolean rememberMe = remember != null;
// refresh the cookies!
createLoginCookie(realm, authResult.getUser(), authResult.getSession(), uriInfo, rememberMe);
if (rememberMe) createRememberMeCookie(realm, uriInfo);
return authResult;
} else {
return authenticateBearerToken(realm, uriInfo, headers);
}
@Override
public AuthResult authenticateIdentityCookie(RealmModel realm, UriInfo uriInfo, HttpHeaders headers) {
AuthResult authResult = super.authenticateIdentityCookie(realm, uriInfo, headers);
if (authResult == null) return null;
Cookie remember = headers.getCookies().get(AuthenticationManager.KEYCLOAK_REMEMBER_ME);
boolean rememberMe = remember != null;
// refresh the cookies!
createLoginCookie(realm, authResult.getUser(), authResult.getSession(), uriInfo, rememberMe);
if (rememberMe) createRememberMeCookie(realm, uriInfo);
return authResult;
}
public String extractAuthorizationHeaderToken(HttpHeaders headers) {

View file

@ -17,26 +17,8 @@ public class Auth {
private final UserModel user;
private final ClientModel client;
public Auth(RealmModel realm, UserModel user, ClientModel client) {
this.cookie = true;
this.realm = realm;
this.token = null;
this.user = user;
this.client = client;
}
public Auth(AccessToken token, UserModel user, ClientModel client) {
this.cookie = false;
this.token = token;
this.realm = null;
this.user = user;
this.client = client;
}
public Auth(RealmModel realm, AccessToken token, UserModel user, ClientModel client) {
this.cookie = false;
public Auth(RealmModel realm, AccessToken token, UserModel user, ClientModel client, boolean cookie) {
this.cookie = cookie;
this.token = token;
this.realm = realm;

View file

@ -145,9 +145,16 @@ public class AccountService {
account = providers.getProvider(AccountProvider.class).setRealm(realm).setUriInfo(uriInfo);
boolean passwordUpdateSupported = false;
AuthenticationManager.AuthResult authResult = authManager.authenticateRequest(realm, uriInfo, headers);
AuthenticationManager.AuthResult authResult = authManager.authenticateIdentityCookie(realm, uriInfo, headers);
if (authResult != null) {
auth = new Auth(realm, authResult.getToken(), authResult.getUser(), application, true);
} else {
authResult = authManager.authenticateBearerToken(realm, uriInfo, headers);
if (authResult != null) {
auth = new Auth(realm, authResult.getToken(), authResult.getUser(), application, false);
}
}
if (authResult != null) {
auth = new Auth(realm, authResult.getUser(), application);
if (authResult.getSession() != null) {
authResult.getSession().associateClient(application);
}
@ -208,7 +215,7 @@ public class AccountService {
} else if (types.contains(MediaType.APPLICATION_JSON_TYPE)) {
requireOneOf(AccountRoles.MANAGE_ACCOUNT, AccountRoles.VIEW_PROFILE);
return Cors.add(request, Response.ok(ModelToRepresentation.toRepresentation(auth.getUser()))).auth().allowedOrigins(auth.getClient()).build();
return Cors.add(request, Response.ok(ModelToRepresentation.toRepresentation(auth.getUser()))).auth().allowedOrigins(auth.getToken()).build();
} else {
return Response.notAcceptable(Variant.VariantListBuilder.newInstance().mediaTypes(MediaType.TEXT_HTML_TYPE, MediaType.APPLICATION_JSON_TYPE).build()).build();
}

View file

@ -8,6 +8,7 @@ import java.util.concurrent.TimeUnit;
import javax.ws.rs.core.Response;
import javax.ws.rs.core.Response.ResponseBuilder;
import org.jboss.logging.Logger;
import org.jboss.resteasy.spi.HttpRequest;
import org.jboss.resteasy.spi.HttpResponse;
import org.keycloak.models.ClientModel;
@ -18,6 +19,7 @@ import org.keycloak.util.CollectionUtil;
* @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
*/
public class Cors {
protected static final Logger logger = Logger.getLogger(Cors.class);
public static final long DEFAULT_MAX_AGE = TimeUnit.HOURS.toSeconds(1);
public static final String DEFAULT_ALLOW_METHODS = "GET, HEAD, OPTIONS";
@ -128,15 +130,18 @@ public class Cors {
return builder.build();
}
public void build(HttpResponse response) {
logger.info("build CORS");
String origin = request.getHttpHeaders().getRequestHeaders().getFirst(ORIGIN_HEADER);
if (origin == null) {
logger.info("No origin returning");
return;
}
if (!preflight && (allowedOrigins == null || !allowedOrigins.contains(origin))) {
logger.info("!preflight and no origin");
return;
}
logger.info("build CORS headers and return");
response.getOutputHeaders().add(ACCESS_CONTROL_ALLOW_ORIGIN, origin);
if (allowedMethods != null) {

View file

@ -2,6 +2,7 @@ package org.keycloak.services.resources;
import org.jboss.logging.Logger;
import org.jboss.resteasy.annotations.cache.NoCache;
import org.jboss.resteasy.spi.BadRequestException;
import org.jboss.resteasy.spi.NotFoundException;
import org.jboss.resteasy.spi.ResteasyProviderFactory;
import org.jboss.resteasy.spi.UnauthorizedException;
@ -98,7 +99,8 @@ public class RealmsResource {
@Produces(MediaType.TEXT_HTML)
@NoCache
public String getLoginStatusIframe(final @PathParam("realm") String name,
@QueryParam("client_id") String client_id) {
@QueryParam("client_id") String client_id,
@QueryParam("origin") String origin) {
logger.info("getLoginStatusIframe");
AuthenticationManager auth = new AuthenticationManager(providers);
@ -116,31 +118,33 @@ public class RealmsResource {
InputStream is = getClass().getClassLoader().getResourceAsStream("login-status-iframe.html");
if (is == null) throw new NotFoundException("Could not find login-status-iframe.html ");
Set<String> redirectUris = TokenService.resolveValidRedirects(uriInfo, client.getRedirectUris());
String origin = null;
for (String redirect : redirectUris) {
int index = redirect.indexOf("://");
if (index == -1) continue;
index = redirect.indexOf('/', index + 3);
if (index == -1) {
origin = redirect;
} else {
origin = redirect.substring(0, index);
boolean valid = false;
for (String o : client.getWebOrigins()) {
if (o.equals("*") || o.equals(origin)) {
valid = true;
break;
}
break;
}
String file = null;
for (String r : TokenService.resolveValidRedirects(uriInfo, client.getRedirectUris())) {
r = r.substring(0, r.indexOf('/', 8));
if (r.equals(origin)) {
valid = true;
break;
}
}
if (!valid) {
throw new BadRequestException("Invalid origin");
}
try {
file = StreamUtil.readString(is);
String file = StreamUtil.readString(is);
return file.replace("ORIGIN", origin);
} catch (IOException e) {
throw new RuntimeException(e);
}
file = file.replace("ORIGIN", origin);
//System.out.println(file);
return file;
}
@Path("{realm}/tokens")

View file

@ -0,0 +1,83 @@
package org.keycloak.services.resources.admin;
import org.keycloak.models.ApplicationModel;
import org.keycloak.models.ClientModel;
import org.keycloak.models.RealmModel;
import org.keycloak.models.RoleModel;
import org.keycloak.models.UserModel;
import org.keycloak.representations.AccessToken;
/**
* @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
*/
public class AdminAuth {
private final RealmModel realm;
private final AccessToken token;
private final UserModel user;
private final ClientModel client;
public AdminAuth(RealmModel realm, AccessToken token, UserModel user, ClientModel client) {
this.token = token;
this.realm = realm;
this.user = user;
this.client = client;
}
public RealmModel getRealm() {
return realm;
}
public UserModel getUser() {
return user;
}
public ClientModel getClient() {
return client;
}
public AccessToken getToken() {
return token;
}
public boolean hasRealmRole(String role) {
if (client instanceof ApplicationModel) {
RoleModel roleModel = realm.getRole(role);
return realm.hasRole(user, roleModel) && realm.hasScope(client, roleModel);
} else {
AccessToken.Access access = token.getRealmAccess();
return access != null && access.isUserInRole(role);
}
}
public boolean hasOneOfRealmRole(String... roles) {
for (String r : roles) {
if (hasRealmRole(r)) {
return true;
}
}
return false;
}
public boolean hasAppRole(ApplicationModel app, String role) {
if (client instanceof ApplicationModel) {
RoleModel roleModel = app.getRole(role);
return realm.hasRole(user, roleModel) && realm.hasScope(client, roleModel);
} else {
AccessToken.Access access = token.getResourceAccess(app.getName());
return access != null && access.isUserInRole(role);
}
}
public boolean hasOneOfAppRole(ApplicationModel app, String... roles) {
for (String r : roles) {
if (hasAppRole(app, r)) {
return true;
}
}
return false;
}
}

View file

@ -9,6 +9,7 @@ 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.ClientModel;
import org.keycloak.models.Constants;
import org.keycloak.models.KeycloakSession;
import org.keycloak.models.RealmModel;
@ -112,7 +113,7 @@ public class AdminRoot {
}
protected Auth authenticateRealmAdminRequest(HttpHeaders headers) {
protected AdminAuth authenticateRealmAdminRequest(HttpHeaders headers) {
String tokenString = authManager.extractAuthorizationHeaderToken(headers);
if (tokenString == null) throw new UnauthorizedException("Bearer");
JWSInput input = new JWSInput(tokenString);
@ -134,14 +135,13 @@ public class AdminRoot {
throw new UnauthorizedException("Bearer");
}
ApplicationModel consoleApp = realm.getApplicationByName(Constants.ADMIN_CONSOLE_APPLICATION);
if (consoleApp == null) {
throw new NotFoundException("Could not find admin console application");
ClientModel client = realm.findClient(token.getIssuedFor());
if (client == null) {
throw new NotFoundException("Could not find client for authorization");
}
Auth auth = new Auth(realm, token, authResult.getUser(), consoleApp);
return auth;
return new AdminAuth(realm, authResult.getToken(), authResult.getUser(), client);
}
public static UriBuilder realmsUrl(UriInfo uriInfo) {
@ -155,11 +155,12 @@ public class AdminRoot {
@Path("realms")
public RealmsAdminResource getRealmsAdmin(@Context final HttpHeaders headers) {
if (request.getHttpMethod().equalsIgnoreCase("OPTIONS")) {
Response response = Cors.add(request, Response.ok()).allowedMethods("GET", "PUT", "POST", "DELETE").auth().build();
logger.info("*** CORS ADMIN PREFLIGHT!!!!");
Response response = Cors.add(request, Response.ok()).preflight().allowedMethods("GET", "PUT", "POST", "DELETE").auth().build();
throw new WebApplicationException(response);
}
Auth auth = authenticateRealmAdminRequest(headers);
AdminAuth auth = authenticateRealmAdminRequest(headers);
if (auth != null) {
logger.info("authenticated admin access for: " + auth.getUser().getLoginName());
}

View file

@ -1,95 +1,95 @@
package org.keycloak.services.resources.admin;
import org.keycloak.models.AdminRoles;
import org.keycloak.models.ApplicationModel;
import org.keycloak.services.ForbiddenException;
import org.keycloak.services.managers.Auth;
import javax.ws.rs.WebApplicationException;
/**
* @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
*/
public class RealmAuth {
private Resource resource;
public enum Resource {
APPLICATION, CLIENT, USER, REALM, AUDIT
}
private Auth auth;
private ApplicationModel realmAdminApp;
public RealmAuth(Auth auth, ApplicationModel realmAdminApp) {
this.auth = auth;
this.realmAdminApp = realmAdminApp;
}
public RealmAuth init(Resource resource) {
this.resource = resource;
return this;
}
public void requireAny() {
if (!auth.hasOneOfAppRole(realmAdminApp, AdminRoles.ALL_REALM_ROLES)) {
throw new ForbiddenException();
}
}
public boolean hasView() {
return auth.hasOneOfAppRole(realmAdminApp, getViewRole(resource), getManageRole(resource));
}
public boolean hasManage() {
return auth.hasOneOfAppRole(realmAdminApp, getManageRole(resource));
}
public void requireView() {
if (!hasView()) {
throw new ForbiddenException();
}
}
public void requireManage() {
if (!hasManage()) {
throw new ForbiddenException();
}
}
private String getViewRole(Resource resource) {
switch (resource) {
case APPLICATION:
return AdminRoles.VIEW_APPLICATIONS;
case CLIENT:
return AdminRoles.VIEW_CLIENTS;
case USER:
return AdminRoles.VIEW_USERS;
case REALM:
return AdminRoles.VIEW_REALM;
case AUDIT:
return AdminRoles.VIEW_AUDIT;
default:
throw new IllegalStateException();
}
}
private String getManageRole(Resource resource) {
switch (resource) {
case APPLICATION:
return AdminRoles.MANAGE_APPLICATIONS;
case CLIENT:
return AdminRoles.MANAGE_CLIENTS;
case USER:
return AdminRoles.MANAGE_USERS;
case REALM:
return AdminRoles.MANAGE_REALM;
case AUDIT:
return AdminRoles.MANAGE_AUDIT;
default:
throw new IllegalStateException();
}
}
}
package org.keycloak.services.resources.admin;
import org.keycloak.models.AdminRoles;
import org.keycloak.models.ApplicationModel;
import org.keycloak.services.ForbiddenException;
import org.keycloak.services.managers.Auth;
import javax.ws.rs.WebApplicationException;
/**
* @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
*/
public class RealmAuth {
private Resource resource;
public enum Resource {
APPLICATION, CLIENT, USER, REALM, AUDIT
}
private AdminAuth auth;
private ApplicationModel realmAdminApp;
public RealmAuth(AdminAuth auth, ApplicationModel realmAdminApp) {
this.auth = auth;
this.realmAdminApp = realmAdminApp;
}
public RealmAuth init(Resource resource) {
this.resource = resource;
return this;
}
public void requireAny() {
if (!auth.hasOneOfAppRole(realmAdminApp, AdminRoles.ALL_REALM_ROLES)) {
throw new ForbiddenException();
}
}
public boolean hasView() {
return auth.hasOneOfAppRole(realmAdminApp, getViewRole(resource), getManageRole(resource));
}
public boolean hasManage() {
return auth.hasOneOfAppRole(realmAdminApp, getManageRole(resource));
}
public void requireView() {
if (!hasView()) {
throw new ForbiddenException();
}
}
public void requireManage() {
if (!hasManage()) {
throw new ForbiddenException();
}
}
private String getViewRole(Resource resource) {
switch (resource) {
case APPLICATION:
return AdminRoles.VIEW_APPLICATIONS;
case CLIENT:
return AdminRoles.VIEW_CLIENTS;
case USER:
return AdminRoles.VIEW_USERS;
case REALM:
return AdminRoles.VIEW_REALM;
case AUDIT:
return AdminRoles.VIEW_AUDIT;
default:
throw new IllegalStateException();
}
}
private String getManageRole(Resource resource) {
switch (resource) {
case APPLICATION:
return AdminRoles.MANAGE_APPLICATIONS;
case CLIENT:
return AdminRoles.MANAGE_CLIENTS;
case USER:
return AdminRoles.MANAGE_USERS;
case REALM:
return AdminRoles.MANAGE_REALM;
case AUDIT:
return AdminRoles.MANAGE_AUDIT;
default:
throw new IllegalStateException();
}
}
}

View file

@ -46,10 +46,10 @@ import java.util.Map;
*/
public class RealmsAdminResource {
protected static final Logger logger = Logger.getLogger(RealmsAdminResource.class);
protected Auth auth;
protected AdminAuth auth;
protected TokenManager tokenManager;
public RealmsAdminResource(Auth auth, TokenManager tokenManager) {
public RealmsAdminResource(AdminAuth auth, TokenManager tokenManager) {
this.auth = auth;
this.tokenManager = tokenManager;
}

View file

@ -158,10 +158,12 @@ public class AccountTest {
});
}
/*
@Test
public void forever() throws Exception{
while (true) Thread.sleep(5000);
}
*/
@Test
public void returnToAppFromQueryParam() {