Skip to content

Commit

Permalink
KEYCLOAK-1070 Support for view and revoke consents in admin console
Browse files Browse the repository at this point in the history
  • Loading branch information
mposolda committed Apr 28, 2015
1 parent 1d4ef83 commit 3160530
Show file tree
Hide file tree
Showing 18 changed files with 315 additions and 106 deletions.
@@ -1,28 +1,52 @@
package org.keycloak.representations.idm; package org.keycloak.representations.idm;


import java.util.List; import java.util.List;
import java.util.Map;


/** /**
* @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a> * @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
*/ */
public class UserConsentRepresentation { public class UserConsentRepresentation {


protected List<String> grantedRoles; // points to roleIds protected String clientId;
protected List<String> grantedProtocolMappers; // points to protocolMapperIds


public List<String> getGrantedRoles() { // Key is protocol, Value is list of granted consents for this protocol
return grantedRoles; protected Map<String, List<String>> grantedProtocolMappers;

protected List<String> grantedRealmRoles;

// Key is clientId, Value is list of granted roles of this client
protected Map<String, List<String>> grantedClientRoles;

public String getClientId() {
return clientId;
} }


public void setGrantedRoles(List<String> grantedRoles) { public void setClientId(String clientId) {
this.grantedRoles = grantedRoles; this.clientId = clientId;
} }


public List<String> getGrantedProtocolMappers() { public Map<String, List<String>> getGrantedProtocolMappers() {
return grantedProtocolMappers; return grantedProtocolMappers;
} }


public void setGrantedProtocolMappers(List<String> grantedProtocolMappers) { public void setGrantedProtocolMappers(Map<String, List<String>> grantedProtocolMappers) {
this.grantedProtocolMappers = grantedProtocolMappers; this.grantedProtocolMappers = grantedProtocolMappers;
} }

public List<String> getGrantedRealmRoles() {
return grantedRealmRoles;
}

public void setGrantedRealmRoles(List<String> grantedRealmRoles) {
this.grantedRealmRoles = grantedRealmRoles;
}

public Map<String, List<String>> getGrantedClientRoles() {
return grantedClientRoles;
}

public void setGrantedClientRoles(Map<String, List<String>> grantedClientRoles) {
this.grantedClientRoles = grantedClientRoles;
}
} }
Expand Up @@ -27,7 +27,7 @@ public class UserRepresentation {
protected List<FederatedIdentityRepresentation> federatedIdentities; protected List<FederatedIdentityRepresentation> federatedIdentities;
protected List<String> realmRoles; protected List<String> realmRoles;
protected Map<String, List<String>> clientRoles; protected Map<String, List<String>> clientRoles;
protected Map<String, UserConsentRepresentation> clientConsents; protected List<UserConsentRepresentation> clientConsents;


@Deprecated @Deprecated
protected Map<String, List<String>> applicationRoles; protected Map<String, List<String>> applicationRoles;
Expand Down Expand Up @@ -177,11 +177,11 @@ public void setClientRoles(Map<String, List<String>> clientRoles) {
this.clientRoles = clientRoles; this.clientRoles = clientRoles;
} }


public Map<String, UserConsentRepresentation> getClientConsents() { public List<UserConsentRepresentation> getClientConsents() {
return clientConsents; return clientConsents;
} }


public void setClientConsents(Map<String, UserConsentRepresentation> clientConsents) { public void setClientConsents(List<UserConsentRepresentation> clientConsents) {
this.clientConsents = clientConsents; this.clientConsents = clientConsents;
} }


