Merge pull request #1435 from patriot1burke/master

role selector
This commit is contained in:
Bill Burke 2015-07-08 19:47:22 -04:00
commit 43308b326d
17 changed files with 238 additions and 23 deletions

View file

@ -27,15 +27,15 @@ public class HardcodedRoleMapper extends AbstractIdentityProviderMapper {
property = new ProviderConfigProperty();
property.setName(ROLE);
property.setLabel("Role");
property.setHelpText("Role to grant to user. To reference an application role the syntax is appname.approle, i.e. myapp.myrole");
property.setType(ProviderConfigProperty.STRING_TYPE);
property.setHelpText("Role to grant to user. Click 'Select Role' button to browse roles, or just type it in the textbox. To reference an application role the syntax is appname.approle, i.e. myapp.myrole");
property.setType(ProviderConfigProperty.ROLE_TYPE);
configProperties.add(property);
}
public static String[] parseRole(String role) {
int scopeIndex = role.indexOf('.');
int scopeIndex = role.lastIndexOf('.');
if (scopeIndex > -1) {
String appName = role.substring(0, scopeIndex);
role = role.substring(scopeIndex + 1);

View file

@ -43,8 +43,8 @@ public class ClaimToRoleMapper extends AbstractClaimMapper {
property = new ProviderConfigProperty();
property.setName(HardcodedRoleMapper.ROLE);
property.setLabel("Role");
property.setHelpText("Role to grant to user if claim is present. To reference an application role the syntax is appname.approle, i.e. myapp.myrole");
property.setType(ProviderConfigProperty.STRING_TYPE);
property.setHelpText("Role to grant to user if claim is present. Click 'Select Role' button to browse roles, or just type it in the textbox. To reference an application role the syntax is appname.approle, i.e. myapp.myrole");
property.setType(ProviderConfigProperty.ROLE_TYPE);
configProperties.add(property);
}

View file

@ -40,8 +40,8 @@ public class ExternalKeycloakRoleToRoleMapper extends AbstractClaimMapper {
property = new ProviderConfigProperty();
property.setName(HardcodedRoleMapper.ROLE);
property.setLabel("Role");
property.setHelpText("Role to grant to user if external role is present. To reference an application role the syntax is appname.approle, i.e. myapp.myrole");
property.setType(ProviderConfigProperty.STRING_TYPE);
property.setHelpText("Role to grant to user if external role is present. Click 'Select Role' button to browse roles, or just type it in the textbox. To reference an application role the syntax is appname.approle, i.e. myapp.myrole");
property.setType(ProviderConfigProperty.ROLE_TYPE);
configProperties.add(property);
}

View file

@ -59,8 +59,8 @@ public class AttributeToRoleMapper extends AbstractIdentityProviderMapper {
property = new ProviderConfigProperty();
property.setName(HardcodedRoleMapper.ROLE);
property.setLabel("Role");
property.setHelpText("Role to grant to user. To reference an application role the syntax is appname.approle, i.e. myapp.myrole");
property.setType(ProviderConfigProperty.STRING_TYPE);
property.setHelpText("Role to grant to user. Click 'Select Role' button to browse roles, or just type it in the textbox. To reference an application role the syntax is appname.approle, i.e. myapp.myrole");
property.setType(ProviderConfigProperty.ROLE_TYPE);
configProperties.add(property);
}

View file

@ -1579,14 +1579,87 @@ module.directive('kcNavigationUser', function () {
}
});
module.directive('kcProviderConfig', function () {
module.controller('RoleSelectorModalCtrl', function($scope, realm, config, configName, RealmRoles, Client, ClientRole, $modalInstance) {
console.log('realm: ' + realm.realm);
$scope.selectedRealmRole = {
role: undefined
};
$scope.selectedClientRole = {
role: undefined
};
$scope.client = {
selected: undefined
};
$scope.selectRealmRole = function() {
config[configName] = $scope.selectedRealmRole.role.name;
$modalInstance.close();
}
$scope.selectClientRole = function() {
config[configName] = $scope.client.selected.clientId + "." + $scope.selectedClientRole.role.name;
$modalInstance.close();
}
$scope.cancel = function() {
$modalInstance.dismiss();
}
$scope.changeClient = function() {
if ($scope.client.selected) {
ClientRole.query({realm: realm.realm, client: $scope.client.selected.id}, function (data) {
$scope.clientRoles = data;
});
} else {
console.log('selected client was null');
$scope.clientRoles = null;
}
}
RealmRoles.query({realm: realm.realm}, function(data) {
$scope.realmRoles = data;
})
Client.query({realm: realm.realm}, function(data) {
$scope.clients = data;
if (data.length > 0) {
$scope.client.selected = data[0];
$scope.changeClient();
}
})
});
module.directive('kcProviderConfig', function ($modal) {
return {
scope: {
config: '=',
properties: '='
properties: '=',
realm: '='
},
restrict: 'E',
replace: true,
link: function(scope, element, attrs) {
scope.openRoleSelector = function(configName) {
$modal.open({
templateUrl: resourceUrl + '/partials/modal/role-selector.html',
controller: 'RoleSelectorModalCtrl',
resolve: {
realm: function () {
return scope.realm;
},
config: function() {
return scope.config;
},
configName: function() {
return configName;
}
}
})
};
},
templateUrl: resourceUrl + '/templates/kc-provider-config.html'
}
});

View file

@ -1118,4 +1118,98 @@ module.factory('AuthenticationExecutionConfig', function($resource) {
});
});
module.service('SelectRoleDialog', function($modal) {
var dialog = {};
var openDialog = function(title, message, btns) {
var controller = function($scope, $modalInstance, title, message, btns) {
$scope.title = title;
$scope.message = message;
$scope.btns = btns;
$scope.ok = function () {
$modalInstance.close();
};
$scope.cancel = function () {
$modalInstance.dismiss('cancel');
};
};
return $modal.open({
templateUrl: resourceUrl + '/templates/kc-modal.html',
controller: controller,
resolve: {
title: function() {
return title;
},
message: function() {
return message;
},
btns: function() {
return btns;
}
}
}).result;
}
var escapeHtml = function(str) {
var div = document.createElement('div');
div.appendChild(document.createTextNode(str));
return div.innerHTML;
};
dialog.confirmDelete = function(name, type, success) {
var title = 'Delete ' + escapeHtml(type.charAt(0).toUpperCase() + type.slice(1));
var msg = 'Are you sure you want to permanently delete the ' + type + ' ' + name + '?';
var btns = {
ok: {
label: 'Delete',
cssClass: 'btn btn-danger'
},
cancel: {
label: 'Cancel',
cssClass: 'btn btn-default'
}
}
openDialog(title, msg, btns).then(success);
}
dialog.confirmGenerateKeys = function(name, type, success) {
var title = 'Generate new keys for realm';
var msg = 'Are you sure you want to permanently generate new keys for ' + name + '?';
var btns = {
ok: {
label: 'Generate Keys',
cssClass: 'btn btn-danger'
},
cancel: {
label: 'Cancel',
cssClass: 'btn btn-default'
}
}
openDialog(title, msg, btns).then(success);
}
dialog.confirm = function(title, message, success, cancel) {
var btns = {
ok: {
label: title,
cssClass: 'btn btn-danger'
},
cancel: {
label: 'Cancel',
cssClass: 'btn btn-default'
}
}
openDialog(title, message, btns).then(success, cancel);
}
return dialog
});

View file

@ -26,7 +26,7 @@
</div>
<kc-tooltip>Name of the configuration.</kc-tooltip>
</div>
<kc-provider-config config="config.config" properties="configType.properties"></kc-provider-config>
<kc-provider-config realm="realm" config="config.config" properties="configType.properties"></kc-provider-config>
</fieldset>
<div class="form-group">

View file

@ -45,7 +45,7 @@
</div>
<kc-tooltip>{{mapperType.helpText}}</kc-tooltip>
</div>
<kc-provider-config config="mapper.config" properties="mapperType.properties"></kc-provider-config>
<kc-provider-config config="mapper.config" properties="mapperType.properties" realm="realm"></kc-provider-config>
</fieldset>
<div class="pull-right form-actions" data-ng-show="create && access.manageRealm">
<button kc-cancel data-ng-click="cancel()">Cancel</button>

View file

@ -0,0 +1,40 @@
<div style="padding: 15px 60px 75px 60px">
<h2>Role Selector</h2>
<form>
<div data-ng-show="realmRoles.length > 0">
<label class="control-label" for="available">Realm Roles</label>
<kc-tooltip>Realm roles that can be selected.</kc-tooltip>
<select id="available" class="form-control" size="5"
ng-dblclick="selectRealmRole()"
ng-model="selectedRealmRole.role"
ng-options="r.name for r in realmRoles | orderBy:'toString()'">
<option style="display:none" value="">Select a role</option>
</select>
<button class="btn btn-default" type="submit" ng-click="selectRealmRole()" tooltip="Select realm role" tooltip-placement="right">
Select Realm Role</i>
</button>
</div>
<br>
<br>
<div data-ng-show="clients.length > 0">
<label class="control-label">
<span>Client Roles</span>
<kc-tooltip>Client roles that can be selected.</kc-tooltip>
<select class="form-control" id="clients" name="clients" ng-change="changeClient()" ng-model="client.selected" ng-options="a.clientId for a in clients" ng-disabled="false">
</select>
</label>
<select id="available-client" class="form-control" size="5"
ng-dblclick="selectClientRole()"
ng-model="selectedClientRole.role"
ng-options="r.name for r in clientRoles | orderBy:'toString()'">
<option style="display:none" value="">Select a role</option>
</select>
<button class="btn btn-default" type="submit" ng-click="selectClientRole()" tooltip="Select client role" tooltip-placement="right">
Select Client Role
</button>
</div>
</form>
<div class="modal-footer">
<button type="button" data-ng-class="btns.cancel.cssClass" ng-click="cancel()">Cancel</button>
</div>
</div>

View file

@ -69,7 +69,7 @@
</div>
<kc-tooltip>{{mapperType.helpText}}</kc-tooltip>
</div>
<kc-provider-config config="mapper.config" properties="mapperType.properties"></kc-provider-config>
<kc-provider-config config="mapper.config" properties="mapperType.properties" realm="realm"></kc-provider-config>
</fieldset>
<div class="form-group">

View file

@ -1,7 +1,7 @@
<div data-ng-repeat="option in properties" class="form-group">
<label class="col-md-2 control-label">{{option.label}}</label>
<div class="col-sm-6" data-ng-hide="option.type == 'boolean' || option.type == 'List'">
<div class="col-sm-6" data-ng-hide="option.type == 'boolean' || option.type == 'List' || option.type == 'Role'">
<input class="form-control" type="text" data-ng-model="config[ option.name ]" >
</div>
<div class="col-sm-6" data-ng-show="option.type == 'boolean'">
@ -12,5 +12,12 @@
<option value="" selected> Select one... </option>
</select>
</div>
<div class="col-sm-6" data-ng-show="option.type == 'Role'">
<input class="form-control" type="text" data-ng-model="config[ option.name ]" >
</div>
<div class="col-sm-4" data-ng-show="option.type == 'Role'">
<button type="submit" data-ng-click="openRoleSelector(option.name)" class="btn btn-default" tooltip="Enter role in the textbox to the left, or click this button to browse and select the role you want">Select Role</button>
</div>
<kc-tooltip>{{option.helpText}}</kc-tooltip>
</div>

View file

@ -7,6 +7,7 @@ package org.keycloak.provider;
public class ProviderConfigProperty {
public static final String BOOLEAN_TYPE="boolean";
public static final String STRING_TYPE="String";
public static final String ROLE_TYPE="Role";
public static final String LIST_TYPE="List";
public static final String CLIENT_LIST_TYPE="ClientList";

View file

@ -25,8 +25,8 @@ public class HardcodedRole extends AbstractSAMLProtocolMapper {
property = new ProviderConfigProperty();
property.setName("role");
property.setLabel("Role");
property.setHelpText("Role name you want to hardcode.");
property.setType(ProviderConfigProperty.STRING_TYPE);
property.setHelpText("Arbitrary role name you want to hardcode. This role does not have to exist in current realm and can be just any string you need");
property.setType(ProviderConfigProperty.ROLE_TYPE);
configProperties.add(property);
}

View file

@ -31,8 +31,8 @@ public class RoleNameMapper extends AbstractOIDCProtocolMapper implements SAMLRo
property = new ProviderConfigProperty();
property.setName(ROLE_CONFIG);
property.setLabel("Role");
property.setHelpText("Role name you want changed. To reference an application role the syntax is appname.approle, i.e. myapp.myrole");
property.setType(ProviderConfigProperty.STRING_TYPE);
property.setHelpText("Role name you want changed. Click 'Select Role' button to browse roles, or just type it in the textbox. To reference an application role the syntax is appname.approle, i.e. myapp.myrole");
property.setType(ProviderConfigProperty.ROLE_TYPE);
configProperties.add(property);
property = new ProviderConfigProperty();
property.setName(NEW_ROLE_NAME);

View file

@ -47,7 +47,7 @@ public class ProtocolMapperUtils {
}
public static String[] parseRole(String role) {
int scopeIndex = role.indexOf('.');
int scopeIndex = role.lastIndexOf('.');
if (scopeIndex > -1) {
String appName = role.substring(0, scopeIndex);
role = role.substring(scopeIndex + 1);

View file

@ -31,8 +31,8 @@ public class HardcodedRole extends AbstractOIDCProtocolMapper implements OIDCAcc
property = new ProviderConfigProperty();
property.setName(ROLE_CONFIG);
property.setLabel("Role");
property.setHelpText("Role you want added to the token. To specify an application role the syntax is appname.approle, i.e. myapp.myrole");
property.setType(ProviderConfigProperty.STRING_TYPE);
property.setHelpText("Role you want added to the token. Click 'Select Role' button to browse roles, or just type it in the textbox. To specify an application role the syntax is appname.approle, i.e. myapp.myrole");
property.setType(ProviderConfigProperty.ROLE_TYPE);
configProperties.add(property);
}

View file

@ -34,7 +34,7 @@ public class RoleNameMapper extends AbstractOIDCProtocolMapper implements OIDCAc
property = new ProviderConfigProperty();
property.setName(ROLE_CONFIG);
property.setLabel("Role");
property.setHelpText("Role name you want changed. To reference an application role the syntax is appname.approle, i.e. myapp.myrole");
property.setHelpText("Role name you want changed. Click 'Select Role' button to browse roles, or just type it in the textbox. To reference an application role the syntax is appname.approle, i.e. myapp.myrole");
property.setType(ProviderConfigProperty.STRING_TYPE);
configProperties.add(property);
property = new ProviderConfigProperty();