KEYCLOAK-1070 Support for view and revoke consents in admin console
This commit is contained in:
parent
1d4ef83b81
commit
316053018b
18 changed files with 315 additions and 106 deletions
|
@ -1,28 +1,52 @@
|
|||
package org.keycloak.representations.idm;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
|
||||
*/
|
||||
public class UserConsentRepresentation {
|
||||
|
||||
protected List<String> grantedRoles; // points to roleIds
|
||||
protected List<String> grantedProtocolMappers; // points to protocolMapperIds
|
||||
protected String clientId;
|
||||
|
||||
public List<String> getGrantedRoles() {
|
||||
return grantedRoles;
|
||||
// Key is protocol, Value is list of granted consents for this protocol
|
||||
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) {
|
||||
this.grantedRoles = grantedRoles;
|
||||
public void setClientId(String clientId) {
|
||||
this.clientId = clientId;
|
||||
}
|
||||
|
||||
public List<String> getGrantedProtocolMappers() {
|
||||
public Map<String, List<String>> getGrantedProtocolMappers() {
|
||||
return grantedProtocolMappers;
|
||||
}
|
||||
|
||||
public void setGrantedProtocolMappers(List<String> grantedProtocolMappers) {
|
||||
public void setGrantedProtocolMappers(Map<String, List<String>> 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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -27,7 +27,7 @@ public class UserRepresentation {
|
|||
protected List<FederatedIdentityRepresentation> federatedIdentities;
|
||||
protected List<String> realmRoles;
|
||||
protected Map<String, List<String>> clientRoles;
|
||||
protected Map<String, UserConsentRepresentation> clientConsents;
|
||||
protected List<UserConsentRepresentation> clientConsents;
|
||||
|
||||
@Deprecated
|
||||
protected Map<String, List<String>> applicationRoles;
|
||||
|
@ -177,11 +177,11 @@ public class UserRepresentation {
|
|||
this.clientRoles = clientRoles;
|
||||
}
|
||||
|
||||
public Map<String, UserConsentRepresentation> getClientConsents() {
|
||||
public List<UserConsentRepresentation> getClientConsents() {
|
||||
return clientConsents;
|
||||
}
|
||||
|
||||
public void setClientConsents(Map<String, UserConsentRepresentation> clientConsents) {
|
||||
public void setClientConsents(List<UserConsentRepresentation> clientConsents) {
|
||||
this.clientConsents = clientConsents;
|
||||
}
|
||||
|
||||
|
|
|
@ -287,29 +287,11 @@ public class ExportUtils {
|
|||
|
||||
// Grants
|
||||
List<UserConsentModel> consents = user.getConsents();
|
||||
Map<String, UserConsentRepresentation> consentReps = new HashMap<String, UserConsentRepresentation>();
|
||||
LinkedList<UserConsentRepresentation> consentReps = new LinkedList<UserConsentRepresentation>();
|
||||
for (UserConsentModel consent : consents) {
|
||||
String clientId = consent.getClient().getClientId();
|
||||
|
||||
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);
|
||||
}
|
||||
UserConsentRepresentation consentRep = ModelToRepresentation.toRepresentation(consent);
|
||||
consentReps.add(consentRep);
|
||||
}
|
||||
|
||||
if (consentReps.size() > 0) {
|
||||
userRep.setClientConsents(consentReps);
|
||||
}
|
||||
|
|
|
@ -399,6 +399,21 @@ module.config([ '$routeProvider', function($routeProvider) {
|
|||
},
|
||||
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', {
|
||||
templateUrl : resourceUrl + '/partials/user-list.html',
|
||||
resolve : {
|
||||
|
@ -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.
|
||||
* Usages kc-select-action="click mouseover"
|
||||
|
|
|
@ -135,6 +135,24 @@ module.controller('UserFederatedIdentityCtrl', function($scope, realm, user, fed
|
|||
$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) {
|
||||
$scope.realm = realm;
|
||||
|
|
|
@ -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
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
|
||||
|
|
|
@ -268,6 +268,13 @@ module.factory('UserFederatedIdentity', function($resource) {
|
|||
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) {
|
||||
var credentials = {};
|
||||
|
|
|
@ -1,12 +1,6 @@
|
|||
<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">
|
||||
<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 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>
|
||||
<kc-navigation-user></kc-navigation-user>
|
||||
<div id="content">
|
||||
<ol class="breadcrumb">
|
||||
<li><a href="#/realms/{{realm.realm}}/users">Users</a></li>
|
||||
|
|
|
@ -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 id="content-area" class="col-md-9" role="main">
|
||||
|
||||
<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>
|
||||
<kc-navigation-user></kc-navigation-user>
|
||||
<div id="content">
|
||||
<ol class="breadcrumb">
|
||||
<li><a href="#/realms/{{realm.realm}}/users">Users</a></li>
|
||||
|
|
|
@ -1,13 +1,6 @@
|
|||
<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">
|
||||
|
||||
<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>
|
||||
<kc-navigation-user></kc-navigation-user>
|
||||
<ul class="nav nav-tabs nav-tabs-pf" data-ng-show="create">
|
||||
<li class="active"><a href="">User List</a></li>
|
||||
<li><a href="#/realms/{{realm.realm}}/user-federation">Federation</a></li>
|
||||
|
|
|
@ -1,12 +1,6 @@
|
|||
<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">
|
||||
<ul class="nav nav-tabs nav-tabs-pf">
|
||||
<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>
|
||||
<kc-navigation-user></kc-navigation-user>
|
||||
<div id="content">
|
||||
<ol class="breadcrumb">
|
||||
<li><a href="#/realms/{{realm.realm}}/users">Users</a></li>
|
||||
|
|
|
@ -1,12 +1,6 @@
|
|||
<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">
|
||||
<ul class="nav nav-tabs nav-tabs-pf">
|
||||
<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>
|
||||
<kc-navigation-user></kc-navigation-user>
|
||||
<div id="content">
|
||||
<ol class="breadcrumb">
|
||||
<li><a href="#/realms/{{realm.realm}}/users">Users</a></li>
|
||||
|
|
|
@ -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>
|
|
@ -9,6 +9,7 @@ import org.keycloak.models.ProtocolMapperModel;
|
|||
import org.keycloak.models.RealmModel;
|
||||
import org.keycloak.models.RequiredCredentialModel;
|
||||
import org.keycloak.models.RoleModel;
|
||||
import org.keycloak.models.UserConsentModel;
|
||||
import org.keycloak.models.UserCredentialModel;
|
||||
import org.keycloak.models.UserFederationProviderModel;
|
||||
import org.keycloak.models.UserModel;
|
||||
|
@ -22,6 +23,7 @@ import org.keycloak.representations.idm.ProtocolMapperRepresentation;
|
|||
import org.keycloak.representations.idm.RealmEventsConfigRepresentation;
|
||||
import org.keycloak.representations.idm.RealmRepresentation;
|
||||
import org.keycloak.representations.idm.RoleRepresentation;
|
||||
import org.keycloak.representations.idm.UserConsentRepresentation;
|
||||
import org.keycloak.representations.idm.UserFederationProviderRepresentation;
|
||||
import org.keycloak.representations.idm.UserRepresentation;
|
||||
import org.keycloak.representations.idm.UserSessionRepresentation;
|
||||
|
@ -325,4 +327,45 @@ public class ModelToRepresentation {
|
|||
return rep;
|
||||
}
|
||||
|
||||
public static UserConsentRepresentation toRepresentation(UserConsentModel model) {
|
||||
String clientId = model.getClient().getClientId();
|
||||
|
||||
Map<String, List<String>> grantedProtocolMappers = new HashMap<String, List<String>>();
|
||||
for (ProtocolMapperModel protocolMapper : model.getGrantedProtocolMappers()) {
|
||||
String protocol = protocolMapper.getProtocol();
|
||||
List<String> currentProtocolMappers = grantedProtocolMappers.get(protocol);
|
||||
if (currentProtocolMappers == null) {
|
||||
currentProtocolMappers = new LinkedList<String>();
|
||||
grantedProtocolMappers.put(protocol, currentProtocolMappers);
|
||||
}
|
||||
currentProtocolMappers.add(protocolMapper.getName());
|
||||
}
|
||||
|
||||
List<String> grantedRealmRoles = new LinkedList<String>();
|
||||
Map<String, List<String>> grantedClientRoles = new HashMap<String, List<String>>();
|
||||
for (RoleModel role : model.getGrantedRoles()) {
|
||||
if (role.getContainer() instanceof RealmModel) {
|
||||
grantedRealmRoles.add(role.getName());
|
||||
} else {
|
||||
ClientModel client2 = (ClientModel) role.getContainer();
|
||||
|
||||
String clientId2 = client2.getClientId();
|
||||
List<String> currentClientRoles = grantedClientRoles.get(clientId2);
|
||||
if (currentClientRoles == null) {
|
||||
currentClientRoles = new LinkedList<String>();
|
||||
grantedClientRoles.put(clientId2, currentClientRoles);
|
||||
}
|
||||
currentClientRoles.add(role.getName());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
UserConsentRepresentation consentRep = new UserConsentRepresentation();
|
||||
consentRep.setClientId(clientId);
|
||||
consentRep.setGrantedProtocolMappers(grantedProtocolMappers);
|
||||
consentRep.setGrantedRealmRoles(grantedRealmRoles);
|
||||
consentRep.setGrantedClientRoles(grantedClientRoles);
|
||||
return consentRep;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -788,33 +788,8 @@ public class RepresentationToModel {
|
|||
}
|
||||
}
|
||||
if (userRep.getClientConsents() != null) {
|
||||
for (Map.Entry<String, UserConsentRepresentation> entry : userRep.getClientConsents().entrySet()) {
|
||||
ClientModel client = clientMap.get(entry.getKey());
|
||||
if (client == null) {
|
||||
throw new RuntimeException("Unable to find client consent mappings for client: " + entry.getKey());
|
||||
}
|
||||
|
||||
UserConsentModel consentModel = new UserConsentModel(client);
|
||||
|
||||
UserConsentRepresentation consentRep = entry.getValue();
|
||||
if (consentRep.getGrantedRoles() != null) {
|
||||
for (String roleId : consentRep.getGrantedRoles()) {
|
||||
RoleModel role = newRealm.getRoleById(roleId);
|
||||
if (role == null) {
|
||||
throw new RuntimeException("Unable to find realm role referenced in consent mappings of user " + user.getUsername() + ". Role ID: " + roleId);
|
||||
}
|
||||
consentModel.addGrantedRole(role);
|
||||
}
|
||||
}
|
||||
if (consentRep.getGrantedProtocolMappers() != null) {
|
||||
for (String mapperId : consentRep.getGrantedProtocolMappers()) {
|
||||
ProtocolMapperModel protocolMapper = client.getProtocolMapperById(mapperId);
|
||||
if (protocolMapper == null) {
|
||||
throw new RuntimeException("Unable to find protocol mapper referenced in consent mappings of user " + user.getUsername() + ". Protocol mapper ID: " + mapperId);
|
||||
}
|
||||
consentModel.addGrantedProtocolMapper(protocolMapper);
|
||||
}
|
||||
}
|
||||
for (UserConsentRepresentation consentRep : userRep.getClientConsents()) {
|
||||
UserConsentModel consentModel = toModel(newRealm, consentRep);
|
||||
user.addConsent(consentModel);
|
||||
}
|
||||
}
|
||||
|
@ -917,4 +892,53 @@ public class RepresentationToModel {
|
|||
return model;
|
||||
}
|
||||
|
||||
public static UserConsentModel toModel(RealmModel newRealm, UserConsentRepresentation consentRep) {
|
||||
ClientModel client = newRealm.getClientByClientId(consentRep.getClientId());
|
||||
if (client == null) {
|
||||
throw new RuntimeException("Unable to find client consent mappings for client: " + consentRep.getClientId());
|
||||
}
|
||||
|
||||
UserConsentModel consentModel = new UserConsentModel(client);
|
||||
|
||||
if (consentRep.getGrantedRealmRoles() != null) {
|
||||
for (String roleName : consentRep.getGrantedRealmRoles()) {
|
||||
RoleModel role = newRealm.getRole(roleName);
|
||||
if (role == null) {
|
||||
throw new RuntimeException("Unable to find realm role referenced in consent mappings of user. Role name: " + roleName);
|
||||
}
|
||||
consentModel.addGrantedRole(role);
|
||||
}
|
||||
}
|
||||
if (consentRep.getGrantedClientRoles() != null) {
|
||||
for (Map.Entry<String, List<String>> entry : consentRep.getGrantedClientRoles().entrySet()) {
|
||||
String clientId2 = entry.getKey();
|
||||
ClientModel client2 = newRealm.getClientByClientId(clientId2);
|
||||
if (client2 == null) {
|
||||
throw new RuntimeException("Unable to find client referenced in consent mappings. Client ID: " + clientId2);
|
||||
}
|
||||
for (String clientRoleName : entry.getValue()) {
|
||||
RoleModel clientRole = client2.getRole(clientRoleName);
|
||||
if (clientRole == null) {
|
||||
throw new RuntimeException("Unable to find client role referenced in consent mappings of user. Role name: " + clientRole + ", Client: " + clientId2);
|
||||
}
|
||||
consentModel.addGrantedRole(clientRole);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (consentRep.getGrantedProtocolMappers() != null) {
|
||||
for (Map.Entry<String, List<String>> protocolEntry : consentRep.getGrantedProtocolMappers().entrySet()) {
|
||||
String protocol = protocolEntry.getKey();
|
||||
for (String protocolMapperName : protocolEntry.getValue()) {
|
||||
ProtocolMapperModel protocolMapper = client.getProtocolMapperByName(protocol, protocolMapperName);
|
||||
if (protocolMapper == null) {
|
||||
throw new RuntimeException("Unable to find protocol mapper for protocol " + protocol + ", mapper name " + protocolMapperName);
|
||||
}
|
||||
|
||||
consentModel.addGrantedProtocolMapper(protocolMapper);
|
||||
}
|
||||
}
|
||||
}
|
||||
return consentModel;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -17,6 +17,7 @@ import org.keycloak.models.ModelDuplicateException;
|
|||
import org.keycloak.models.ModelReadOnlyException;
|
||||
import org.keycloak.models.RealmModel;
|
||||
import org.keycloak.models.RoleModel;
|
||||
import org.keycloak.models.UserConsentModel;
|
||||
import org.keycloak.models.UserCredentialModel;
|
||||
import org.keycloak.models.UserModel;
|
||||
import org.keycloak.models.UserSessionModel;
|
||||
|
@ -30,6 +31,7 @@ import org.keycloak.representations.idm.CredentialRepresentation;
|
|||
import org.keycloak.representations.idm.FederatedIdentityRepresentation;
|
||||
import org.keycloak.representations.idm.MappingsRepresentation;
|
||||
import org.keycloak.representations.idm.RoleRepresentation;
|
||||
import org.keycloak.representations.idm.UserConsentRepresentation;
|
||||
import org.keycloak.representations.idm.UserRepresentation;
|
||||
import org.keycloak.representations.idm.UserSessionRepresentation;
|
||||
import org.keycloak.services.managers.AuthenticationManager;
|
||||
|
@ -310,6 +312,56 @@ public class UsersResource {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* List set of consents granted by this user.
|
||||
*
|
||||
* @param username
|
||||
* @return
|
||||
*/
|
||||
@Path("{username}/consents")
|
||||
@GET
|
||||
@NoCache
|
||||
@Produces(MediaType.APPLICATION_JSON)
|
||||
public List<UserConsentRepresentation> getConsents(final @PathParam("username") String username) {
|
||||
auth.requireView();
|
||||
UserModel user = session.users().getUserByUsername(username, realm);
|
||||
if (user == null) {
|
||||
throw new NotFoundException("User not found");
|
||||
}
|
||||
|
||||
List<UserConsentModel> consents = user.getConsents();
|
||||
List<UserConsentRepresentation> result = new ArrayList<UserConsentRepresentation>();
|
||||
|
||||
for (UserConsentModel consent : consents) {
|
||||
UserConsentRepresentation rep = ModelToRepresentation.toRepresentation(consent);
|
||||
result.add(rep);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Revoke consent for particular client
|
||||
*
|
||||
* @param username
|
||||
* @param clientId
|
||||
*/
|
||||
@Path("{username}/consents/{client}")
|
||||
@DELETE
|
||||
@NoCache
|
||||
public void revokeConsent(final @PathParam("username") String username, final @PathParam("client") String clientId) {
|
||||
auth.requireManage();
|
||||
UserModel user = session.users().getUserByUsername(username, realm);
|
||||
if (user == null) {
|
||||
throw new NotFoundException("User not found");
|
||||
}
|
||||
|
||||
ClientModel client = realm.getClientByClientId(clientId);
|
||||
boolean revoked = user.revokeConsentForClient(client.getId());
|
||||
if (!revoked) {
|
||||
throw new NotFoundException("Consent not found for user " + username + " and client " + clientId);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove all user sessions associated with this user. And, for all client that have an admin URL, tell
|
||||
* them to invalidate the sessions for this particular user.
|
||||
|
|
|
@ -75,15 +75,22 @@
|
|||
"Application": [ "app-admin" ],
|
||||
"OtherApp": [ "otherapp-admin" ]
|
||||
},
|
||||
"clientConsents": {
|
||||
"Application": {
|
||||
"grantedRoles": [ "456", "789" ]
|
||||
"clientConsents": [
|
||||
{
|
||||
"clientId": "Application",
|
||||
"grantedRealmRoles": [ "admin" ],
|
||||
"grantedClientRoles": {
|
||||
"Application": [ "app-admin" ]
|
||||
}
|
||||
},
|
||||
"OtherApp": {
|
||||
"grantedProtocolMappers": [ "123" ],
|
||||
"grantedRoles": [ "456" ]
|
||||
{
|
||||
"clientId": "OtherApp",
|
||||
"grantedRealmRoles": [ "admin" ],
|
||||
"grantedProtocolMappers": {
|
||||
"openid-connect": [ "gss delegation credential" ]
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"username": "mySocialUser",
|
||||
|
@ -124,7 +131,6 @@
|
|||
"enabled": true,
|
||||
"protocolMappers" : [
|
||||
{
|
||||
"id": "123",
|
||||
"name" : "gss delegation credential",
|
||||
"protocol" : "openid-connect",
|
||||
"protocolMapper" : "oidc-usersessionmodel-note-mapper",
|
||||
|
@ -150,14 +156,12 @@
|
|||
"roles" : {
|
||||
"realm" : [
|
||||
{
|
||||
"id": "456",
|
||||
"name": "admin"
|
||||
}
|
||||
],
|
||||
"application" : {
|
||||
"Application" : [
|
||||
{
|
||||
"id": "789",
|
||||
"name": "app-admin"
|
||||
},
|
||||
{
|
||||
|
|
Loading…
Reference in a new issue