Expand Down
Expand Up @@ -287,29 +287,11 @@ public static UserRepresentation exportUser(KeycloakSession session, RealmModel


// Grants // Grants
List<UserConsentModel> consents = user.getConsents(); List<UserConsentModel> consents = user.getConsents();
Map<String, UserConsentRepresentation> consentReps = new HashMap<String, UserConsentRepresentation>(); LinkedList<UserConsentRepresentation> consentReps = new LinkedList<UserConsentRepresentation>();
for (UserConsentModel consent : consents) { for (UserConsentModel consent : consents) {
String clientId = consent.getClient().getClientId(); UserConsentRepresentation consentRep = ModelToRepresentation.toRepresentation(consent);

consentReps.add(consentRep);
List<String> grantedProtocolMappers = new LinkedList<String>();
for (ProtocolMapperModel protocolMapper : consent.getGrantedProtocolMappers()) {
grantedProtocolMappers.add(protocolMapper.getId());
}

List<String> grantedRoles = new LinkedList<String>();
for (RoleModel role : consent.getGrantedRoles()) {
grantedRoles.add(role.getId());
}


if (grantedRoles.size() > 0 || grantedProtocolMappers.size() > 0) {
UserConsentRepresentation consentRep = new UserConsentRepresentation();
if (grantedRoles.size() > 0) consentRep.setGrantedRoles(grantedRoles);
if (grantedProtocolMappers.size() > 0) consentRep.setGrantedProtocolMappers(grantedProtocolMappers);
consentReps.put(clientId, consentRep);
}
} }

if (consentReps.size() > 0) { if (consentReps.size() > 0) {
userRep.setClientConsents(consentReps); userRep.setClientConsents(consentReps);
} }
Expand Down
Expand Up @@ -399,6 +399,21 @@ module.config([ '$routeProvider', function($routeProvider) {
}, },
controller : 'UserFederatedIdentityCtrl' controller : 'UserFederatedIdentityCtrl'
}) })
.when('/realms/:realm/users/:user/consents', {
templateUrl : resourceUrl + '/partials/user-consents.html',
resolve : {
realm : function(RealmLoader) {
return RealmLoader();
},
user : function(UserLoader) {
return UserLoader();
},
userConsents : function(UserConsentsLoader) {
return UserConsentsLoader();
}
},
controller : 'UserConsentsCtrl'
})
.when('/realms/:realm/users', { .when('/realms/:realm/users', {
templateUrl : resourceUrl + '/partials/user-list.html', templateUrl : resourceUrl + '/partials/user-list.html',
resolve : { resolve : {
Expand Down Expand Up @@ -1418,6 +1433,15 @@ module.directive('kcNavigationClient', function () {
} }
}); });


module.directive('kcNavigationUser', function () {
return {
scope: true,
restrict: 'E',
replace: true,
templateUrl: resourceUrl + '/templates/kc-navigation-user.html'
}
});

/* /*
* Used to select the element (invoke $(elem).select()) on specified action list. * Used to select the element (invoke $(elem).select()) on specified action list.
* Usages kc-select-action="click mouseover" * Usages kc-select-action="click mouseover"
Expand Down
Expand Up @@ -135,6 +135,24 @@ module.controller('UserFederatedIdentityCtrl', function($scope, realm, user, fed
$scope.federatedIdentities = federatedIdentities; $scope.federatedIdentities = federatedIdentities;
}); });


module.controller('UserConsentsCtrl', function($scope, realm, user, userConsents, UserConsents, Notifications) {
$scope.realm = realm;
$scope.user = user;
$scope.userConsents = userConsents;

$scope.revokeConsent = function(clientId) {
UserConsents.delete({realm : realm.realm, user: user.username, client: clientId }, function () {
UserConsents.query({realm: realm.realm, user: user.username}, function(updated) {
$scope.userConsents = updated;
})
Notifications.success('Consent revoked successfully');
}, function() {
Notifications.error("Consent couldn't be revoked");
});
console.log("Revoke consent " + clientId);
}
});



module.controller('UserListCtrl', function($scope, realm, User) { module.controller('UserListCtrl', function($scope, realm, User) {
$scope.realm = realm; $scope.realm = realm;
Expand Down
Expand Up @@ -144,6 +144,14 @@ module.factory('UserFederatedIdentityLoader', function(Loader, UserFederatedIden
}); });
}); });


module.factory('UserConsentsLoader', function(Loader, UserConsents, $route, $q) {
return Loader.query(UserConsents, function() {
return {
realm : $route.current.params.realm,
user : $route.current.params.user
}
});
});






Expand Down
Expand Up @@ -268,6 +268,13 @@ module.factory('UserFederatedIdentity', function($resource) {
user : '@user' user : '@user'
}); });
}); });
module.factory('UserConsents', function($resource) {
return $resource(authUrl + '/admin/realms/:realm/users/:user/consents/:client', {
realm : '@realm',
user : '@user',
client: '@client'
});
});


module.factory('UserCredentials', function($resource) { module.factory('UserCredentials', function($resource) {
var credentials = {}; var credentials = {};
Expand Down
@@ -1,12 +1,6 @@
<div class="bs-sidebar col-md-3 clearfix" data-ng-include data-src="resourceUrl + '/partials/realm-menu.html'"></div> <div class="bs-sidebar col-md-3 clearfix" data-ng-include data-src="resourceUrl + '/partials/realm-menu.html'"></div>
<div id="content-area" class="col-md-9" role="main"> <div id="content-area" class="col-md-9" role="main">
<ul class="nav nav-tabs nav-tabs-pf" data-ng-show="!create"> <kc-navigation-user></kc-navigation-user>
<li><a href="#/realms/{{realm.realm}}/users/{{user.username}}">Attributes</a></li>
<li data-ng-show="access.manageUsers"><a href="#/realms/{{realm.realm}}/users/{{user.username}}/user-credentials">Credentials</a></li>
<li class="active"><a href="#/realms/{{realm.realm}}/users/{{user.username}}/role-mappings">Role Mappings</a></li>
<li><a href="#/realms/{{realm.realm}}/users/{{user.username}}/sessions">Sessions</a></li>
<li data-ng-show="realm.identityFederationEnabled"><a href="#/realms/{{realm.realm}}/users/{{user.username}}/social-links">Federated Identities</a></li>
</ul>
<div id="content"> <div id="content">
<ol class="breadcrumb"> <ol class="breadcrumb">
<li><a href="#/realms/{{realm.realm}}/users">Users</a></li> <li><a href="#/realms/{{realm.realm}}/users">Users</a></li>
Expand Down
@@ -0,0 +1,47 @@
<div class="bs-sidebar col-md-3 clearfix" data-ng-include data-src="resourceUrl + '/partials/realm-menu.html'"></div>
<div id="content-area" class="col-md-9" role="main">
<kc-navigation-user></kc-navigation-user>
<div id="content">
<ol class="breadcrumb">
<li><a href="#/realms/{{realm.realm}}/users">Users</a></li>
<li><a href="#/realms/{{realm.realm}}/users/{{user.username}}">{{user.username}}</a></li>
<li class="active">Consents</li>
</ol>
<h2>User <span>{{user.username}}</span> Consents <span tooltip-placement="right" tooltip="This page shows you all the consents, which user granted permissions" class="fa fa-info-circle"></span></h2>
<table class="table table-striped table-bordered">
<thead>
<tr>
<th>Client</th>
<th>Granted Roles</th>
<th>Granted Protocol Mappers</th>
<th>Action</th>
</tr>
</thead>
<tbody>
<tr data-ng-repeat="consent in userConsents">
<td>{{consent.clientId}}</td>
<td>
<span data-ng-repeat="realmRole in consent.grantedRealmRoles">
<span ng-if="!$first">, </span>{{realmRole}}
</span>
<span data-ng-repeat="(clientId, clientRoles) in consent.grantedClientRoles">
<span data-ng-repeat="clientRole in clientRoles">
<span ng-if="!$first || consent.grantedRealmRoles.length > 0">, </span>{{clientRole}} in {{clientId}}
</span>
</span>
</td>
<td>
<span data-ng-repeat="protocol in consent.grantedProtocolMappers">
<span data-ng-repeat="protocolMapper in protocol">
<span ng-if="!$first">, </span>{{protocolMapper}}
</span>
</span>
</td>
<td>
<button class="btn btn-danger" ng-click="revokeConsent(consent.clientId)">Revoke consent</button>
</td>
</tr>
</tbody>
</table>
</div>
</div>
@@ -1,13 +1,6 @@
<div class="bs-sidebar col-md-3 clearfix" data-ng-include data-src="resourceUrl + '/partials/realm-menu.html'"></div> <div class="bs-sidebar col-md-3 clearfix" data-ng-include data-src="resourceUrl + '/partials/realm-menu.html'"></div>
<div id="content-area" class="col-md-9" role="main"> <div id="content-area" class="col-md-9" role="main">

<kc-navigation-user></kc-navigation-user>
<ul class="nav nav-tabs nav-tabs-pf" data-ng-show="!create">
<li><a href="#/realms/{{realm.realm}}/users/{{user.username}}">Attributes</a></li>
<li class="active"><a href="#/realms/{{realm.realm}}/users/{{user.username}}/user-credentials">Credentials</a></li>
<li><a href="#/realms/{{realm.realm}}/users/{{user.username}}/role-mappings">Role Mappings</a></li>
<li><a href="#/realms/{{realm.realm}}/users/{{user.username}}/sessions">Sessions</a></li>
<li data-ng-show="realm.identityFederationEnabled"><a href="#/realms/{{realm.realm}}/users/{{user.username}}/federated-identity">Federated Identities</a></li>
</ul>
<div id="content"> <div id="content">
<ol class="breadcrumb"> <ol class="breadcrumb">
<li><a href="#/realms/{{realm.realm}}/users">Users</a></li> <li><a href="#/realms/{{realm.realm}}/users">Users</a></li>
Expand Down
@@ -1,13 +1,6 @@
<div class="bs-sidebar col-md-3 clearfix" data-ng-include data-src="resourceUrl + '/partials/realm-menu.html'"></div> <div class="bs-sidebar col-md-3 clearfix" data-ng-include data-src="resourceUrl + '/partials/realm-menu.html'"></div>
<div id="content-area" class="col-md-9" role="main"> <div id="content-area" class="col-md-9" role="main">

<kc-navigation-user></kc-navigation-user>
<ul class="nav nav-tabs nav-tabs-pf" data-ng-show="!create">
<li class="active"><a href="#/realms/{{realm.realm}}/users/{{user.username}}">Attributes</a></li>
<li data-ng-show="access.manageUsers"><a href="#/realms/{{realm.realm}}/users/{{user.username}}/user-credentials">Credentials</a></li>
<li><a href="#/realms/{{realm.realm}}/users/{{user.username}}/role-mappings">Role Mappings</a></li>
<li><a href="#/realms/{{realm.realm}}/users/{{user.username}}/sessions">Sessions</a></li>
<li data-ng-show="realm.identityFederationEnabled"><a href="#/realms/{{realm.realm}}/users/{{user.username}}/federated-identity">Federated Identities</a></li>
</ul>
<ul class="nav nav-tabs nav-tabs-pf" data-ng-show="create"> <ul class="nav nav-tabs nav-tabs-pf" data-ng-show="create">
<li class="active"><a href="">User List</a></li> <li class="active"><a href="">User List</a></li>
<li><a href="#/realms/{{realm.realm}}/user-federation">Federation</a></li> <li><a href="#/realms/{{realm.realm}}/user-federation">Federation</a></li>
Expand Down
@@ -1,12 +1,6 @@
<div class="bs-sidebar col-md-3 clearfix" data-ng-include data-src="resourceUrl + '/partials/realm-menu.html'"></div> <div class="bs-sidebar col-md-3 clearfix" data-ng-include data-src="resourceUrl + '/partials/realm-menu.html'"></div>
<div id="content-area" class="col-md-9" role="main"> <div id="content-area" class="col-md-9" role="main">
<ul class="nav nav-tabs nav-tabs-pf"> <kc-navigation-user></kc-navigation-user>
<li><a href="#/realms/{{realm.realm}}/users/{{user.username}}">Attributes</a></li>
<li><a href="#/realms/{{realm.realm}}/users/{{user.username}}/user-credentials">Credentials</a></li>
<li><a href="#/realms/{{realm.realm}}/users/{{user.username}}/role-mappings">Role Mappings</a></li>
<li><a href="#/realms/{{realm.realm}}/users/{{user.username}}/sessions">Sessions</a></li>
<li class="active"><a href="#/realms/{{realm.realm}}/users/{{user.username}}/federated-identity">Federated Identities</a></li>
</ul>
<div id="content"> <div id="content">
<ol class="breadcrumb"> <ol class="breadcrumb">
<li><a href="#/realms/{{realm.realm}}/users">Users</a></li> <li><a href="#/realms/{{realm.realm}}/users">Users</a></li>
Expand Down
@@ -1,12 +1,6 @@
<div class="bs-sidebar col-md-3 clearfix" data-ng-include data-src="resourceUrl + '/partials/realm-menu.html'"></div> <div class="bs-sidebar col-md-3 clearfix" data-ng-include data-src="resourceUrl + '/partials/realm-menu.html'"></div>
<div id="content-area" class="col-md-9" role="main"> <div id="content-area" class="col-md-9" role="main">
<ul class="nav nav-tabs nav-tabs-pf"> <kc-navigation-user></kc-navigation-user>
<li><a href="#/realms/{{realm.realm}}/users/{{user.username}}">Attributes</a></li>
<li><a href="#/realms/{{realm.realm}}/users/{{user.username}}/user-credentials">Credentials</a></li>
<li><a href="#/realms/{{realm.realm}}/users/{{user.username}}/role-mappings">Role Mappings</a></li>
<li class="active"><a href="#/realms/{{realm.realm}}/users/{{user.username}}/sessions">Sessions</a></li>
<li data-ng-show="realm.identityFederationEnabled"><a href="#/realms/{{realm.realm}}/users/{{user.username}}/federated-identity">Federated Identities</a></li>
</ul>
<div id="content"> <div id="content">
<ol class="breadcrumb"> <ol class="breadcrumb">
<li><a href="#/realms/{{realm.realm}}/users">Users</a></li> <li><a href="#/realms/{{realm.realm}}/users">Users</a></li>
Expand Down
@@ -0,0 +1,8 @@
<ul class="nav nav-tabs nav-tabs-pf" data-ng-hide="create">
<li ng-class="{active: !path[4]}"><a href="#/realms/{{realm.realm}}/users/{{user.username}}">Attributes</a></li>
<li ng-class="{active: path[4] == 'user-credentials'}"><a href="#/realms/{{realm.realm}}/users/{{user.username}}/user-credentials">Credentials</a></li>
<li ng-class="{active: path[4] == 'role-mappings'}"><a href="#/realms/{{realm.realm}}/users/{{user.username}}/role-mappings">Role Mappings</a></li>
<li ng-class="{active: path[4] == 'sessions'}"><a href="#/realms/{{realm.realm}}/users/{{user.username}}/sessions">Sessions</a></li>
<li ng-class="{active: path[4] == 'federated-identity'}" data-ng-show="realm.identityFederationEnabled"><a href="#/realms/{{realm.realm}}/users/{{user.username}}/federated-identity">Federated Identities</a></li>
<li ng-class="{active: path[4] == 'consents'}"><a href="#/realms/{{realm.realm}}/users/{{user.username}}/consents">Consents</a></li>
</ul>

0 comments on commit 3160530

Please sign in to comment.