KEYCLOAK-1233 Admin console support for add/remove federated identity
This commit is contained in:
parent
83c0f537ce
commit
142d44a01f
9 changed files with 188 additions and 42 deletions
|
@ -388,7 +388,7 @@ module.config([ '$routeProvider', function($routeProvider) {
|
||||||
controller : 'UserSessionsCtrl'
|
controller : 'UserSessionsCtrl'
|
||||||
})
|
})
|
||||||
.when('/realms/:realm/users/:user/federated-identity', {
|
.when('/realms/:realm/users/:user/federated-identity', {
|
||||||
templateUrl : resourceUrl + '/partials/user-federated-identity.html',
|
templateUrl : resourceUrl + '/partials/user-federated-identity-list.html',
|
||||||
resolve : {
|
resolve : {
|
||||||
realm : function(RealmLoader) {
|
realm : function(RealmLoader) {
|
||||||
return RealmLoader();
|
return RealmLoader();
|
||||||
|
@ -402,6 +402,21 @@ module.config([ '$routeProvider', function($routeProvider) {
|
||||||
},
|
},
|
||||||
controller : 'UserFederatedIdentityCtrl'
|
controller : 'UserFederatedIdentityCtrl'
|
||||||
})
|
})
|
||||||
|
.when('/create/federated-identity/:realm/:user', {
|
||||||
|
templateUrl : resourceUrl + '/partials/user-federated-identity-detail.html',
|
||||||
|
resolve : {
|
||||||
|
realm : function(RealmLoader) {
|
||||||
|
return RealmLoader();
|
||||||
|
},
|
||||||
|
user : function(UserLoader) {
|
||||||
|
return UserLoader();
|
||||||
|
},
|
||||||
|
federatedIdentities : function(UserFederatedIdentityLoader) {
|
||||||
|
return UserFederatedIdentityLoader();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
controller : 'UserFederatedIdentityAddCtrl'
|
||||||
|
})
|
||||||
.when('/realms/:realm/users/:user/consents', {
|
.when('/realms/:realm/users/:user/consents', {
|
||||||
templateUrl : resourceUrl + '/partials/user-consents.html',
|
templateUrl : resourceUrl + '/partials/user-consents.html',
|
||||||
resolve : {
|
resolve : {
|
||||||
|
|
|
@ -129,10 +129,66 @@ module.controller('UserSessionsCtrl', function($scope, realm, user, sessions, Us
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
module.controller('UserFederatedIdentityCtrl', function($scope, realm, user, federatedIdentities) {
|
module.controller('UserFederatedIdentityCtrl', function($scope, $location, realm, user, federatedIdentities, UserFederatedIdentity, Notifications, Dialog) {
|
||||||
$scope.realm = realm;
|
$scope.realm = realm;
|
||||||
$scope.user = user;
|
$scope.user = user;
|
||||||
$scope.federatedIdentities = federatedIdentities;
|
$scope.federatedIdentities = federatedIdentities;
|
||||||
|
|
||||||
|
$scope.hasAnyProvidersToCreate = function() {
|
||||||
|
return realm.identityProviders.length - $scope.federatedIdentities.length > 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
$scope.removeProviderLink = function(providerLink) {
|
||||||
|
|
||||||
|
console.log("Removing provider link: " + providerLink.identityProvider);
|
||||||
|
|
||||||
|
Dialog.confirmDelete(providerLink.identityProvider, 'Identity Provider Link', function() {
|
||||||
|
UserFederatedIdentity.remove({ realm: realm.realm, user: user.id, provider: providerLink.identityProvider }, function() {
|
||||||
|
Notifications.success("The provider link has been deleted.");
|
||||||
|
var indexToRemove = $scope.federatedIdentities.indexOf(providerLink);
|
||||||
|
$scope.federatedIdentities.splice(indexToRemove, 1);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
module.controller('UserFederatedIdentityAddCtrl', function($scope, $location, realm, user, federatedIdentities, UserFederatedIdentity, Notifications) {
|
||||||
|
$scope.realm = realm;
|
||||||
|
$scope.user = user;
|
||||||
|
$scope.federatedIdentity = {};
|
||||||
|
|
||||||
|
var getAvailableProvidersToCreate = function() {
|
||||||
|
var realmProviders = [];
|
||||||
|
for (var i=0 ; i<realm.identityProviders.length ; i++) {
|
||||||
|
var providerAlias = realm.identityProviders[i].alias;
|
||||||
|
realmProviders.push(providerAlias);
|
||||||
|
};
|
||||||
|
|
||||||
|
for (var i=0 ; i<federatedIdentities.length ; i++) {
|
||||||
|
var providerAlias = federatedIdentities[i].identityProvider;
|
||||||
|
var index = realmProviders.indexOf(providerAlias);
|
||||||
|
realmProviders.splice(index, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
return realmProviders;
|
||||||
|
}
|
||||||
|
$scope.availableProvidersToCreate = getAvailableProvidersToCreate();
|
||||||
|
|
||||||
|
$scope.save = function() {
|
||||||
|
UserFederatedIdentity.save({
|
||||||
|
realm : realm.realm,
|
||||||
|
user: user.id,
|
||||||
|
provider: $scope.federatedIdentity.identityProvider
|
||||||
|
}, $scope.federatedIdentity, function(data, headers) {
|
||||||
|
$location.url("/realms/" + realm.realm + '/users/' + $scope.user.id + '/federated-identity');
|
||||||
|
Notifications.success("Provider link has been created.");
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
$scope.cancel = function() {
|
||||||
|
$location.url("/realms/" + realm.realm + '/users/' + $scope.user.id + '/federated-identity');
|
||||||
|
};
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
module.controller('UserConsentsCtrl', function($scope, realm, user, userConsents, UserConsents, Notifications) {
|
module.controller('UserConsentsCtrl', function($scope, realm, user, userConsents, UserConsents, Notifications) {
|
||||||
|
|
|
@ -171,8 +171,8 @@ module.factory('UserSessionsLoader', function(Loader, UserSessions, $route, $q)
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
module.factory('UserFederatedIdentityLoader', function(Loader, UserFederatedIdentity, $route, $q) {
|
module.factory('UserFederatedIdentityLoader', function(Loader, UserFederatedIdentities, $route, $q) {
|
||||||
return Loader.query(UserFederatedIdentity, function() {
|
return Loader.query(UserFederatedIdentities, function() {
|
||||||
return {
|
return {
|
||||||
realm : $route.current.params.realm,
|
realm : $route.current.params.realm,
|
||||||
user : $route.current.params.user
|
user : $route.current.params.user
|
||||||
|
|
|
@ -305,12 +305,21 @@ module.factory('UserLogout', function($resource) {
|
||||||
user : '@user'
|
user : '@user'
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
module.factory('UserFederatedIdentity', function($resource) {
|
|
||||||
|
module.factory('UserFederatedIdentities', function($resource) {
|
||||||
return $resource(authUrl + '/admin/realms/:realm/users/:user/federated-identity', {
|
return $resource(authUrl + '/admin/realms/:realm/users/:user/federated-identity', {
|
||||||
realm : '@realm',
|
realm : '@realm',
|
||||||
user : '@user'
|
user : '@user'
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
module.factory('UserFederatedIdentity', function($resource) {
|
||||||
|
return $resource(authUrl + '/admin/realms/:realm/users/:user/federated-identity/:provider', {
|
||||||
|
realm : '@realm',
|
||||||
|
user : '@user',
|
||||||
|
provider : '@provider'
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
module.factory('UserConsents', function($resource) {
|
module.factory('UserConsents', function($resource) {
|
||||||
return $resource(authUrl + '/admin/realms/:realm/users/:user/consents/:client', {
|
return $resource(authUrl + '/admin/realms/:realm/users/:user/consents/:client', {
|
||||||
realm : '@realm',
|
realm : '@realm',
|
||||||
|
|
|
@ -0,0 +1,50 @@
|
||||||
|
<div class="col-sm-9 col-md-10 col-sm-push-3 col-md-push-2">
|
||||||
|
<ol class="breadcrumb">
|
||||||
|
<li><a href="#/realms/{{realm.realm}}/users">Users</a></li>
|
||||||
|
<li>{{user.username}}</li>
|
||||||
|
</ol>
|
||||||
|
|
||||||
|
<h1 data-ng-show="create">Add Identity Provider Link</h1>
|
||||||
|
|
||||||
|
<kc-tabs-user></kc-tabs-user>
|
||||||
|
|
||||||
|
<form class="form-horizontal" name="realmForm" novalidate kc-read-only="!access.manageRealm">
|
||||||
|
<fieldset>
|
||||||
|
<div class="form-group">
|
||||||
|
<label class="col-md-2 control-label" for="identityProvider">Identity Provier <span class="required">*</span></label>
|
||||||
|
<div class="col-sm-6">
|
||||||
|
<div>
|
||||||
|
<select class="form-control" id="identityProvider"
|
||||||
|
ng-model="federatedIdentity.identityProvider"
|
||||||
|
ng-options="providerAlias for providerAlias in availableProvidersToCreate"
|
||||||
|
required>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="form-group clearfix">
|
||||||
|
<label class="col-md-2 control-label" for="userId">Identity Provider User ID <span class="required">*</span></label>
|
||||||
|
<div class="col-md-6">
|
||||||
|
<input class="form-control" id="userId" type="text" ng-model="federatedIdentity.userId" required>
|
||||||
|
</div>
|
||||||
|
<kc-tooltip>Unique ID of the user on the Identity Provider side</kc-tooltip>
|
||||||
|
</div>
|
||||||
|
<div class="form-group clearfix">
|
||||||
|
<label class="col-md-2 control-label" for="userName">Identity Provider Username <span class="required">*</span></label>
|
||||||
|
<div class="col-md-6">
|
||||||
|
<input class="form-control" id="userName" type="text" ng-model="federatedIdentity.userName" required>
|
||||||
|
</div>
|
||||||
|
<kc-tooltip>Username on the Identity Provider side</kc-tooltip>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</fieldset>
|
||||||
|
|
||||||
|
<div class="pull-right form-actions" data-ng-show="access.manageRealm">
|
||||||
|
<button kc-cancel data-ng-click="cancel()">Cancel</button>
|
||||||
|
<button kc-save>Save</button>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<kc-menu></kc-menu>
|
|
@ -0,0 +1,45 @@
|
||||||
|
<div class="col-sm-9 col-md-10 col-sm-push-3 col-md-push-2">
|
||||||
|
<ol class="breadcrumb">
|
||||||
|
<li><a href="#/realms/{{realm.realm}}/users">Users</a></li>
|
||||||
|
<li>{{user.username}}</li>
|
||||||
|
</ol>
|
||||||
|
|
||||||
|
<h1>{{user.username|capitalize}}</h1>
|
||||||
|
|
||||||
|
<kc-tabs-user></kc-tabs-user>
|
||||||
|
|
||||||
|
<table class="table table-striped table-bordered">
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th class="kc-table-actions" colspan="4">
|
||||||
|
<div class="form-inline">
|
||||||
|
<div class="pull-right" data-ng-show="hasAnyProvidersToCreate()">
|
||||||
|
<a class="btn btn-primary" href="#/create/federated-identity/{{realm.realm}}/{{user.id}}">Create</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</th>
|
||||||
|
</tr>
|
||||||
|
<tr data-ng-hide="federatedIdentities.length == 0">
|
||||||
|
<th>Identity Provider Alias</th>
|
||||||
|
<th>Provider user ID</th>
|
||||||
|
<th>Provider username</th>
|
||||||
|
<th>Action</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
<tr data-ng-repeat="identity in federatedIdentities">
|
||||||
|
<td>{{identity.identityProvider}}</td>
|
||||||
|
<td>{{identity.userId}}</td>
|
||||||
|
<td>{{identity.userName}}</td>
|
||||||
|
<td class="actions">
|
||||||
|
<div class="action-div"><i class="pficon pficon-delete" ng-click="removeProviderLink(identity)" tooltip-placement="right" tooltip="Remove Provider Link"></i></div>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr data-ng-show="federatedIdentities.length == 0">
|
||||||
|
<td>No identity provider links available</td>
|
||||||
|
</tr>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<kc-menu></kc-menu>
|
|
@ -1,27 +0,0 @@
|
||||||
<div class="col-sm-9 col-md-10 col-sm-push-3 col-md-push-2">
|
|
||||||
<ol class="breadcrumb">
|
|
||||||
<li><a href="#/realms/{{realm.realm}}/users">Users</a></li>
|
|
||||||
<li>{{user.username}}</li>
|
|
||||||
</ol>
|
|
||||||
|
|
||||||
<h1>{{user.username|capitalize}}</h1>
|
|
||||||
|
|
||||||
<kc-tabs-user></kc-tabs-user>
|
|
||||||
|
|
||||||
<table class="table table-striped table-bordered">
|
|
||||||
<thead>
|
|
||||||
<tr>
|
|
||||||
<th>Identity Provider Alias</th>
|
|
||||||
<th>Username</th>
|
|
||||||
</tr>
|
|
||||||
</thead>
|
|
||||||
<tbody>
|
|
||||||
<tr data-ng-repeat="identity in federatedIdentities">
|
|
||||||
<td>{{identity.identityProvider}}</td>
|
|
||||||
<td>{{identity.userName}}</td>
|
|
||||||
</tr>
|
|
||||||
</tbody>
|
|
||||||
</table>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<kc-menu></kc-menu>
|
|
|
@ -1,8 +1,8 @@
|
||||||
<ul class="nav nav-tabs" data-ng-show="!create">
|
<ul class="nav nav-tabs" data-ng-show="!create">
|
||||||
<li ng-class="{active: !path[4]}"><a href="#/realms/{{realm.realm}}/users/{{user.id}}">Attributes</a></li>
|
<li ng-class="{active: !path[4] && path[0] != 'create'}"><a href="#/realms/{{realm.realm}}/users/{{user.id}}">Attributes</a></li>
|
||||||
<li ng-class="{active: path[4] == 'user-credentials'}" data-ng-show="access.manageUsers"><a href="#/realms/{{realm.realm}}/users/{{user.id}}/user-credentials">Credentials</a></li>
|
<li ng-class="{active: path[4] == 'user-credentials'}" data-ng-show="access.manageUsers"><a href="#/realms/{{realm.realm}}/users/{{user.id}}/user-credentials">Credentials</a></li>
|
||||||
<li ng-class="{active: path[4] == 'role-mappings'}" ><a href="#/realms/{{realm.realm}}/users/{{user.id}}/role-mappings">Role Mappings</a></li>
|
<li ng-class="{active: path[4] == 'role-mappings'}" ><a href="#/realms/{{realm.realm}}/users/{{user.id}}/role-mappings">Role Mappings</a></li>
|
||||||
<li ng-class="{active: path[4] == 'consents'}"><a href="#/realms/{{realm.realm}}/users/{{user.id}}/consents">Consents</a></li>
|
<li ng-class="{active: path[4] == 'consents'}"><a href="#/realms/{{realm.realm}}/users/{{user.id}}/consents">Consents</a></li>
|
||||||
<li ng-class="{active: path[4] == 'sessions'}" ><a href="#/realms/{{realm.realm}}/users/{{user.id}}/sessions">Sessions</a></li>
|
<li ng-class="{active: path[4] == 'sessions'}" ><a href="#/realms/{{realm.realm}}/users/{{user.id}}/sessions">Sessions</a></li>
|
||||||
<li ng-class="{active: path[4] == 'federated-identity'}" data-ng-show="user.federatedIdentities && user.federatedIdentities.length > 0"><a href="#/realms/{{realm.realm}}/users/{{user.id}}/federated-identity">Identity Provider Links</a></li>
|
<li ng-class="{active: path[4] == 'federated-identity' || path[1] == 'federated-identity'}" data-ng-show="user.federatedIdentities != null"><a href="#/realms/{{realm.realm}}/users/{{user.id}}/federated-identity">Identity Provider Links</a></li>
|
||||||
</ul>
|
</ul>
|
|
@ -259,15 +259,9 @@ public class UsersResource {
|
||||||
UserRepresentation rep = ModelToRepresentation.toRepresentation(user);
|
UserRepresentation rep = ModelToRepresentation.toRepresentation(user);
|
||||||
|
|
||||||
if (realm.isIdentityFederationEnabled()) {
|
if (realm.isIdentityFederationEnabled()) {
|
||||||
Set<FederatedIdentityModel> identities = session.users().getFederatedIdentities(user, realm);
|
List<FederatedIdentityRepresentation> reps = getFederatedIdentities(user);
|
||||||
if (!identities.isEmpty()) {
|
|
||||||
List<FederatedIdentityRepresentation> reps = new LinkedList<>();
|
|
||||||
for (FederatedIdentityModel m : identities) {
|
|
||||||
reps.add(ModelToRepresentation.toRepresentation(m));
|
|
||||||
}
|
|
||||||
rep.setFederatedIdentities(reps);
|
rep.setFederatedIdentities(reps);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
if ((protector != null) && protector.isTemporarilyDisabled(session, realm, rep.getUsername())) {
|
if ((protector != null) && protector.isTemporarilyDisabled(session, realm, rep.getUsername())) {
|
||||||
rep.setEnabled(false);
|
rep.setEnabled(false);
|
||||||
|
@ -318,6 +312,10 @@ public class UsersResource {
|
||||||
throw new NotFoundException("User not found");
|
throw new NotFoundException("User not found");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return getFederatedIdentities(user);
|
||||||
|
}
|
||||||
|
|
||||||
|
private List<FederatedIdentityRepresentation> getFederatedIdentities(UserModel user) {
|
||||||
Set<FederatedIdentityModel> identities = session.users().getFederatedIdentities(user, realm);
|
Set<FederatedIdentityModel> identities = session.users().getFederatedIdentities(user, realm);
|
||||||
List<FederatedIdentityRepresentation> result = new ArrayList<FederatedIdentityRepresentation>();
|
List<FederatedIdentityRepresentation> result = new ArrayList<FederatedIdentityRepresentation>();
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue