template scope
This commit is contained in:
parent
0527d441e3
commit
d939b6a431
42 changed files with 1294 additions and 132 deletions
|
@ -15,6 +15,17 @@
|
||||||
<column name="REALM_ID" type="VARCHAR(36)"/>
|
<column name="REALM_ID" type="VARCHAR(36)"/>
|
||||||
<column name="DESCRIPTION" type="VARCHAR(255)"/>
|
<column name="DESCRIPTION" type="VARCHAR(255)"/>
|
||||||
<column name="PROTOCOL" type="VARCHAR(255)"/>
|
<column name="PROTOCOL" type="VARCHAR(255)"/>
|
||||||
|
<column name="FULL_SCOPE_ALLOWED" type="BOOLEAN" defaultValueBoolean="false">
|
||||||
|
<constraints nullable="false"/>
|
||||||
|
</column>
|
||||||
|
</createTable>
|
||||||
|
<createTable tableName="TEMPLATE_SCOPE_MAPPING">
|
||||||
|
<column name="TEMPLATE_ID" type="VARCHAR(36)">
|
||||||
|
<constraints nullable="false"/>
|
||||||
|
</column>
|
||||||
|
<column name="ROLE_ID" type="VARCHAR(36)">
|
||||||
|
<constraints nullable="false"/>
|
||||||
|
</column>
|
||||||
</createTable>
|
</createTable>
|
||||||
|
|
||||||
|
|
||||||
|
@ -24,6 +35,15 @@
|
||||||
<column name="CLIENT_TEMPLATE_ID" type="VARCHAR(36)">
|
<column name="CLIENT_TEMPLATE_ID" type="VARCHAR(36)">
|
||||||
<constraints nullable="true"/>
|
<constraints nullable="true"/>
|
||||||
</column>
|
</column>
|
||||||
|
<column name="USE_TEMPLATE_CONFIG" type="BOOLEAN" defaultValueBoolean="false">
|
||||||
|
<constraints nullable="false"/>
|
||||||
|
</column>
|
||||||
|
<column name="USE_TEMPLATE_SCOPE" type="BOOLEAN" defaultValueBoolean="false">
|
||||||
|
<constraints nullable="false"/>
|
||||||
|
</column>
|
||||||
|
<column name="USE_TEMPLATE_MAPPERS" type="BOOLEAN" defaultValueBoolean="false">
|
||||||
|
<constraints nullable="false"/>
|
||||||
|
</column>
|
||||||
</addColumn>
|
</addColumn>
|
||||||
<addColumn tableName="PROTOCOL_MAPPER">
|
<addColumn tableName="PROTOCOL_MAPPER">
|
||||||
<column name="CLIENT_TEMPLATE_ID" type="VARCHAR(36)">
|
<column name="CLIENT_TEMPLATE_ID" type="VARCHAR(36)">
|
||||||
|
@ -46,6 +66,9 @@
|
||||||
<addForeignKeyConstraint baseColumnNames="CLIENT_TEMPLATE_ID" baseTableName="CLIENT" constraintName="FK_CLI_TMPLT_CLIENT" referencedColumnNames="ID" referencedTableName="CLIENT_TEMPLATE"/>
|
<addForeignKeyConstraint baseColumnNames="CLIENT_TEMPLATE_ID" baseTableName="CLIENT" constraintName="FK_CLI_TMPLT_CLIENT" referencedColumnNames="ID" referencedTableName="CLIENT_TEMPLATE"/>
|
||||||
<addForeignKeyConstraint baseColumnNames="REALM_ID" baseTableName="REALM_CLIENT_TEMPLATE" constraintName="FK_RLM_CLI_TMPLT_RLM" referencedColumnNames="ID" referencedTableName="REALM"/>
|
<addForeignKeyConstraint baseColumnNames="REALM_ID" baseTableName="REALM_CLIENT_TEMPLATE" constraintName="FK_RLM_CLI_TMPLT_RLM" referencedColumnNames="ID" referencedTableName="REALM"/>
|
||||||
<addForeignKeyConstraint baseColumnNames="CLIENT_TEMPLATE_ID" baseTableName="REALM_CLIENT_TEMPLATE" constraintName="FK_RLM_CLI_TMPLT_CLI" referencedColumnNames="ID" referencedTableName="CLIENT_TEMPLATE"/>
|
<addForeignKeyConstraint baseColumnNames="CLIENT_TEMPLATE_ID" baseTableName="REALM_CLIENT_TEMPLATE" constraintName="FK_RLM_CLI_TMPLT_CLI" referencedColumnNames="ID" referencedTableName="CLIENT_TEMPLATE"/>
|
||||||
|
<addPrimaryKey columnNames="TEMPLATE_ID, ROLE_ID" constraintName="PK_TEMPLATE_SCOPE" tableName="TEMPLATE_SCOPE_MAPPING"/>
|
||||||
|
<addForeignKeyConstraint baseColumnNames="TEMPLATE_ID" baseTableName="TEMPLATE_SCOPE_MAPPING" constraintName="FK_TEMPL_SCOPE_TEMPL" referencedColumnNames="ID" referencedTableName="CLIENT_TEMPLATE"/>
|
||||||
|
<addForeignKeyConstraint baseColumnNames="ROLE_ID" baseTableName="TEMPLATE_SCOPE_MAPPING" constraintName="FK_TEMPL_SCOPE_ROLE" referencedColumnNames="ID" referencedTableName="KEYCLOAK_ROLE"/>
|
||||||
|
|
||||||
|
|
||||||
</changeSet>
|
</changeSet>
|
||||||
|
|
|
@ -36,6 +36,7 @@
|
||||||
<class>org.keycloak.models.jpa.entities.GroupRoleMappingEntity</class>
|
<class>org.keycloak.models.jpa.entities.GroupRoleMappingEntity</class>
|
||||||
<class>org.keycloak.models.jpa.entities.UserGroupMembershipEntity</class>
|
<class>org.keycloak.models.jpa.entities.UserGroupMembershipEntity</class>
|
||||||
<class>org.keycloak.models.jpa.entities.ClientTemplateEntity</class>
|
<class>org.keycloak.models.jpa.entities.ClientTemplateEntity</class>
|
||||||
|
<class>org.keycloak.models.jpa.entities.TemplateScopeMappingEntity</class>
|
||||||
|
|
||||||
<!-- JpaAuditProviders -->
|
<!-- JpaAuditProviders -->
|
||||||
<class>org.keycloak.events.jpa.EventEntity</class>
|
<class>org.keycloak.events.jpa.EventEntity</class>
|
||||||
|
|
|
@ -41,6 +41,10 @@ public class ClientRepresentation {
|
||||||
protected Map<String, Integer> registeredNodes;
|
protected Map<String, Integer> registeredNodes;
|
||||||
protected List<ProtocolMapperRepresentation> protocolMappers;
|
protected List<ProtocolMapperRepresentation> protocolMappers;
|
||||||
protected String clientTemplate;
|
protected String clientTemplate;
|
||||||
|
private Boolean useTemplateConfig;
|
||||||
|
private Boolean useTemplateScope;
|
||||||
|
private Boolean useTemplateMappers;
|
||||||
|
|
||||||
|
|
||||||
public String getId() {
|
public String getId() {
|
||||||
return id;
|
return id;
|
||||||
|
@ -298,4 +302,29 @@ public class ClientRepresentation {
|
||||||
public void setClientTemplate(String clientTemplate) {
|
public void setClientTemplate(String clientTemplate) {
|
||||||
this.clientTemplate = clientTemplate;
|
this.clientTemplate = clientTemplate;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Boolean isUseTemplateConfig() {
|
||||||
|
return useTemplateConfig;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setUseTemplateConfig(Boolean useTemplateConfig) {
|
||||||
|
this.useTemplateConfig = useTemplateConfig;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Boolean isUseTemplateScope() {
|
||||||
|
return useTemplateScope;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setUseTemplateScope(Boolean useTemplateScope) {
|
||||||
|
this.useTemplateScope = useTemplateScope;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Boolean isUseTemplateMappers() {
|
||||||
|
return useTemplateMappers;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setUseTemplateMappers(Boolean useTemplateMappers) {
|
||||||
|
this.useTemplateMappers = useTemplateMappers;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -16,6 +16,7 @@ public class ClientTemplateRepresentation {
|
||||||
protected String name;
|
protected String name;
|
||||||
protected String description;
|
protected String description;
|
||||||
protected String protocol;
|
protected String protocol;
|
||||||
|
protected Boolean fullScopeAllowed;
|
||||||
protected List<ProtocolMapperRepresentation> protocolMappers;
|
protected List<ProtocolMapperRepresentation> protocolMappers;
|
||||||
|
|
||||||
public String getId() {
|
public String getId() {
|
||||||
|
@ -58,4 +59,12 @@ public class ClientTemplateRepresentation {
|
||||||
public void setProtocol(String protocol) {
|
public void setProtocol(String protocol) {
|
||||||
this.protocol = protocol;
|
this.protocol = protocol;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Boolean isFullScopeAllowed() {
|
||||||
|
return fullScopeAllowed;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setFullScopeAllowed(Boolean fullScopeAllowed) {
|
||||||
|
this.fullScopeAllowed = fullScopeAllowed;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1088,6 +1088,9 @@ module.config([ '$routeProvider', function($routeProvider) {
|
||||||
client : function(ClientLoader) {
|
client : function(ClientLoader) {
|
||||||
return ClientLoader();
|
return ClientLoader();
|
||||||
},
|
},
|
||||||
|
templates : function(ClientTemplateListLoader) {
|
||||||
|
return ClientTemplateListLoader();
|
||||||
|
},
|
||||||
clients : function(ClientListLoader) {
|
clients : function(ClientListLoader) {
|
||||||
return ClientListLoader();
|
return ClientListLoader();
|
||||||
}
|
}
|
||||||
|
@ -1202,6 +1205,21 @@ module.config([ '$routeProvider', function($routeProvider) {
|
||||||
},
|
},
|
||||||
controller : 'ClientTemplateDetailCtrl'
|
controller : 'ClientTemplateDetailCtrl'
|
||||||
})
|
})
|
||||||
|
.when('/realms/:realm/client-templates/:template/scope-mappings', {
|
||||||
|
templateUrl : resourceUrl + '/partials/client-template-scope-mappings.html',
|
||||||
|
resolve : {
|
||||||
|
realm : function(RealmLoader) {
|
||||||
|
return RealmLoader();
|
||||||
|
},
|
||||||
|
template : function(ClientTemplateLoader) {
|
||||||
|
return ClientTemplateLoader();
|
||||||
|
},
|
||||||
|
clients : function(ClientListLoader) {
|
||||||
|
return ClientListLoader();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
controller : 'ClientTemplateScopeMappingCtrl'
|
||||||
|
})
|
||||||
.when('/realms/:realm/clients', {
|
.when('/realms/:realm/clients', {
|
||||||
templateUrl : resourceUrl + '/partials/client-list.html',
|
templateUrl : resourceUrl + '/partials/client-list.html',
|
||||||
resolve : {
|
resolve : {
|
||||||
|
|
|
@ -1089,8 +1089,8 @@ module.controller('ClientDetailCtrl', function($scope, realm, client, templates,
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
|
||||||
module.controller('ClientScopeMappingCtrl', function($scope, $http, realm, client, clients, Notifications,
|
module.controller('ClientScopeMappingCtrl', function($scope, $http, realm, client, clients, templates, Notifications,
|
||||||
Client,
|
Client, ClientTemplate,
|
||||||
ClientRealmScopeMapping, ClientClientScopeMapping, ClientRole,
|
ClientRealmScopeMapping, ClientClientScopeMapping, ClientRole,
|
||||||
ClientAvailableRealmScopeMapping, ClientAvailableClientScopeMapping,
|
ClientAvailableRealmScopeMapping, ClientAvailableClientScopeMapping,
|
||||||
ClientCompositeRealmScopeMapping, ClientCompositeClientScopeMapping) {
|
ClientCompositeRealmScopeMapping, ClientCompositeClientScopeMapping) {
|
||||||
|
@ -1107,8 +1107,20 @@ module.controller('ClientScopeMappingCtrl', function($scope, $http, realm, clien
|
||||||
$scope.clientMappings = [];
|
$scope.clientMappings = [];
|
||||||
$scope.dummymodel = [];
|
$scope.dummymodel = [];
|
||||||
|
|
||||||
|
if (client.clientTemplate) {
|
||||||
|
for (var i = 0; i < templates.length; i++) {
|
||||||
|
if (templates[i].name == client.clientTemplate) {
|
||||||
|
ClientTemplate.get({realm: realm.realm, template: templates[i].id}, function(data) {
|
||||||
|
$scope.template = data;
|
||||||
|
});
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
$scope.changeFullScopeAllowed = function() {
|
}
|
||||||
|
|
||||||
|
|
||||||
|
$scope.changeFlag = function() {
|
||||||
Client.update({
|
Client.update({
|
||||||
realm : realm.realm,
|
realm : realm.realm,
|
||||||
client : client.id
|
client : client.id
|
||||||
|
@ -1122,6 +1134,7 @@ module.controller('ClientScopeMappingCtrl', function($scope, $http, realm, clien
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
function updateRealmRoles() {
|
function updateRealmRoles() {
|
||||||
$scope.realmRoles = ClientAvailableRealmScopeMapping.query({realm : realm.realm, client : client.id});
|
$scope.realmRoles = ClientAvailableRealmScopeMapping.query({realm : realm.realm, client : client.id});
|
||||||
$scope.realmMappings = ClientRealmScopeMapping.query({realm : realm.realm, client : client.id});
|
$scope.realmMappings = ClientRealmScopeMapping.query({realm : realm.realm, client : client.id});
|
||||||
|
@ -1420,6 +1433,7 @@ module.controller('AddBuiltinProtocolMapperCtrl', function($scope, realm, client
|
||||||
});
|
});
|
||||||
|
|
||||||
module.controller('ClientProtocolMapperListCtrl', function($scope, realm, client, templates, serverInfo,
|
module.controller('ClientProtocolMapperListCtrl', function($scope, realm, client, templates, serverInfo,
|
||||||
|
Client,
|
||||||
ClientProtocolMappersByProtocol, ClientProtocolMapper,
|
ClientProtocolMappersByProtocol, ClientProtocolMapper,
|
||||||
$route, Dialog, Notifications) {
|
$route, Dialog, Notifications) {
|
||||||
$scope.realm = realm;
|
$scope.realm = realm;
|
||||||
|
@ -1435,6 +1449,16 @@ module.controller('ClientProtocolMapperListCtrl', function($scope, realm, client
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
$scope.changeFlag = function() {
|
||||||
|
Client.update({
|
||||||
|
realm : realm.realm,
|
||||||
|
client : client.id
|
||||||
|
}, $scope.client, function() {
|
||||||
|
$scope.changed = false;
|
||||||
|
client = angular.copy($scope.client);
|
||||||
|
Notifications.success("Client updated.");
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
var protocolMappers = serverInfo.protocolMapperTypes[client.protocol];
|
var protocolMappers = serverInfo.protocolMapperTypes[client.protocol];
|
||||||
var mapperTypes = {};
|
var mapperTypes = {};
|
||||||
|
@ -1910,6 +1934,104 @@ module.controller('ClientTemplateAddBuiltinProtocolMapperCtrl', function($scope,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
|
module.controller('ClientTemplateScopeMappingCtrl', function($scope, $http, realm, template, clients, Notifications,
|
||||||
|
ClientTemplate,
|
||||||
|
ClientTemplateRealmScopeMapping, ClientTemplateClientScopeMapping, ClientRole,
|
||||||
|
ClientTemplateAvailableRealmScopeMapping, ClientTemplateAvailableClientScopeMapping,
|
||||||
|
ClientTemplateCompositeRealmScopeMapping, ClientTemplateCompositeClientScopeMapping) {
|
||||||
|
$scope.realm = realm;
|
||||||
|
$scope.template = angular.copy(template);
|
||||||
|
$scope.selectedRealmRoles = [];
|
||||||
|
$scope.selectedRealmMappings = [];
|
||||||
|
$scope.realmMappings = [];
|
||||||
|
$scope.clients = clients;
|
||||||
|
$scope.clientRoles = [];
|
||||||
|
$scope.clientComposite = [];
|
||||||
|
$scope.selectedClientRoles = [];
|
||||||
|
$scope.selectedClientMappings = [];
|
||||||
|
$scope.clientMappings = [];
|
||||||
|
$scope.dummymodel = [];
|
||||||
|
|
||||||
|
|
||||||
|
$scope.changeFullScopeAllowed = function() {
|
||||||
|
ClientTemplate.update({
|
||||||
|
realm : realm.realm,
|
||||||
|
template : template.id
|
||||||
|
}, $scope.template, function() {
|
||||||
|
$scope.changed = false;
|
||||||
|
template = angular.copy($scope.template);
|
||||||
|
updateTemplateRealmRoles();
|
||||||
|
Notifications.success("Scope mappings updated.");
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
function updateTemplateRealmRoles() {
|
||||||
|
$scope.realmRoles = ClientTemplateAvailableRealmScopeMapping.query({realm : realm.realm, template : template.id});
|
||||||
|
$scope.realmMappings = ClientTemplateRealmScopeMapping.query({realm : realm.realm, template : template.id});
|
||||||
|
$scope.realmComposite = ClientTemplateCompositeRealmScopeMapping.query({realm : realm.realm, template : template.id});
|
||||||
|
}
|
||||||
|
|
||||||
|
function updateTemplateClientRoles() {
|
||||||
|
if ($scope.targetClient) {
|
||||||
|
$scope.clientRoles = ClientTemplateAvailableClientScopeMapping.query({realm : realm.realm, template : template.id, targetClient : $scope.targetClient.id});
|
||||||
|
$scope.clientMappings = ClientTemplateClientScopeMapping.query({realm : realm.realm, template : template.id, targetClient : $scope.targetClient.id});
|
||||||
|
$scope.clientComposite = ClientTemplateCompositeClientScopeMapping.query({realm : realm.realm, template : template.id, targetClient : $scope.targetClient.id});
|
||||||
|
} else {
|
||||||
|
$scope.clientRoles = null;
|
||||||
|
$scope.clientMappings = null;
|
||||||
|
$scope.clientComposite = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$scope.changeClient = function() {
|
||||||
|
updateTemplateClientRoles();
|
||||||
|
};
|
||||||
|
|
||||||
|
$scope.addRealmRole = function() {
|
||||||
|
var roles = $scope.selectedRealmRoles;
|
||||||
|
$scope.selectedRealmRoles = [];
|
||||||
|
$http.post(authUrl + '/admin/realms/' + realm.realm + '/client-templates/' + template.id + '/scope-mappings/realm',
|
||||||
|
roles).success(function() {
|
||||||
|
updateTemplateRealmRoles();
|
||||||
|
Notifications.success("Scope mappings updated.");
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
$scope.deleteRealmRole = function() {
|
||||||
|
var roles = $scope.selectedRealmMappings;
|
||||||
|
$scope.selectedRealmMappings = [];
|
||||||
|
$http.delete(authUrl + '/admin/realms/' + realm.realm + '/client-templates/' + template.id + '/scope-mappings/realm',
|
||||||
|
{data : roles, headers : {"content-type" : "application/json"}}).success(function () {
|
||||||
|
updateTemplateRealmRoles();
|
||||||
|
Notifications.success("Scope mappings updated.");
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
$scope.addClientRole = function() {
|
||||||
|
var roles = $scope.selectedClientRoles;
|
||||||
|
$scope.selectedClientRoles = [];
|
||||||
|
$http.post(authUrl + '/admin/realms/' + realm.realm + '/client-templates/' + template.id + '/scope-mappings/clients/' + $scope.targetClient.id,
|
||||||
|
roles).success(function () {
|
||||||
|
updateTemplateClientRoles();
|
||||||
|
Notifications.success("Scope mappings updated.");
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
$scope.deleteClientRole = function() {
|
||||||
|
var roles = $scope.selectedClientMappings;
|
||||||
|
$scope.selectedClientMappings = [];
|
||||||
|
$http.delete(authUrl + '/admin/realms/' + realm.realm + '/client-templates/' + template.id + '/scope-mappings/clients/' + $scope.targetClient.id,
|
||||||
|
{data : roles, headers : {"content-type" : "application/json"}}).success(function () {
|
||||||
|
updateTemplateClientRoles();
|
||||||
|
Notifications.success("Scope mappings updated.");
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
updateTemplateRealmRoles();
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -848,6 +848,52 @@ module.factory('ClientTemplateProtocolMappersByProtocol', function($resource) {
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
module.factory('ClientTemplateRealmScopeMapping', function($resource) {
|
||||||
|
return $resource(authUrl + '/admin/realms/:realm/client-templates/:template/scope-mappings/realm', {
|
||||||
|
realm : '@realm',
|
||||||
|
template : '@template'
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
module.factory('ClientTemplateAvailableRealmScopeMapping', function($resource) {
|
||||||
|
return $resource(authUrl + '/admin/realms/:realm/client-templates/:template/scope-mappings/realm/available', {
|
||||||
|
realm : '@realm',
|
||||||
|
template : '@template'
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
module.factory('ClientTemplateCompositeRealmScopeMapping', function($resource) {
|
||||||
|
return $resource(authUrl + '/admin/realms/:realm/client-templates/:template/scope-mappings/realm/composite', {
|
||||||
|
realm : '@realm',
|
||||||
|
template : '@template'
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
module.factory('ClientTemplateClientScopeMapping', function($resource) {
|
||||||
|
return $resource(authUrl + '/admin/realms/:realm/client-templates/:template/scope-mappings/clients/:targetClient', {
|
||||||
|
realm : '@realm',
|
||||||
|
template : '@template',
|
||||||
|
targetClient : '@targetClient'
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
module.factory('ClientTemplateAvailableClientScopeMapping', function($resource) {
|
||||||
|
return $resource(authUrl + '/admin/realms/:realm/client-templates/:template/scope-mappings/clients/:targetClient/available', {
|
||||||
|
realm : '@realm',
|
||||||
|
template : '@template',
|
||||||
|
targetClient : '@targetClient'
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
module.factory('ClientTemplateCompositeClientScopeMapping', function($resource) {
|
||||||
|
return $resource(authUrl + '/admin/realms/:realm/client-templates/:template/scope-mappings/clients/:targetClient/composite', {
|
||||||
|
realm : '@realm',
|
||||||
|
template : '@template',
|
||||||
|
targetClient : '@targetClient'
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
module.factory('ClientSessionStats', function($resource) {
|
module.factory('ClientSessionStats', function($resource) {
|
||||||
return $resource(authUrl + '/admin/realms/:realm/clients/:client/session-stats', {
|
return $resource(authUrl + '/admin/realms/:realm/clients/:client/session-stats', {
|
||||||
realm : '@realm',
|
realm : '@realm',
|
||||||
|
|
|
@ -7,6 +7,20 @@
|
||||||
|
|
||||||
<kc-tabs-client></kc-tabs-client>
|
<kc-tabs-client></kc-tabs-client>
|
||||||
|
|
||||||
|
<form class="form-horizontal" name="allowScope" novalidate kc-read-only="!access.manageClients">
|
||||||
|
<fieldset class="border-top">
|
||||||
|
<div class="form-group" ng-show="client.clientTemplate">
|
||||||
|
<label class="col-md-2 control-label" for="useTemplateScope">Inherit Template Mappers</label>
|
||||||
|
<kc-tooltip>Inherit mappers from client template</kc-tooltip>
|
||||||
|
<div class="col-md-1">
|
||||||
|
<input ng-model="client.useTemplateMappers" ng-click="changeFlag()" name="useTemplateScope" id="useTemplateScope" onoffswitch on-text="{{:: 'onText' | translate}}" off-text="{{:: 'offText' | translate}}" />
|
||||||
|
</div>
|
||||||
|
<div class="col-md-2">
|
||||||
|
<a href="#/realms/{{realm.realm}}/client-templates/{{template.id}}/mappers">view template mappers</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</fieldset>
|
||||||
|
</form>
|
||||||
<table class="table table-striped table-bordered">
|
<table class="table table-striped table-bordered">
|
||||||
<thead>
|
<thead>
|
||||||
<tr>
|
<tr>
|
||||||
|
@ -24,7 +38,6 @@
|
||||||
<div class="pull-right" data-ng-show="access.manageClients">
|
<div class="pull-right" data-ng-show="access.manageClients">
|
||||||
<a class="btn btn-default" href="#/create/client/{{realm.realm}}/{{client.id}}/mappers">{{:: 'create' | translate}}</a>
|
<a class="btn btn-default" href="#/create/client/{{realm.realm}}/{{client.id}}/mappers">{{:: 'create' | translate}}</a>
|
||||||
<a class="btn btn-default" href="#/realms/{{realm.realm}}/clients/{{client.id}}/add-mappers">{{:: 'add-builtin' | translate}}</a>
|
<a class="btn btn-default" href="#/realms/{{realm.realm}}/clients/{{client.id}}/add-mappers">{{:: 'add-builtin' | translate}}</a>
|
||||||
<a ng-show="template" class="btn btn-default" href="#/realms/{{realm.realm}}/client-templates/{{template.id}}/mappers">Inherited Template Mappers</a>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</th>
|
</th>
|
||||||
|
|
|
@ -11,17 +11,37 @@
|
||||||
<p class="subtitle"></p>
|
<p class="subtitle"></p>
|
||||||
<form class="form-horizontal" name="allowScope" novalidate kc-read-only="!access.manageClients">
|
<form class="form-horizontal" name="allowScope" novalidate kc-read-only="!access.manageClients">
|
||||||
<fieldset class="border-top">
|
<fieldset class="border-top">
|
||||||
<div class="form-group">
|
<div class="form-group" ng-show="client.clientTemplate">
|
||||||
|
<label class="col-md-2 control-label" for="useTemplateScope">Inherit Template Scope</label>
|
||||||
|
<kc-tooltip>Inherit scope from client template</kc-tooltip>
|
||||||
|
<div class="col-md-1">
|
||||||
|
<input ng-model="client.useTemplateScope" ng-click="changeFlag()" name="useTemplateScope" id="useTemplateScope" onoffswitch on-text="{{:: 'onText' | translate}}" off-text="{{:: 'offText' | translate}}" />
|
||||||
|
</div>
|
||||||
|
<div class="col-md-2">
|
||||||
|
<a href="#/realms/{{realm.realm}}/client-templates/{{template.id}}/scope-mappings">view template scope</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="form-group" ng-hide="client.useTemplateScope && template && template.fullScopeAllowed">
|
||||||
<label class="col-md-2 control-label" for="fullScopeAllowed">{{:: 'full-scope-allowed' | translate}}</label>
|
<label class="col-md-2 control-label" for="fullScopeAllowed">{{:: 'full-scope-allowed' | translate}}</label>
|
||||||
<kc-tooltip>{{:: 'full-scope-allowed.tooltip' | translate}}</kc-tooltip>
|
<kc-tooltip>{{:: 'full-scope-allowed.tooltip' | translate}}</kc-tooltip>
|
||||||
<div class="col-md-6">
|
<div class="col-md-6">
|
||||||
<input ng-model="client.fullScopeAllowed" ng-click="changeFullScopeAllowed()" name="fullScopeAllowed" id="fullScopeAllowed" onoffswitch on-text="{{:: 'onText' | translate}}" off-text="{{:: 'offText' | translate}}" />
|
<input ng-model="client.fullScopeAllowed" ng-click="changeFlag()" name="fullScopeAllowed" id="fullScopeAllowed" onoffswitch on-text="{{:: 'onText' | translate}}" off-text="{{:: 'offText' | translate}}" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="form-group" ng-show="client.useTemplateScope && template && template.fullScopeAllowed">
|
||||||
|
<label class="col-md-2 control-label" for="fullScopeAllowed">{{:: 'full-scope-allowed' | translate}}</label>
|
||||||
|
<kc-tooltip>Client template has full scope allowed, which means this client will have the full scope of all roles.</kc-tooltip>
|
||||||
|
<div class="col-md-1">
|
||||||
|
<input ng-model="template.fullScopeAllowed" name="fullScopeAllowed" id="fullScopeAllowed" ng-disabled="true" onoffswitch />
|
||||||
|
</div>
|
||||||
|
<div class="col-md-1">
|
||||||
|
<i>inherited</i>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</fieldset>
|
</fieldset>
|
||||||
</form>
|
</form>
|
||||||
|
|
||||||
<form class="form-horizontal" name="realmForm" novalidate kc-read-only="!access.manageClients" data-ng-show="!client.fullScopeAllowed">
|
<form class="form-horizontal" name="realmForm" novalidate kc-read-only="!access.manageClients" data-ng-show="!client.fullScopeAllowed" data-ng-hide="client.useTemplateScope && template && template.fullScopeAllowed">
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<label class="col-md-2 control-label" class="control-label">{{:: 'realm-roles' | translate}}</label>
|
<label class="col-md-2 control-label" class="control-label">{{:: 'realm-roles' | translate}}</label>
|
||||||
<div class="col-md-10">
|
<div class="col-md-10">
|
||||||
|
|
|
@ -0,0 +1,117 @@
|
||||||
|
<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}}/client-templates">Client Templates</a></li>
|
||||||
|
<li>{{template.name}}</li>
|
||||||
|
</ol>
|
||||||
|
|
||||||
|
<kc-tabs-client-template></kc-tabs-client-template>
|
||||||
|
|
||||||
|
<h2><span>{{template.name}}</span> {{:: 'scope-mappings' | translate}} </h2>
|
||||||
|
<p class="subtitle"></p>
|
||||||
|
<form class="form-horizontal" name="allowScope" novalidate kc-read-only="!access.manageClients">
|
||||||
|
<fieldset class="border-top">
|
||||||
|
<div class="form-group">
|
||||||
|
<label class="col-md-2 control-label" for="fullScopeAllowed">{{:: 'full-scope-allowed' | translate}}</label>
|
||||||
|
<kc-tooltip>{{:: 'full-scope-allowed.tooltip' | translate}}</kc-tooltip>
|
||||||
|
<div class="col-md-6">
|
||||||
|
<input ng-model="template.fullScopeAllowed" ng-click="changeFullScopeAllowed()" name="fullScopeAllowed" id="fullScopeAllowed" onoffswitch on-text="{{:: 'onText' | translate}}" off-text="{{:: 'offText' | translate}}" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</fieldset>
|
||||||
|
</form>
|
||||||
|
|
||||||
|
<form class="form-horizontal" name="realmForm" novalidate kc-read-only="!access.manageClients" data-ng-show="!template.fullScopeAllowed">
|
||||||
|
<div class="form-group">
|
||||||
|
<label class="col-md-2 control-label" class="control-label">{{:: 'realm-roles' | translate}}</label>
|
||||||
|
<div class="col-md-10">
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-md-3">
|
||||||
|
<label class="control-label" for="available">{{:: 'available-roles' | translate}}</label>
|
||||||
|
<kc-tooltip>{{:: 'scope.available-roles.tooltip' | translate}}</kc-tooltip>
|
||||||
|
|
||||||
|
<select id="available" class="form-control" multiple size="5"
|
||||||
|
ng-multiple="true"
|
||||||
|
ng-model="selectedRealmRoles"
|
||||||
|
ng-options="r.name for r in realmRoles">
|
||||||
|
</select>
|
||||||
|
<button ng-disabled="selectedRealmRoles.length == 0" class="btn btn-default" type="submit" ng-click="addRealmRole()">
|
||||||
|
{{:: 'add-selected' | translate}} <i class="fa fa-angle-double-right"></i>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
<div class="col-md-3">
|
||||||
|
<label class="control-label" for="assigned">{{:: 'assigned-roles' | translate}}</label>
|
||||||
|
<kc-tooltip>{{:: 'assigned-roles.tooltip' | translate}}</kc-tooltip>
|
||||||
|
<select id="assigned" class="form-control" multiple size=5
|
||||||
|
ng-multiple="true"
|
||||||
|
ng-model="selectedRealmMappings"
|
||||||
|
ng-options="r.name for r in realmMappings">
|
||||||
|
</select>
|
||||||
|
<button ng-disabled="selectedRealmMappings.length == 0" class="btn btn-default" type="submit" ng-click="deleteRealmRole()">
|
||||||
|
<i class="fa fa-angle-double-left"></i> {{:: 'remove-selected' | translate}}
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
<div class="col-md-3">
|
||||||
|
<label class="control-label" for="realm-composite">{{:: 'effective-roles' | translate}} </label>
|
||||||
|
<kc-tooltip>{{:: 'realm.effective-roles.tooltip' | translate}}</kc-tooltip>
|
||||||
|
<select id="realm-composite" class="form-control" multiple size=5
|
||||||
|
disabled="true"
|
||||||
|
ng-model="dummymodel"
|
||||||
|
ng-options="r.name for r in realmComposite">
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="form-group">
|
||||||
|
<label class="col-md-2 control-label" class="control-label">
|
||||||
|
<span>{{:: 'client-roles' | translate}}</span>
|
||||||
|
<select class="form-control" id="clients" name="clients" ng-change="changeClient()" ng-model="targetClient" ng-options="a.clientId for a in clients" ng-disabled="false"></select>
|
||||||
|
</label>
|
||||||
|
|
||||||
|
<div class="col-md-10">
|
||||||
|
<div class="row" data-ng-hide="targetClient">
|
||||||
|
<div class="col-md-4"><span class="text-muted">{{:: 'select-client-roles.tooltip' | translate}}</span></div>
|
||||||
|
</div>
|
||||||
|
<div class="row" data-ng-show="targetClient">
|
||||||
|
<div class="col-md-3">
|
||||||
|
<label class="control-label" for="available-client">{{:: 'available-roles' | translate}}</label>
|
||||||
|
<kc-tooltip>{{:: 'assign.available-roles.tooltip' | translate}}</kc-tooltip>
|
||||||
|
<select id="available-client" class="form-control" multiple size="5"
|
||||||
|
ng-multiple="true"
|
||||||
|
ng-model="selectedClientRoles"
|
||||||
|
ng-options="r.name for r in clientRoles">
|
||||||
|
</select>
|
||||||
|
<button ng-disabled="selectedClientRoles.length == 0" class="btn btn-default" type="submit" ng-click="addClientRole()">
|
||||||
|
{{:: 'add-selected' | translate}} <i class="fa fa-angle-double-right"></i>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
<div class="col-md-3">
|
||||||
|
<label class="control-label" for="assigned-client">{{:: 'assigned-roles' | translate}}</label>
|
||||||
|
<kc-tooltip>{{:: 'client.assigned-roles.tooltip' | translate}}</kc-tooltip>
|
||||||
|
<select id="assigned-client" class="form-control" multiple size=5
|
||||||
|
ng-multiple="true"
|
||||||
|
ng-model="selectedClientMappings"
|
||||||
|
ng-options="r.name for r in clientMappings">
|
||||||
|
</select>
|
||||||
|
<button ng-disabled="selectedClientMappings.length == 0" class="btn btn-default" type="submit" ng-click="deleteClientRole()">
|
||||||
|
<i class="fa fa-angle-double-left"></i> {{:: 'remove-selected' | translate}}
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
<div class="col-md-3">
|
||||||
|
<label class="control-label" for="client-composite">{{:: 'effective-roles' | translate}}</label>
|
||||||
|
<kc-tooltip>{{:: 'client.effective-roles.tooltip' | translate}}</kc-tooltip>
|
||||||
|
<select id="client-composite" class="form-control" multiple size=5
|
||||||
|
disabled="true"
|
||||||
|
ng-model="dummymodel"
|
||||||
|
ng-options="r.name for r in clientComposite">
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<kc-menu></kc-menu>
|
|
@ -12,5 +12,9 @@
|
||||||
<a href="#/realms/{{realm.realm}}/client-templates/{{template.id}}/mappers">{{:: 'mappers' | translate}}</a>
|
<a href="#/realms/{{realm.realm}}/client-templates/{{template.id}}/mappers">{{:: 'mappers' | translate}}</a>
|
||||||
<kc-tooltip>{{:: 'mappers.tooltip' | translate}}</kc-tooltip>
|
<kc-tooltip>{{:: 'mappers.tooltip' | translate}}</kc-tooltip>
|
||||||
</li>
|
</li>
|
||||||
|
<li ng-class="{active: path[4] == 'scope-mappings'}" >
|
||||||
|
<a href="#/realms/{{realm.realm}}/client-templates/{{template.id}}/scope-mappings">{{:: 'scope' | translate}}</a>
|
||||||
|
<kc-tooltip>{{:: 'scope.tooltip' | translate}}</kc-tooltip>
|
||||||
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
|
@ -27,6 +27,9 @@ public interface ClientTemplateResource {
|
||||||
@Path("protocol-mappers")
|
@Path("protocol-mappers")
|
||||||
public ProtocolMappersResource getProtocolMappers();
|
public ProtocolMappersResource getProtocolMappers();
|
||||||
|
|
||||||
|
@Path("/scope-mappings")
|
||||||
|
public RoleMappingResource getScopeMappings();
|
||||||
|
|
||||||
@GET
|
@GET
|
||||||
@Produces(MediaType.APPLICATION_JSON)
|
@Produces(MediaType.APPLICATION_JSON)
|
||||||
public ClientTemplateRepresentation toRepresentation();
|
public ClientTemplateRepresentation toRepresentation();
|
||||||
|
@ -37,4 +40,6 @@ public interface ClientTemplateResource {
|
||||||
|
|
||||||
@DELETE
|
@DELETE
|
||||||
public void remove();
|
public void remove();
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
|
@ -8,7 +8,7 @@ import java.util.Set;
|
||||||
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
|
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
|
||||||
* @version $Revision: 1 $
|
* @version $Revision: 1 $
|
||||||
*/
|
*/
|
||||||
public interface ClientModel extends RoleContainerModel, ProtocolMapperContainerModel {
|
public interface ClientModel extends RoleContainerModel, ProtocolMapperContainerModel, ScopeContainerModel {
|
||||||
|
|
||||||
// COMMON ATTRIBUTES
|
// COMMON ATTRIBUTES
|
||||||
|
|
||||||
|
@ -74,7 +74,6 @@ public interface ClientModel extends RoleContainerModel, ProtocolMapperContaine
|
||||||
|
|
||||||
void updateDefaultRoles(String[] defaultRoles);
|
void updateDefaultRoles(String[] defaultRoles);
|
||||||
|
|
||||||
Set<RoleModel> getClientScopeMappings(ClientModel client);
|
|
||||||
|
|
||||||
boolean isBearerOnly();
|
boolean isBearerOnly();
|
||||||
void setBearerOnly(boolean only);
|
void setBearerOnly(boolean only);
|
||||||
|
@ -93,9 +92,6 @@ public interface ClientModel extends RoleContainerModel, ProtocolMapperContaine
|
||||||
String getRegistrationToken();
|
String getRegistrationToken();
|
||||||
void setRegistrationToken(String registrationToken);
|
void setRegistrationToken(String registrationToken);
|
||||||
|
|
||||||
boolean isFullScopeAllowed();
|
|
||||||
void setFullScopeAllowed(boolean value);
|
|
||||||
|
|
||||||
String getProtocol();
|
String getProtocol();
|
||||||
void setProtocol(String protocol);
|
void setProtocol(String protocol);
|
||||||
|
|
||||||
|
@ -126,16 +122,16 @@ public interface ClientModel extends RoleContainerModel, ProtocolMapperContaine
|
||||||
boolean isServiceAccountsEnabled();
|
boolean isServiceAccountsEnabled();
|
||||||
void setServiceAccountsEnabled(boolean serviceAccountsEnabled);
|
void setServiceAccountsEnabled(boolean serviceAccountsEnabled);
|
||||||
|
|
||||||
Set<RoleModel> getScopeMappings();
|
|
||||||
void addScopeMapping(RoleModel role);
|
|
||||||
void deleteScopeMapping(RoleModel role);
|
|
||||||
Set<RoleModel> getRealmScopeMappings();
|
|
||||||
boolean hasScope(RoleModel role);
|
|
||||||
|
|
||||||
RealmModel getRealm();
|
RealmModel getRealm();
|
||||||
|
|
||||||
ClientTemplateModel getClientTemplate();
|
ClientTemplateModel getClientTemplate();
|
||||||
void setClientTemplate(ClientTemplateModel template);
|
void setClientTemplate(ClientTemplateModel template);
|
||||||
|
boolean useTemplateScope();
|
||||||
|
void setUseTemplateScope(boolean flag);
|
||||||
|
boolean useTemplateMappers();
|
||||||
|
void setUseTemplateMappers(boolean flag);
|
||||||
|
boolean useTemplateConfig();
|
||||||
|
void setUseTemplateConfig(boolean flag);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Time in seconds since epoc
|
* Time in seconds since epoc
|
||||||
|
|
|
@ -8,7 +8,7 @@ import java.util.Set;
|
||||||
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
|
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
|
||||||
* @version $Revision: 1 $
|
* @version $Revision: 1 $
|
||||||
*/
|
*/
|
||||||
public interface ClientTemplateModel extends ProtocolMapperContainerModel {
|
public interface ClientTemplateModel extends ProtocolMapperContainerModel, ScopeContainerModel {
|
||||||
String getId();
|
String getId();
|
||||||
|
|
||||||
String getName();
|
String getName();
|
||||||
|
|
24
model/api/src/main/java/org/keycloak/models/ScopeContainerModel.java
Executable file
24
model/api/src/main/java/org/keycloak/models/ScopeContainerModel.java
Executable file
|
@ -0,0 +1,24 @@
|
||||||
|
package org.keycloak.models;
|
||||||
|
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
|
||||||
|
* @version $Revision: 1 $
|
||||||
|
*/
|
||||||
|
public interface ScopeContainerModel {
|
||||||
|
boolean isFullScopeAllowed();
|
||||||
|
|
||||||
|
void setFullScopeAllowed(boolean value);
|
||||||
|
|
||||||
|
Set<RoleModel> getScopeMappings();
|
||||||
|
|
||||||
|
void addScopeMapping(RoleModel role);
|
||||||
|
|
||||||
|
void deleteScopeMapping(RoleModel role);
|
||||||
|
|
||||||
|
Set<RoleModel> getRealmScopeMappings();
|
||||||
|
|
||||||
|
boolean hasScope(RoleModel role);
|
||||||
|
|
||||||
|
}
|
|
@ -1,9 +0,0 @@
|
||||||
package org.keycloak.models;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
|
|
||||||
* @version $Revision: 1 $
|
|
||||||
*/
|
|
||||||
public interface ScopeMapperModel {
|
|
||||||
|
|
||||||
}
|
|
|
@ -49,6 +49,9 @@ public class ClientEntity extends AbstractIdentifiableEntity {
|
||||||
private List<ClientIdentityProviderMappingEntity> identityProviders = new ArrayList<ClientIdentityProviderMappingEntity>();
|
private List<ClientIdentityProviderMappingEntity> identityProviders = new ArrayList<ClientIdentityProviderMappingEntity>();
|
||||||
private List<ProtocolMapperEntity> protocolMappers = new ArrayList<ProtocolMapperEntity>();
|
private List<ProtocolMapperEntity> protocolMappers = new ArrayList<ProtocolMapperEntity>();
|
||||||
private String clientTemplate;
|
private String clientTemplate;
|
||||||
|
private boolean useTemplateConfig;
|
||||||
|
private boolean useTemplateScope;
|
||||||
|
private boolean useTemplateMappers;
|
||||||
|
|
||||||
public String getClientId() {
|
public String getClientId() {
|
||||||
return clientId;
|
return clientId;
|
||||||
|
@ -309,5 +312,29 @@ public class ClientEntity extends AbstractIdentifiableEntity {
|
||||||
public void setClientTemplate(String clientTemplate) {
|
public void setClientTemplate(String clientTemplate) {
|
||||||
this.clientTemplate = clientTemplate;
|
this.clientTemplate = clientTemplate;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public boolean isUseTemplateConfig() {
|
||||||
|
return useTemplateConfig;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setUseTemplateConfig(boolean useTemplateConfig) {
|
||||||
|
this.useTemplateConfig = useTemplateConfig;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isUseTemplateScope() {
|
||||||
|
return useTemplateScope;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setUseTemplateScope(boolean useTemplateScope) {
|
||||||
|
this.useTemplateScope = useTemplateScope;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isUseTemplateMappers() {
|
||||||
|
return useTemplateMappers;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setUseTemplateMappers(boolean useTemplateMappers) {
|
||||||
|
this.useTemplateMappers = useTemplateMappers;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -14,6 +14,8 @@ public class ClientTemplateEntity extends AbstractIdentifiableEntity {
|
||||||
private String description;
|
private String description;
|
||||||
private String realmId;
|
private String realmId;
|
||||||
private String protocol;
|
private String protocol;
|
||||||
|
private boolean fullScopeAllowed;
|
||||||
|
private List<String> scopeIds = new ArrayList<String>();
|
||||||
private List<ProtocolMapperEntity> protocolMappers = new ArrayList<ProtocolMapperEntity>();
|
private List<ProtocolMapperEntity> protocolMappers = new ArrayList<ProtocolMapperEntity>();
|
||||||
|
|
||||||
public String getName() {
|
public String getName() {
|
||||||
|
@ -55,5 +57,21 @@ public class ClientTemplateEntity extends AbstractIdentifiableEntity {
|
||||||
public void setProtocol(String protocol) {
|
public void setProtocol(String protocol) {
|
||||||
this.protocol = protocol;
|
this.protocol = protocol;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public boolean isFullScopeAllowed() {
|
||||||
|
return fullScopeAllowed;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setFullScopeAllowed(boolean fullScopeAllowed) {
|
||||||
|
this.fullScopeAllowed = fullScopeAllowed;
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<String> getScopeIds() {
|
||||||
|
return scopeIds;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setScopeIds(List<String> scopeIds) {
|
||||||
|
this.scopeIds = scopeIds;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -15,7 +15,9 @@ import org.keycloak.models.KeycloakSessionTask;
|
||||||
import org.keycloak.models.KeycloakTransaction;
|
import org.keycloak.models.KeycloakTransaction;
|
||||||
import org.keycloak.models.ModelDuplicateException;
|
import org.keycloak.models.ModelDuplicateException;
|
||||||
import org.keycloak.models.RealmModel;
|
import org.keycloak.models.RealmModel;
|
||||||
|
import org.keycloak.models.RoleContainerModel;
|
||||||
import org.keycloak.models.RoleModel;
|
import org.keycloak.models.RoleModel;
|
||||||
|
import org.keycloak.models.ScopeContainerModel;
|
||||||
import org.keycloak.models.UserCredentialModel;
|
import org.keycloak.models.UserCredentialModel;
|
||||||
import org.keycloak.models.UserFederationMapperModel;
|
import org.keycloak.models.UserFederationMapperModel;
|
||||||
import org.keycloak.models.UserFederationProviderModel;
|
import org.keycloak.models.UserFederationProviderModel;
|
||||||
|
@ -38,6 +40,7 @@ import java.security.SecureRandom;
|
||||||
import java.security.cert.X509Certificate;
|
import java.security.cert.X509Certificate;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
|
import java.util.HashSet;
|
||||||
import java.util.LinkedList;
|
import java.util.LinkedList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
@ -521,4 +524,20 @@ public final class KeycloakModelUtils {
|
||||||
}
|
}
|
||||||
return found;
|
return found;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static Set<RoleModel> getClientScopeMappings(ClientModel client, ScopeContainerModel container) {
|
||||||
|
Set<RoleModel> mappings = container.getScopeMappings();
|
||||||
|
Set<RoleModel> result = new HashSet<>();
|
||||||
|
for (RoleModel role : mappings) {
|
||||||
|
RoleContainerModel roleContainer = role.getContainer();
|
||||||
|
if (roleContainer instanceof ClientModel) {
|
||||||
|
if (client.getId().equals(((ClientModel)roleContainer).getId())) {
|
||||||
|
result.add(role);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -419,6 +419,7 @@ public class ModelToRepresentation {
|
||||||
}
|
}
|
||||||
rep.setProtocolMappers(mappings);
|
rep.setProtocolMappers(mappings);
|
||||||
}
|
}
|
||||||
|
rep.setFullScopeAllowed(clientModel.isFullScopeAllowed());
|
||||||
|
|
||||||
return rep;
|
return rep;
|
||||||
}
|
}
|
||||||
|
@ -476,6 +477,9 @@ public class ModelToRepresentation {
|
||||||
}
|
}
|
||||||
rep.setProtocolMappers(mappings);
|
rep.setProtocolMappers(mappings);
|
||||||
}
|
}
|
||||||
|
rep.setUseTemplateMappers(clientModel.useTemplateMappers());
|
||||||
|
rep.setUseTemplateConfig(clientModel.useTemplateConfig());
|
||||||
|
rep.setUseTemplateScope(clientModel.useTemplateScope());
|
||||||
|
|
||||||
return rep;
|
return rep;
|
||||||
}
|
}
|
||||||
|
|
|
@ -802,11 +802,6 @@ public class RepresentationToModel {
|
||||||
if (resourceRep.isPublicClient() != null) client.setPublicClient(resourceRep.isPublicClient());
|
if (resourceRep.isPublicClient() != null) client.setPublicClient(resourceRep.isPublicClient());
|
||||||
if (resourceRep.isFrontchannelLogout() != null) client.setFrontchannelLogout(resourceRep.isFrontchannelLogout());
|
if (resourceRep.isFrontchannelLogout() != null) client.setFrontchannelLogout(resourceRep.isFrontchannelLogout());
|
||||||
if (resourceRep.getProtocol() != null) client.setProtocol(resourceRep.getProtocol());
|
if (resourceRep.getProtocol() != null) client.setProtocol(resourceRep.getProtocol());
|
||||||
if (resourceRep.isFullScopeAllowed() != null) {
|
|
||||||
client.setFullScopeAllowed(resourceRep.isFullScopeAllowed());
|
|
||||||
} else {
|
|
||||||
client.setFullScopeAllowed(!client.isConsentRequired());
|
|
||||||
}
|
|
||||||
if (resourceRep.getNodeReRegistrationTimeout() != null) {
|
if (resourceRep.getNodeReRegistrationTimeout() != null) {
|
||||||
client.setNodeReRegistrationTimeout(resourceRep.getNodeReRegistrationTimeout());
|
client.setNodeReRegistrationTimeout(resourceRep.getNodeReRegistrationTimeout());
|
||||||
} else {
|
} else {
|
||||||
|
@ -893,6 +888,26 @@ public class RepresentationToModel {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (resourceRep.isFullScopeAllowed() != null) {
|
||||||
|
client.setFullScopeAllowed(resourceRep.isFullScopeAllowed());
|
||||||
|
} else {
|
||||||
|
if (client.getClientTemplate() != null) {
|
||||||
|
client.setFullScopeAllowed(!client.isConsentRequired() && client.getClientTemplate().isFullScopeAllowed());
|
||||||
|
|
||||||
|
} else {
|
||||||
|
client.setFullScopeAllowed(!client.isConsentRequired());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (resourceRep.isUseTemplateConfig() != null) client.setUseTemplateConfig(resourceRep.isUseTemplateConfig());
|
||||||
|
else client.setUseTemplateConfig(resourceRep.getClientTemplate() != null);
|
||||||
|
|
||||||
|
if (resourceRep.isUseTemplateScope() != null) client.setUseTemplateScope(resourceRep.isUseTemplateScope());
|
||||||
|
else client.setUseTemplateScope(resourceRep.getClientTemplate() != null);
|
||||||
|
|
||||||
|
if (resourceRep.isUseTemplateMappers() != null) client.setUseTemplateMappers(resourceRep.isUseTemplateMappers());
|
||||||
|
else client.setUseTemplateMappers(resourceRep.getClientTemplate() != null);
|
||||||
|
|
||||||
|
|
||||||
return client;
|
return client;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -949,14 +964,23 @@ public class RepresentationToModel {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (rep.isUseTemplateConfig() != null) resource.setUseTemplateConfig(rep.isUseTemplateConfig());
|
||||||
|
if (rep.isUseTemplateScope() != null) resource.setUseTemplateScope(rep.isUseTemplateScope());
|
||||||
|
if (rep.isUseTemplateMappers() != null) resource.setUseTemplateMappers(rep.isUseTemplateMappers());
|
||||||
|
|
||||||
|
|
||||||
if (rep.getClientTemplate() != null) {
|
if (rep.getClientTemplate() != null) {
|
||||||
if (rep.getClientTemplate().equals(ClientTemplateRepresentation.NONE)) {
|
if (rep.getClientTemplate().equals(ClientTemplateRepresentation.NONE)) {
|
||||||
resource.setClientTemplate(null);
|
resource.setClientTemplate(null);
|
||||||
} else {
|
} else {
|
||||||
RealmModel realm = resource.getRealm();
|
RealmModel realm = resource.getRealm();
|
||||||
for (ClientTemplateModel template : realm.getClientTemplates()) {
|
for (ClientTemplateModel template : realm.getClientTemplates()) {
|
||||||
|
|
||||||
if (template.getName().equals(rep.getClientTemplate())) {
|
if (template.getName().equals(rep.getClientTemplate())) {
|
||||||
resource.setClientTemplate(template);
|
resource.setClientTemplate(template);
|
||||||
|
if (rep.isUseTemplateConfig() == null) resource.setUseTemplateConfig(true);
|
||||||
|
if (rep.isUseTemplateScope() == null) resource.setUseTemplateScope(true);
|
||||||
|
if (rep.isUseTemplateMappers() == null) resource.setUseTemplateMappers(true);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -984,7 +1008,7 @@ public class RepresentationToModel {
|
||||||
if (resourceRep.getName() != null) client.setName(resourceRep.getName());
|
if (resourceRep.getName() != null) client.setName(resourceRep.getName());
|
||||||
if(resourceRep.getDescription() != null) client.setDescription(resourceRep.getDescription());
|
if(resourceRep.getDescription() != null) client.setDescription(resourceRep.getDescription());
|
||||||
if (resourceRep.getProtocol() != null) client.setProtocol(resourceRep.getProtocol());
|
if (resourceRep.getProtocol() != null) client.setProtocol(resourceRep.getProtocol());
|
||||||
|
if (resourceRep.isFullScopeAllowed() != null) client.setFullScopeAllowed(resourceRep.isFullScopeAllowed());
|
||||||
if (resourceRep.getProtocolMappers() != null) {
|
if (resourceRep.getProtocolMappers() != null) {
|
||||||
// first, remove all default/built in mappers
|
// first, remove all default/built in mappers
|
||||||
Set<ProtocolMapperModel> mappers = client.getProtocolMappers();
|
Set<ProtocolMapperModel> mappers = client.getProtocolMappers();
|
||||||
|
@ -1001,6 +1025,9 @@ public class RepresentationToModel {
|
||||||
public static void updateClientTemplate(ClientTemplateRepresentation rep, ClientTemplateModel resource) {
|
public static void updateClientTemplate(ClientTemplateRepresentation rep, ClientTemplateModel resource) {
|
||||||
if (rep.getName() != null) resource.setName(rep.getName());
|
if (rep.getName() != null) resource.setName(rep.getName());
|
||||||
if (rep.getDescription() != null) resource.setDescription(rep.getDescription());
|
if (rep.getDescription() != null) resource.setDescription(rep.getDescription());
|
||||||
|
if (rep.isFullScopeAllowed() != null) {
|
||||||
|
resource.setFullScopeAllowed(rep.isFullScopeAllowed());
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
if (rep.getProtocol() != null) resource.setProtocol(rep.getProtocol());
|
if (rep.getProtocol() != null) resource.setProtocol(rep.getProtocol());
|
||||||
|
|
|
@ -69,6 +69,47 @@ public class ClientAdapter implements ClientModel {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean useTemplateScope() {
|
||||||
|
if (updated != null) return updated.useTemplateScope();
|
||||||
|
return cached.isUseTemplateScope();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setUseTemplateScope(boolean value) {
|
||||||
|
getDelegateForUpdate();
|
||||||
|
updated.setUseTemplateScope(value);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean useTemplateConfig() {
|
||||||
|
if (updated != null) return updated.useTemplateConfig();
|
||||||
|
return cached.isUseTemplateConfig();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setUseTemplateConfig(boolean value) {
|
||||||
|
getDelegateForUpdate();
|
||||||
|
updated.setUseTemplateConfig(value);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean useTemplateMappers() {
|
||||||
|
if (updated != null) return updated.useTemplateMappers();
|
||||||
|
return cached.isUseTemplateMappers();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setUseTemplateMappers(boolean value) {
|
||||||
|
getDelegateForUpdate();
|
||||||
|
updated.setUseTemplateMappers(value);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
public void addWebOrigin(String webOrigin) {
|
public void addWebOrigin(String webOrigin) {
|
||||||
getDelegateForUpdate();
|
getDelegateForUpdate();
|
||||||
updated.addWebOrigin(webOrigin);
|
updated.addWebOrigin(webOrigin);
|
||||||
|
@ -412,25 +453,6 @@ public class ClientAdapter implements ClientModel {
|
||||||
updated.updateDefaultRoles(defaultRoles);
|
updated.updateDefaultRoles(defaultRoles);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public Set<RoleModel> getClientScopeMappings(ClientModel client) {
|
|
||||||
Set<RoleModel> roleMappings = client.getScopeMappings();
|
|
||||||
|
|
||||||
Set<RoleModel> appRoles = new HashSet<RoleModel>();
|
|
||||||
for (RoleModel role : roleMappings) {
|
|
||||||
RoleContainerModel container = role.getContainer();
|
|
||||||
if (container instanceof RealmModel) {
|
|
||||||
} else {
|
|
||||||
ClientModel app = (ClientModel)container;
|
|
||||||
if (app.getId().equals(getId())) {
|
|
||||||
appRoles.add(role);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return appRoles;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean isBearerOnly() {
|
public boolean isBearerOnly() {
|
||||||
if (updated != null) return updated.isBearerOnly();
|
if (updated != null) return updated.isBearerOnly();
|
||||||
|
|
|
@ -132,6 +132,70 @@ public class ClientTemplateAdapter implements ClientTemplateModel {
|
||||||
updated.setProtocol(protocol);
|
updated.setProtocol(protocol);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isFullScopeAllowed() {
|
||||||
|
if (updated != null) return updated.isFullScopeAllowed();
|
||||||
|
return cached.isFullScopeAllowed();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setFullScopeAllowed(boolean value) {
|
||||||
|
getDelegateForUpdate();
|
||||||
|
updated.setFullScopeAllowed(value);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public Set<RoleModel> getScopeMappings() {
|
||||||
|
if (updated != null) return updated.getScopeMappings();
|
||||||
|
Set<RoleModel> roles = new HashSet<RoleModel>();
|
||||||
|
for (String id : cached.getScope()) {
|
||||||
|
roles.add(cacheSession.getRoleById(id, getRealm()));
|
||||||
|
|
||||||
|
}
|
||||||
|
return roles;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void addScopeMapping(RoleModel role) {
|
||||||
|
getDelegateForUpdate();
|
||||||
|
updated.addScopeMapping(role);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void deleteScopeMapping(RoleModel role) {
|
||||||
|
getDelegateForUpdate();
|
||||||
|
updated.deleteScopeMapping(role);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Set<RoleModel> getRealmScopeMappings() {
|
||||||
|
Set<RoleModel> roleMappings = getScopeMappings();
|
||||||
|
|
||||||
|
Set<RoleModel> appRoles = new HashSet<RoleModel>();
|
||||||
|
for (RoleModel role : roleMappings) {
|
||||||
|
RoleContainerModel container = role.getContainer();
|
||||||
|
if (container instanceof RealmModel) {
|
||||||
|
if (((RealmModel) container).getId().equals(cachedRealm.getId())) {
|
||||||
|
appRoles.add(role);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return appRoles;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean hasScope(RoleModel role) {
|
||||||
|
if (updated != null) return updated.hasScope(role);
|
||||||
|
if (cached.isFullScopeAllowed() || cached.getScope().contains(role.getId())) return true;
|
||||||
|
|
||||||
|
Set<RoleModel> roles = getScopeMappings();
|
||||||
|
|
||||||
|
for (RoleModel mapping : roles) {
|
||||||
|
if (mapping.hasRole(role)) return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean equals(Object o) {
|
public boolean equals(Object o) {
|
||||||
if (this == o) return true;
|
if (this == o) return true;
|
||||||
|
|
|
@ -56,6 +56,9 @@ public class CachedClient implements Serializable {
|
||||||
private int nodeReRegistrationTimeout;
|
private int nodeReRegistrationTimeout;
|
||||||
private Map<String, Integer> registeredNodes;
|
private Map<String, Integer> registeredNodes;
|
||||||
private String clientTemplate;
|
private String clientTemplate;
|
||||||
|
private boolean useTemplateScope;
|
||||||
|
private boolean useTemplateConfig;
|
||||||
|
private boolean useTemplateMappers;
|
||||||
|
|
||||||
public CachedClient(RealmCache cache, RealmProvider delegate, RealmModel realm, ClientModel model) {
|
public CachedClient(RealmCache cache, RealmProvider delegate, RealmModel realm, ClientModel model) {
|
||||||
id = model.getId();
|
id = model.getId();
|
||||||
|
@ -102,6 +105,9 @@ public class CachedClient implements Serializable {
|
||||||
if (model.getClientTemplate() != null) {
|
if (model.getClientTemplate() != null) {
|
||||||
clientTemplate = model.getClientTemplate().getId();
|
clientTemplate = model.getClientTemplate().getId();
|
||||||
}
|
}
|
||||||
|
useTemplateConfig = model.useTemplateConfig();
|
||||||
|
useTemplateMappers = model.useTemplateMappers();
|
||||||
|
useTemplateScope = model.useTemplateScope();
|
||||||
}
|
}
|
||||||
public String getId() {
|
public String getId() {
|
||||||
return id;
|
return id;
|
||||||
|
@ -238,4 +244,16 @@ public class CachedClient implements Serializable {
|
||||||
public String getClientTemplate() {
|
public String getClientTemplate() {
|
||||||
return clientTemplate;
|
return clientTemplate;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public boolean isUseTemplateScope() {
|
||||||
|
return useTemplateScope;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isUseTemplateConfig() {
|
||||||
|
return useTemplateConfig;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isUseTemplateMappers() {
|
||||||
|
return useTemplateMappers;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -28,6 +28,8 @@ public class CachedClientTemplate implements Serializable {
|
||||||
private String description;
|
private String description;
|
||||||
private String realm;
|
private String realm;
|
||||||
private String protocol;
|
private String protocol;
|
||||||
|
private boolean fullScopeAllowed;
|
||||||
|
private Set<String> scope = new HashSet<String>();
|
||||||
private Set<ProtocolMapperModel> protocolMappers = new HashSet<ProtocolMapperModel>();
|
private Set<ProtocolMapperModel> protocolMappers = new HashSet<ProtocolMapperModel>();
|
||||||
|
|
||||||
public CachedClientTemplate(RealmCache cache, RealmProvider delegate, RealmModel realm, ClientTemplateModel model) {
|
public CachedClientTemplate(RealmCache cache, RealmProvider delegate, RealmModel realm, ClientTemplateModel model) {
|
||||||
|
@ -36,9 +38,13 @@ public class CachedClientTemplate implements Serializable {
|
||||||
description = model.getDescription();
|
description = model.getDescription();
|
||||||
this.realm = realm.getId();
|
this.realm = realm.getId();
|
||||||
protocol = model.getProtocol();
|
protocol = model.getProtocol();
|
||||||
|
fullScopeAllowed = model.isFullScopeAllowed();
|
||||||
for (ProtocolMapperModel mapper : model.getProtocolMappers()) {
|
for (ProtocolMapperModel mapper : model.getProtocolMappers()) {
|
||||||
this.protocolMappers.add(mapper);
|
this.protocolMappers.add(mapper);
|
||||||
}
|
}
|
||||||
|
for (RoleModel role : model.getScopeMappings()) {
|
||||||
|
scope.add(role.getId());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
public String getId() {
|
public String getId() {
|
||||||
return id;
|
return id;
|
||||||
|
@ -63,4 +69,12 @@ public class CachedClientTemplate implements Serializable {
|
||||||
public String getProtocol() {
|
public String getProtocol() {
|
||||||
return protocol;
|
return protocol;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public boolean isFullScopeAllowed() {
|
||||||
|
return fullScopeAllowed;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Set<String> getScope() {
|
||||||
|
return scope;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -238,7 +238,8 @@ public class ClientAdapter implements ClientModel {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void addScopeMapping(RoleModel role) {
|
public void addScopeMapping(RoleModel role) {
|
||||||
if (hasScope(role)) return;
|
Set<RoleModel> roles = getScopeMappings();
|
||||||
|
if (roles.contains(role)) return;
|
||||||
ScopeMappingEntity entity = new ScopeMappingEntity();
|
ScopeMappingEntity entity = new ScopeMappingEntity();
|
||||||
entity.setClient(getEntity());
|
entity.setClient(getEntity());
|
||||||
RoleEntity roleEntity = RoleAdapter.toRoleEntity(role, em);
|
RoleEntity roleEntity = RoleAdapter.toRoleEntity(role, em);
|
||||||
|
@ -319,6 +320,39 @@ public class ClientAdapter implements ClientModel {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean useTemplateScope() {
|
||||||
|
return entity.isUseTemplateScope();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setUseTemplateScope(boolean flag) {
|
||||||
|
entity.setUseTemplateScope(flag);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean useTemplateMappers() {
|
||||||
|
return entity.isUseTemplateMappers();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setUseTemplateMappers(boolean flag) {
|
||||||
|
entity.setUseTemplateMappers(flag);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean useTemplateConfig() {
|
||||||
|
return entity.isUseTemplateConfig();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setUseTemplateConfig(boolean flag) {
|
||||||
|
entity.setUseTemplateConfig(flag);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
public static boolean contains(String str, String[] array) {
|
public static boolean contains(String str, String[] array) {
|
||||||
for (String s : array) {
|
for (String s : array) {
|
||||||
if (str.equals(s)) return true;
|
if (str.equals(s)) return true;
|
||||||
|
@ -604,6 +638,7 @@ public class ClientAdapter implements ClientModel {
|
||||||
String compositeRoleTable = JpaUtils.getTableNameForNativeQuery("COMPOSITE_ROLE", em);
|
String compositeRoleTable = JpaUtils.getTableNameForNativeQuery("COMPOSITE_ROLE", em);
|
||||||
em.createNativeQuery("delete from " + compositeRoleTable + " where CHILD_ROLE = :role").setParameter("role", role).executeUpdate();
|
em.createNativeQuery("delete from " + compositeRoleTable + " where CHILD_ROLE = :role").setParameter("role", role).executeUpdate();
|
||||||
em.createNamedQuery("deleteScopeMappingByRole").setParameter("role", role).executeUpdate();
|
em.createNamedQuery("deleteScopeMappingByRole").setParameter("role", role).executeUpdate();
|
||||||
|
em.createNamedQuery("deleteTemplateScopeMappingByRole").setParameter("role", role).executeUpdate();
|
||||||
role.setClient(null);
|
role.setClient(null);
|
||||||
em.flush();
|
em.flush();
|
||||||
em.remove(role);
|
em.remove(role);
|
||||||
|
@ -641,28 +676,6 @@ public class ClientAdapter implements ClientModel {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public Set<RoleModel> getClientScopeMappings(ClientModel client) {
|
|
||||||
Set<RoleModel> roleMappings = client.getScopeMappings();
|
|
||||||
|
|
||||||
Set<RoleModel> appRoles = new HashSet<RoleModel>();
|
|
||||||
for (RoleModel role : roleMappings) {
|
|
||||||
RoleContainerModel container = role.getContainer();
|
|
||||||
if (container instanceof RealmModel) {
|
|
||||||
} else {
|
|
||||||
ClientModel app = (ClientModel)container;
|
|
||||||
if (app.getId().equals(getId())) {
|
|
||||||
appRoles.add(role);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return appRoles;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public List<String> getDefaultRoles() {
|
public List<String> getDefaultRoles() {
|
||||||
Collection<RoleEntity> entities = entity.getDefaultRoles();
|
Collection<RoleEntity> entities = entity.getDefaultRoles();
|
||||||
|
|
|
@ -14,6 +14,7 @@ import org.keycloak.models.jpa.entities.ClientTemplateEntity;
|
||||||
import org.keycloak.models.jpa.entities.ProtocolMapperEntity;
|
import org.keycloak.models.jpa.entities.ProtocolMapperEntity;
|
||||||
import org.keycloak.models.jpa.entities.RoleEntity;
|
import org.keycloak.models.jpa.entities.RoleEntity;
|
||||||
import org.keycloak.models.jpa.entities.ScopeMappingEntity;
|
import org.keycloak.models.jpa.entities.ScopeMappingEntity;
|
||||||
|
import org.keycloak.models.jpa.entities.TemplateScopeMappingEntity;
|
||||||
import org.keycloak.models.utils.KeycloakModelUtils;
|
import org.keycloak.models.utils.KeycloakModelUtils;
|
||||||
|
|
||||||
import javax.persistence.EntityManager;
|
import javax.persistence.EntityManager;
|
||||||
|
@ -203,6 +204,88 @@ public class ClientTemplateAdapter implements ClientTemplateModel {
|
||||||
return mapping;
|
return mapping;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isFullScopeAllowed() {
|
||||||
|
return entity.isFullScopeAllowed();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setFullScopeAllowed(boolean value) {
|
||||||
|
entity.setFullScopeAllowed(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Set<RoleModel> getRealmScopeMappings() {
|
||||||
|
Set<RoleModel> roleMappings = getScopeMappings();
|
||||||
|
|
||||||
|
Set<RoleModel> appRoles = new HashSet<>();
|
||||||
|
for (RoleModel role : roleMappings) {
|
||||||
|
RoleContainerModel container = role.getContainer();
|
||||||
|
if (container instanceof RealmModel) {
|
||||||
|
if (((RealmModel) container).getId().equals(realm.getId())) {
|
||||||
|
appRoles.add(role);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return appRoles;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Set<RoleModel> getScopeMappings() {
|
||||||
|
TypedQuery<String> query = em.createNamedQuery("clientTemplateScopeMappingIds", String.class);
|
||||||
|
query.setParameter("template", getEntity());
|
||||||
|
List<String> ids = query.getResultList();
|
||||||
|
Set<RoleModel> roles = new HashSet<RoleModel>();
|
||||||
|
for (String roleId : ids) {
|
||||||
|
RoleModel role = realm.getRoleById(roleId);
|
||||||
|
if (role == null) continue;
|
||||||
|
roles.add(role);
|
||||||
|
}
|
||||||
|
return roles;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void addScopeMapping(RoleModel role) {
|
||||||
|
if (hasScope(role)) return;
|
||||||
|
TemplateScopeMappingEntity entity = new TemplateScopeMappingEntity();
|
||||||
|
entity.setTemplate(getEntity());
|
||||||
|
RoleEntity roleEntity = RoleAdapter.toRoleEntity(role, em);
|
||||||
|
entity.setRole(roleEntity);
|
||||||
|
em.persist(entity);
|
||||||
|
em.flush();
|
||||||
|
em.detach(entity);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void deleteScopeMapping(RoleModel role) {
|
||||||
|
TypedQuery<TemplateScopeMappingEntity> query = getRealmScopeMappingQuery(role);
|
||||||
|
List<TemplateScopeMappingEntity> results = query.getResultList();
|
||||||
|
if (results.size() == 0) return;
|
||||||
|
for (TemplateScopeMappingEntity entity : results) {
|
||||||
|
em.remove(entity);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected TypedQuery<TemplateScopeMappingEntity> getRealmScopeMappingQuery(RoleModel role) {
|
||||||
|
TypedQuery<TemplateScopeMappingEntity> query = em.createNamedQuery("templateHasScope", TemplateScopeMappingEntity.class);
|
||||||
|
query.setParameter("template", getEntity());
|
||||||
|
RoleEntity roleEntity = RoleAdapter.toRoleEntity(role, em);
|
||||||
|
query.setParameter("role", roleEntity);
|
||||||
|
return query;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean hasScope(RoleModel role) {
|
||||||
|
if (isFullScopeAllowed()) return true;
|
||||||
|
Set<RoleModel> roles = getScopeMappings();
|
||||||
|
if (roles.contains(role)) return true;
|
||||||
|
|
||||||
|
for (RoleModel mapping : roles) {
|
||||||
|
if (mapping.hasRole(role)) return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean equals(Object o) {
|
public boolean equals(Object o) {
|
||||||
|
@ -219,4 +302,6 @@ public class ClientTemplateAdapter implements ClientTemplateModel {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -110,6 +110,9 @@ public class JpaRealmProvider implements RealmProvider {
|
||||||
for (ClientEntity a : new LinkedList<>(realm.getClients())) {
|
for (ClientEntity a : new LinkedList<>(realm.getClients())) {
|
||||||
adapter.removeClient(a.getId());
|
adapter.removeClient(a.getId());
|
||||||
}
|
}
|
||||||
|
for (ClientTemplateEntity a : new LinkedList<>(realm.getClientTemplates())) {
|
||||||
|
adapter.removeClientTemplate(a.getId());
|
||||||
|
}
|
||||||
|
|
||||||
em.remove(realm);
|
em.remove(realm);
|
||||||
|
|
||||||
|
|
|
@ -1051,6 +1051,7 @@ public class RealmAdapter implements RealmModel {
|
||||||
String compositeRoleTable = JpaUtils.getTableNameForNativeQuery("COMPOSITE_ROLE", em);
|
String compositeRoleTable = JpaUtils.getTableNameForNativeQuery("COMPOSITE_ROLE", em);
|
||||||
em.createNativeQuery("delete from " + compositeRoleTable + " where CHILD_ROLE = :role").setParameter("role", roleEntity).executeUpdate();
|
em.createNativeQuery("delete from " + compositeRoleTable + " where CHILD_ROLE = :role").setParameter("role", roleEntity).executeUpdate();
|
||||||
em.createNamedQuery("deleteScopeMappingByRole").setParameter("role", roleEntity).executeUpdate();
|
em.createNamedQuery("deleteScopeMappingByRole").setParameter("role", roleEntity).executeUpdate();
|
||||||
|
em.createNamedQuery("deleteTemplateScopeMappingByRole").setParameter("role", roleEntity).executeUpdate();
|
||||||
em.createNamedQuery("deleteGroupRoleMappingsByRole").setParameter("roleId", roleEntity.getId()).executeUpdate();
|
em.createNamedQuery("deleteGroupRoleMappingsByRole").setParameter("roleId", roleEntity.getId()).executeUpdate();
|
||||||
|
|
||||||
em.remove(roleEntity);
|
em.remove(roleEntity);
|
||||||
|
@ -2146,9 +2147,12 @@ public class RealmAdapter implements RealmModel {
|
||||||
if (client == null) {
|
if (client == null) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
em.createNamedQuery("deleteTemplateScopeMappingByClient").setParameter("template", clientEntity).executeUpdate();
|
||||||
|
em.flush();
|
||||||
em.remove(clientEntity);
|
em.remove(clientEntity);
|
||||||
em.flush();
|
em.flush();
|
||||||
|
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -61,6 +61,15 @@ public class ClientEntity {
|
||||||
@JoinColumn(name = "CLIENT_TEMPLATE_ID")
|
@JoinColumn(name = "CLIENT_TEMPLATE_ID")
|
||||||
protected ClientTemplateEntity clientTemplate;
|
protected ClientTemplateEntity clientTemplate;
|
||||||
|
|
||||||
|
@Column(name="USE_TEMPLATE_CONFIG")
|
||||||
|
private boolean useTemplateConfig;
|
||||||
|
|
||||||
|
@Column(name="USE_TEMPLATE_SCOPE")
|
||||||
|
private boolean useTemplateScope;
|
||||||
|
|
||||||
|
@Column(name="USE_TEMPLATE_MAPPERS")
|
||||||
|
private boolean useTemplateMappers;
|
||||||
|
|
||||||
@ManyToOne(fetch = FetchType.LAZY)
|
@ManyToOne(fetch = FetchType.LAZY)
|
||||||
@JoinColumn(name = "REALM_ID")
|
@JoinColumn(name = "REALM_ID")
|
||||||
protected RealmEntity realm;
|
protected RealmEntity realm;
|
||||||
|
@ -404,4 +413,28 @@ public class ClientEntity {
|
||||||
public void setClientTemplate(ClientTemplateEntity clientTemplate) {
|
public void setClientTemplate(ClientTemplateEntity clientTemplate) {
|
||||||
this.clientTemplate = clientTemplate;
|
this.clientTemplate = clientTemplate;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public boolean isUseTemplateConfig() {
|
||||||
|
return useTemplateConfig;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setUseTemplateConfig(boolean useTemplateConfig) {
|
||||||
|
this.useTemplateConfig = useTemplateConfig;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isUseTemplateScope() {
|
||||||
|
return useTemplateScope;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setUseTemplateScope(boolean useTemplateScope) {
|
||||||
|
this.useTemplateScope = useTemplateScope;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isUseTemplateMappers() {
|
||||||
|
return useTemplateMappers;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setUseTemplateMappers(boolean useTemplateMappers) {
|
||||||
|
this.useTemplateMappers = useTemplateMappers;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -45,6 +45,8 @@ public class ClientTemplateEntity {
|
||||||
@Column(name="PROTOCOL")
|
@Column(name="PROTOCOL")
|
||||||
private String protocol;
|
private String protocol;
|
||||||
|
|
||||||
|
@Column(name="FULL_SCOPE_ALLOWED")
|
||||||
|
private boolean fullScopeAllowed;
|
||||||
|
|
||||||
public RealmEntity getRealm() {
|
public RealmEntity getRealm() {
|
||||||
return realm;
|
return realm;
|
||||||
|
@ -93,4 +95,12 @@ public class ClientTemplateEntity {
|
||||||
public void setProtocol(String protocol) {
|
public void setProtocol(String protocol) {
|
||||||
this.protocol = protocol;
|
this.protocol = protocol;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public boolean isFullScopeAllowed() {
|
||||||
|
return fullScopeAllowed;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setFullScopeAllowed(boolean fullScopeAllowed) {
|
||||||
|
this.fullScopeAllowed = fullScopeAllowed;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,99 @@
|
||||||
|
package org.keycloak.models.jpa.entities;
|
||||||
|
|
||||||
|
import javax.persistence.Entity;
|
||||||
|
import javax.persistence.FetchType;
|
||||||
|
import javax.persistence.Id;
|
||||||
|
import javax.persistence.IdClass;
|
||||||
|
import javax.persistence.JoinColumn;
|
||||||
|
import javax.persistence.ManyToOne;
|
||||||
|
import javax.persistence.NamedQueries;
|
||||||
|
import javax.persistence.NamedQuery;
|
||||||
|
import javax.persistence.Table;
|
||||||
|
import java.io.Serializable;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
|
||||||
|
* @version $Revision: 1 $
|
||||||
|
*/
|
||||||
|
@NamedQueries({
|
||||||
|
@NamedQuery(name="templateHasScope", query="select m from TemplateScopeMappingEntity m where m.template = :template and m.role = :role"),
|
||||||
|
@NamedQuery(name="clientTemplateScopeMappings", query="select m from TemplateScopeMappingEntity m where m.template = :template"),
|
||||||
|
@NamedQuery(name="clientTemplateScopeMappingIds", query="select m.role.id from TemplateScopeMappingEntity m where m.template = :template"),
|
||||||
|
@NamedQuery(name="deleteTemplateScopeMappingByRole", query="delete from TemplateScopeMappingEntity where role = :role"),
|
||||||
|
@NamedQuery(name="deleteTemplateScopeMappingByClient", query="delete from TemplateScopeMappingEntity where template = :template")
|
||||||
|
})
|
||||||
|
@Table(name="TEMPLATE_SCOPE_MAPPING")
|
||||||
|
@Entity
|
||||||
|
@IdClass(TemplateScopeMappingEntity.Key.class)
|
||||||
|
public class TemplateScopeMappingEntity {
|
||||||
|
|
||||||
|
@Id
|
||||||
|
@ManyToOne(fetch= FetchType.LAZY)
|
||||||
|
@JoinColumn(name = "TEMPLATE_ID")
|
||||||
|
protected ClientTemplateEntity template;
|
||||||
|
|
||||||
|
@Id
|
||||||
|
@ManyToOne(fetch= FetchType.LAZY)
|
||||||
|
@JoinColumn(name="ROLE_ID")
|
||||||
|
protected RoleEntity role;
|
||||||
|
|
||||||
|
public ClientTemplateEntity getTemplate() {
|
||||||
|
return template;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setTemplate(ClientTemplateEntity template) {
|
||||||
|
this.template = template;
|
||||||
|
}
|
||||||
|
|
||||||
|
public RoleEntity getRole() {
|
||||||
|
return role;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setRole(RoleEntity role) {
|
||||||
|
this.role = role;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class Key implements Serializable {
|
||||||
|
|
||||||
|
protected ClientTemplateEntity template;
|
||||||
|
|
||||||
|
protected RoleEntity role;
|
||||||
|
|
||||||
|
public Key() {
|
||||||
|
}
|
||||||
|
|
||||||
|
public Key(ClientTemplateEntity template, RoleEntity role) {
|
||||||
|
this.template = template;
|
||||||
|
this.role = role;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ClientTemplateEntity getTemplate() {
|
||||||
|
return template;
|
||||||
|
}
|
||||||
|
|
||||||
|
public RoleEntity getRole() {
|
||||||
|
return role;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean equals(Object o) {
|
||||||
|
if (this == o) return true;
|
||||||
|
if (o == null || getClass() != o.getClass()) return false;
|
||||||
|
|
||||||
|
Key key = (Key) o;
|
||||||
|
|
||||||
|
if (template != null ? !template.getId().equals(key.template != null ? key.template.getId() : null) : key.template != null) return false;
|
||||||
|
if (role != null ? !role.getId().equals(key.role != null ? key.role.getId() : null) : key.role != null) return false;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int hashCode() {
|
||||||
|
int result = template != null ? template.getId().hashCode() : 0;
|
||||||
|
result = 31 * result + (role != null ? role.getId().hashCode() : 0);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -10,6 +10,7 @@ import org.keycloak.models.ModelDuplicateException;
|
||||||
import org.keycloak.models.ProtocolMapperModel;
|
import org.keycloak.models.ProtocolMapperModel;
|
||||||
import org.keycloak.models.RealmModel;
|
import org.keycloak.models.RealmModel;
|
||||||
import org.keycloak.models.RoleModel;
|
import org.keycloak.models.RoleModel;
|
||||||
|
import org.keycloak.models.ScopeContainerModel;
|
||||||
import org.keycloak.models.entities.ProtocolMapperEntity;
|
import org.keycloak.models.entities.ProtocolMapperEntity;
|
||||||
import org.keycloak.models.mongo.keycloak.entities.MongoClientEntity;
|
import org.keycloak.models.mongo.keycloak.entities.MongoClientEntity;
|
||||||
import org.keycloak.models.mongo.keycloak.entities.MongoRoleEntity;
|
import org.keycloak.models.mongo.keycloak.entities.MongoRoleEntity;
|
||||||
|
@ -620,19 +621,6 @@ public class ClientAdapter extends AbstractMongoAdapter<MongoClientEntity> imple
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public Set<RoleModel> getClientScopeMappings(ClientModel client) {
|
|
||||||
Set<RoleModel> result = new HashSet<RoleModel>();
|
|
||||||
List<MongoRoleEntity> roles = MongoModelUtils.getAllScopesOfClient(client, invocationContext);
|
|
||||||
|
|
||||||
for (MongoRoleEntity role : roles) {
|
|
||||||
if (getId().equals(role.getClientId())) {
|
|
||||||
result.add(new RoleAdapter(session, getRealm(), role, this, invocationContext));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public List<String> getDefaultRoles() {
|
public List<String> getDefaultRoles() {
|
||||||
return getMongoEntity().getDefaultRoles();
|
return getMongoEntity().getDefaultRoles();
|
||||||
|
@ -726,4 +714,41 @@ public class ClientAdapter extends AbstractMongoAdapter<MongoClientEntity> imple
|
||||||
updateMongoEntity();
|
updateMongoEntity();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean useTemplateScope() {
|
||||||
|
return getMongoEntity().isUseTemplateScope();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setUseTemplateScope(boolean flag) {
|
||||||
|
getMongoEntity().setUseTemplateScope(flag);
|
||||||
|
updateMongoEntity();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean useTemplateMappers() {
|
||||||
|
return getMongoEntity().isUseTemplateMappers();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setUseTemplateMappers(boolean flag) {
|
||||||
|
getMongoEntity().setUseTemplateMappers(flag);
|
||||||
|
updateMongoEntity();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean useTemplateConfig() {
|
||||||
|
return getMongoEntity().isUseTemplateConfig();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setUseTemplateConfig(boolean flag) {
|
||||||
|
getMongoEntity().setUseTemplateConfig(flag);
|
||||||
|
updateMongoEntity();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -209,7 +209,70 @@ public class ClientTemplateAdapter extends AbstractMongoAdapter<MongoClientTempl
|
||||||
return mapping;
|
return mapping;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isFullScopeAllowed() {
|
||||||
|
return getMongoEntity().isFullScopeAllowed();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setFullScopeAllowed(boolean value) {
|
||||||
|
getMongoEntity().setFullScopeAllowed(value);
|
||||||
|
updateMongoEntity();
|
||||||
|
|
||||||
|
}
|
||||||
|
@Override
|
||||||
|
public Set<RoleModel> getScopeMappings() {
|
||||||
|
Set<RoleModel> result = new HashSet<RoleModel>();
|
||||||
|
List<MongoRoleEntity> roles = MongoModelUtils.getAllScopesOfTemplate(this, invocationContext);
|
||||||
|
|
||||||
|
for (MongoRoleEntity role : roles) {
|
||||||
|
if (realm.getId().equals(role.getRealmId())) {
|
||||||
|
result.add(new RoleAdapter(session, realm, role, realm, invocationContext));
|
||||||
|
} else {
|
||||||
|
// Likely applicationRole, but we don't have this application yet
|
||||||
|
result.add(new RoleAdapter(session, realm, role, invocationContext));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Set<RoleModel> getRealmScopeMappings() {
|
||||||
|
Set<RoleModel> allScopes = getScopeMappings();
|
||||||
|
|
||||||
|
// Filter to retrieve just realm roles TODO: Maybe improve to avoid filter programmatically... Maybe have separate fields for realmRoles and appRoles on user?
|
||||||
|
Set<RoleModel> realmRoles = new HashSet<RoleModel>();
|
||||||
|
for (RoleModel role : allScopes) {
|
||||||
|
MongoRoleEntity roleEntity = ((RoleAdapter) role).getRole();
|
||||||
|
|
||||||
|
if (realm.getId().equals(roleEntity.getRealmId())) {
|
||||||
|
realmRoles.add(role);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return realmRoles;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void addScopeMapping(RoleModel role) {
|
||||||
|
getMongoStore().pushItemToList(this.getMongoEntity(), "scopeIds", role.getId(), true, invocationContext);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void deleteScopeMapping(RoleModel role) {
|
||||||
|
getMongoStore().pullItemFromList(this.getMongoEntity(), "scopeIds", role.getId(), invocationContext);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean hasScope(RoleModel role) {
|
||||||
|
if (isFullScopeAllowed()) return true;
|
||||||
|
Set<RoleModel> roles = getScopeMappings();
|
||||||
|
if (roles.contains(role)) return true;
|
||||||
|
|
||||||
|
for (RoleModel mapping : roles) {
|
||||||
|
if (mapping.hasRole(role)) return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean equals(Object o) {
|
public boolean equals(Object o) {
|
||||||
|
|
|
@ -4,12 +4,15 @@ import com.mongodb.DBObject;
|
||||||
import com.mongodb.QueryBuilder;
|
import com.mongodb.QueryBuilder;
|
||||||
import org.keycloak.connections.mongo.api.context.MongoStoreInvocationContext;
|
import org.keycloak.connections.mongo.api.context.MongoStoreInvocationContext;
|
||||||
import org.keycloak.models.ClientModel;
|
import org.keycloak.models.ClientModel;
|
||||||
|
import org.keycloak.models.ClientTemplateModel;
|
||||||
import org.keycloak.models.GroupModel;
|
import org.keycloak.models.GroupModel;
|
||||||
import org.keycloak.models.RealmModel;
|
import org.keycloak.models.RealmModel;
|
||||||
import org.keycloak.models.RoleModel;
|
import org.keycloak.models.RoleModel;
|
||||||
import org.keycloak.models.UserModel;
|
import org.keycloak.models.UserModel;
|
||||||
import org.keycloak.models.entities.ClientEntity;
|
import org.keycloak.models.entities.ClientEntity;
|
||||||
|
import org.keycloak.models.entities.ClientTemplateEntity;
|
||||||
import org.keycloak.models.mongo.keycloak.adapters.ClientAdapter;
|
import org.keycloak.models.mongo.keycloak.adapters.ClientAdapter;
|
||||||
|
import org.keycloak.models.mongo.keycloak.adapters.ClientTemplateAdapter;
|
||||||
import org.keycloak.models.mongo.keycloak.adapters.GroupAdapter;
|
import org.keycloak.models.mongo.keycloak.adapters.GroupAdapter;
|
||||||
import org.keycloak.models.mongo.keycloak.adapters.UserAdapter;
|
import org.keycloak.models.mongo.keycloak.adapters.UserAdapter;
|
||||||
import org.keycloak.models.mongo.keycloak.entities.MongoRoleEntity;
|
import org.keycloak.models.mongo.keycloak.entities.MongoRoleEntity;
|
||||||
|
@ -52,6 +55,19 @@ public class MongoModelUtils {
|
||||||
return Collections.emptyList();
|
return Collections.emptyList();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
DBObject query = new QueryBuilder()
|
||||||
|
.and("_id").in(scopeIds)
|
||||||
|
.get();
|
||||||
|
return invContext.getMongoStore().loadEntities(MongoRoleEntity.class, query, invContext);
|
||||||
|
}
|
||||||
|
public static List<MongoRoleEntity> getAllScopesOfTemplate(ClientTemplateModel template, MongoStoreInvocationContext invContext) {
|
||||||
|
ClientTemplateEntity scopedEntity = ((ClientTemplateAdapter)template).getMongoEntity();
|
||||||
|
List<String> scopeIds = scopedEntity.getScopeIds();
|
||||||
|
|
||||||
|
if (scopeIds == null || scopeIds.isEmpty()) {
|
||||||
|
return Collections.emptyList();
|
||||||
|
}
|
||||||
|
|
||||||
DBObject query = new QueryBuilder()
|
DBObject query = new QueryBuilder()
|
||||||
.and("_id").in(scopeIds)
|
.and("_id").in(scopeIds)
|
||||||
.get();
|
.get();
|
||||||
|
|
|
@ -267,7 +267,7 @@ public class TokenManager {
|
||||||
|
|
||||||
Set<String> requestedProtocolMappers = new HashSet<String>();
|
Set<String> requestedProtocolMappers = new HashSet<String>();
|
||||||
ClientTemplateModel clientTemplate = client.getClientTemplate();
|
ClientTemplateModel clientTemplate = client.getClientTemplate();
|
||||||
if (clientTemplate != null) {
|
if (clientTemplate != null && client.useTemplateMappers()) {
|
||||||
for (ProtocolMapperModel protocolMapper : clientTemplate.getProtocolMappers()) {
|
for (ProtocolMapperModel protocolMapper : clientTemplate.getProtocolMappers()) {
|
||||||
if (protocolMapper.getProtocol().equals(clientSession.getAuthMethod())) {
|
if (protocolMapper.getProtocol().equals(clientSession.getAuthMethod())) {
|
||||||
requestedProtocolMappers.add(protocolMapper.getId());
|
requestedProtocolMappers.add(protocolMapper.getId());
|
||||||
|
@ -322,14 +322,22 @@ public class TokenManager {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
ClientTemplateModel template = client.getClientTemplate();
|
||||||
|
|
||||||
if (client.isFullScopeAllowed()) {
|
boolean useTemplateScope = template != null && client.useTemplateScope();
|
||||||
|
|
||||||
|
if ( (useTemplateScope && template.isFullScopeAllowed()) || (client.isFullScopeAllowed())) {
|
||||||
|
logger.debug("Using full scope for client");
|
||||||
requestedRoles = roleMappings;
|
requestedRoles = roleMappings;
|
||||||
} else {
|
} else {
|
||||||
|
Set<RoleModel> scopeMappings = new HashSet<>();
|
||||||
Set<RoleModel> scopeMappings = client.getScopeMappings();
|
if (useTemplateScope) {
|
||||||
|
logger.debug("Adding template scope mappings");
|
||||||
|
scopeMappings.addAll(template.getScopeMappings());
|
||||||
|
}
|
||||||
scopeMappings.addAll(client.getRoles());
|
scopeMappings.addAll(client.getRoles());
|
||||||
|
Set<RoleModel> clientScopeMappings = client.getScopeMappings();
|
||||||
|
scopeMappings.addAll(clientScopeMappings);
|
||||||
for (RoleModel role : roleMappings) {
|
for (RoleModel role : roleMappings) {
|
||||||
for (RoleModel desiredRole : scopeMappings) {
|
for (RoleModel desiredRole : scopeMappings) {
|
||||||
Set<RoleModel> visited = new HashSet<RoleModel>();
|
Set<RoleModel> visited = new HashSet<RoleModel>();
|
||||||
|
@ -337,7 +345,6 @@ public class TokenManager {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (applyScopeParam) {
|
if (applyScopeParam) {
|
||||||
Collection<String> scopeParamRoles;
|
Collection<String> scopeParamRoles;
|
||||||
if (scopeParam != null) {
|
if (scopeParam != null) {
|
||||||
|
|
|
@ -67,7 +67,7 @@ public class ClientTemplateResource {
|
||||||
protected RealmModel realm;
|
protected RealmModel realm;
|
||||||
private RealmAuth auth;
|
private RealmAuth auth;
|
||||||
private AdminEventBuilder adminEvent;
|
private AdminEventBuilder adminEvent;
|
||||||
protected ClientTemplateModel client;
|
protected ClientTemplateModel template;
|
||||||
protected KeycloakSession session;
|
protected KeycloakSession session;
|
||||||
|
|
||||||
@Context
|
@Context
|
||||||
|
@ -80,10 +80,10 @@ public class ClientTemplateResource {
|
||||||
return keycloak;
|
return keycloak;
|
||||||
}
|
}
|
||||||
|
|
||||||
public ClientTemplateResource(RealmModel realm, RealmAuth auth, ClientTemplateModel clientModel, KeycloakSession session, AdminEventBuilder adminEvent) {
|
public ClientTemplateResource(RealmModel realm, RealmAuth auth, ClientTemplateModel template, KeycloakSession session, AdminEventBuilder adminEvent) {
|
||||||
this.realm = realm;
|
this.realm = realm;
|
||||||
this.auth = auth;
|
this.auth = auth;
|
||||||
this.client = clientModel;
|
this.template = template;
|
||||||
this.session = session;
|
this.session = session;
|
||||||
this.adminEvent = adminEvent;
|
this.adminEvent = adminEvent;
|
||||||
|
|
||||||
|
@ -92,11 +92,21 @@ public class ClientTemplateResource {
|
||||||
|
|
||||||
@Path("protocol-mappers")
|
@Path("protocol-mappers")
|
||||||
public ProtocolMappersResource getProtocolMappers() {
|
public ProtocolMappersResource getProtocolMappers() {
|
||||||
ProtocolMappersResource mappers = new ProtocolMappersResource(client, auth, adminEvent);
|
ProtocolMappersResource mappers = new ProtocolMappersResource(template, auth, adminEvent);
|
||||||
ResteasyProviderFactory.getInstance().injectProperties(mappers);
|
ResteasyProviderFactory.getInstance().injectProperties(mappers);
|
||||||
return mappers;
|
return mappers;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Base path for managing the scope mappings for the client
|
||||||
|
*
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
@Path("scope-mappings")
|
||||||
|
public ScopeMappedResource getScopeMappedResource() {
|
||||||
|
return new ScopeMappedResource(realm, auth, template, session, adminEvent);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Update the client template
|
* Update the client template
|
||||||
* @param rep
|
* @param rep
|
||||||
|
@ -108,7 +118,7 @@ public class ClientTemplateResource {
|
||||||
auth.requireManage();
|
auth.requireManage();
|
||||||
|
|
||||||
try {
|
try {
|
||||||
RepresentationToModel.updateClientTemplate(rep, client);
|
RepresentationToModel.updateClientTemplate(rep, template);
|
||||||
adminEvent.operation(OperationType.UPDATE).resourcePath(uriInfo).representation(rep).success();
|
adminEvent.operation(OperationType.UPDATE).resourcePath(uriInfo).representation(rep).success();
|
||||||
return Response.noContent().build();
|
return Response.noContent().build();
|
||||||
} catch (ModelDuplicateException e) {
|
} catch (ModelDuplicateException e) {
|
||||||
|
@ -127,7 +137,7 @@ public class ClientTemplateResource {
|
||||||
@Produces(MediaType.APPLICATION_JSON)
|
@Produces(MediaType.APPLICATION_JSON)
|
||||||
public ClientTemplateRepresentation getClient() {
|
public ClientTemplateRepresentation getClient() {
|
||||||
auth.requireView();
|
auth.requireView();
|
||||||
return ModelToRepresentation.toRepresentation(client);
|
return ModelToRepresentation.toRepresentation(template);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -138,7 +148,7 @@ public class ClientTemplateResource {
|
||||||
@NoCache
|
@NoCache
|
||||||
public void deleteClientTemplate() {
|
public void deleteClientTemplate() {
|
||||||
auth.requireManage();
|
auth.requireManage();
|
||||||
realm.removeClientTemplate(client.getId());
|
realm.removeClientTemplate(template.getId());
|
||||||
adminEvent.operation(OperationType.DELETE).resourcePath(uriInfo).success();
|
adminEvent.operation(OperationType.DELETE).resourcePath(uriInfo).success();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -7,6 +7,8 @@ import org.keycloak.models.ClientModel;
|
||||||
import org.keycloak.models.KeycloakSession;
|
import org.keycloak.models.KeycloakSession;
|
||||||
import org.keycloak.models.RealmModel;
|
import org.keycloak.models.RealmModel;
|
||||||
import org.keycloak.models.RoleModel;
|
import org.keycloak.models.RoleModel;
|
||||||
|
import org.keycloak.models.ScopeContainerModel;
|
||||||
|
import org.keycloak.models.utils.KeycloakModelUtils;
|
||||||
import org.keycloak.models.utils.ModelToRepresentation;
|
import org.keycloak.models.utils.ModelToRepresentation;
|
||||||
import org.keycloak.representations.idm.RoleRepresentation;
|
import org.keycloak.representations.idm.RoleRepresentation;
|
||||||
|
|
||||||
|
@ -29,15 +31,15 @@ import java.util.Set;
|
||||||
public class ScopeMappedClientResource {
|
public class ScopeMappedClientResource {
|
||||||
protected RealmModel realm;
|
protected RealmModel realm;
|
||||||
private RealmAuth auth;
|
private RealmAuth auth;
|
||||||
protected ClientModel client;
|
protected ScopeContainerModel scopeContainer;
|
||||||
protected KeycloakSession session;
|
protected KeycloakSession session;
|
||||||
protected ClientModel scopedClient;
|
protected ClientModel scopedClient;
|
||||||
protected AdminEventBuilder adminEvent;
|
protected AdminEventBuilder adminEvent;
|
||||||
|
|
||||||
public ScopeMappedClientResource(RealmModel realm, RealmAuth auth, ClientModel client, KeycloakSession session, ClientModel scopedClient, AdminEventBuilder adminEvent) {
|
public ScopeMappedClientResource(RealmModel realm, RealmAuth auth, ScopeContainerModel scopeContainer, KeycloakSession session, ClientModel scopedClient, AdminEventBuilder adminEvent) {
|
||||||
this.realm = realm;
|
this.realm = realm;
|
||||||
this.auth = auth;
|
this.auth = auth;
|
||||||
this.client = client;
|
this.scopeContainer = scopeContainer;
|
||||||
this.session = session;
|
this.session = session;
|
||||||
this.scopedClient = scopedClient;
|
this.scopedClient = scopedClient;
|
||||||
this.adminEvent = adminEvent;
|
this.adminEvent = adminEvent;
|
||||||
|
@ -56,7 +58,7 @@ public class ScopeMappedClientResource {
|
||||||
public List<RoleRepresentation> getClientScopeMappings() {
|
public List<RoleRepresentation> getClientScopeMappings() {
|
||||||
auth.requireView();
|
auth.requireView();
|
||||||
|
|
||||||
Set<RoleModel> mappings = scopedClient.getClientScopeMappings(client);
|
Set<RoleModel> mappings = KeycloakModelUtils.getClientScopeMappings(scopedClient, scopeContainer); //scopedClient.getClientScopeMappings(client);
|
||||||
List<RoleRepresentation> mapRep = new ArrayList<RoleRepresentation>();
|
List<RoleRepresentation> mapRep = new ArrayList<RoleRepresentation>();
|
||||||
for (RoleModel roleModel : mappings) {
|
for (RoleModel roleModel : mappings) {
|
||||||
mapRep.add(ModelToRepresentation.toRepresentation(roleModel));
|
mapRep.add(ModelToRepresentation.toRepresentation(roleModel));
|
||||||
|
@ -79,7 +81,7 @@ public class ScopeMappedClientResource {
|
||||||
auth.requireView();
|
auth.requireView();
|
||||||
|
|
||||||
Set<RoleModel> roles = scopedClient.getRoles();
|
Set<RoleModel> roles = scopedClient.getRoles();
|
||||||
return ScopeMappedResource.getAvailable(client, roles);
|
return ScopeMappedResource.getAvailable(scopeContainer, roles);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -97,7 +99,7 @@ public class ScopeMappedClientResource {
|
||||||
auth.requireView();
|
auth.requireView();
|
||||||
|
|
||||||
Set<RoleModel> roles = scopedClient.getRoles();
|
Set<RoleModel> roles = scopedClient.getRoles();
|
||||||
return ScopeMappedResource.getComposite(client, roles);
|
return ScopeMappedResource.getComposite(scopeContainer, roles);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -115,7 +117,7 @@ public class ScopeMappedClientResource {
|
||||||
if (roleModel == null) {
|
if (roleModel == null) {
|
||||||
throw new NotFoundException("Role not found");
|
throw new NotFoundException("Role not found");
|
||||||
}
|
}
|
||||||
client.addScopeMapping(roleModel);
|
scopeContainer.addScopeMapping(roleModel);
|
||||||
adminEvent.operation(OperationType.CREATE).resourcePath(session.getContext().getUri(), roleModel.getId()).representation(roles).success();
|
adminEvent.operation(OperationType.CREATE).resourcePath(session.getContext().getUri(), roleModel.getId()).representation(roles).success();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -131,9 +133,9 @@ public class ScopeMappedClientResource {
|
||||||
auth.requireManage();
|
auth.requireManage();
|
||||||
|
|
||||||
if (roles == null) {
|
if (roles == null) {
|
||||||
Set<RoleModel> roleModels = scopedClient.getClientScopeMappings(client);
|
Set<RoleModel> roleModels = KeycloakModelUtils.getClientScopeMappings(scopedClient, scopeContainer);//scopedClient.getClientScopeMappings(client);
|
||||||
for (RoleModel roleModel : roleModels) {
|
for (RoleModel roleModel : roleModels) {
|
||||||
client.deleteScopeMapping(roleModel);
|
scopeContainer.deleteScopeMapping(roleModel);
|
||||||
}
|
}
|
||||||
adminEvent.operation(OperationType.DELETE).resourcePath(session.getContext().getUri()).representation(roles).success();
|
adminEvent.operation(OperationType.DELETE).resourcePath(session.getContext().getUri()).representation(roles).success();
|
||||||
} else {
|
} else {
|
||||||
|
@ -142,7 +144,7 @@ public class ScopeMappedClientResource {
|
||||||
if (roleModel == null) {
|
if (roleModel == null) {
|
||||||
throw new NotFoundException("Role not found");
|
throw new NotFoundException("Role not found");
|
||||||
}
|
}
|
||||||
client.deleteScopeMapping(roleModel);
|
scopeContainer.deleteScopeMapping(roleModel);
|
||||||
adminEvent.operation(OperationType.DELETE).resourcePath(session.getContext().getUri(), roleModel.getId()).representation(roles).success();
|
adminEvent.operation(OperationType.DELETE).resourcePath(session.getContext().getUri(), roleModel.getId()).representation(roles).success();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,6 +7,8 @@ import org.keycloak.models.ClientModel;
|
||||||
import org.keycloak.models.KeycloakSession;
|
import org.keycloak.models.KeycloakSession;
|
||||||
import org.keycloak.models.RealmModel;
|
import org.keycloak.models.RealmModel;
|
||||||
import org.keycloak.models.RoleModel;
|
import org.keycloak.models.RoleModel;
|
||||||
|
import org.keycloak.models.ScopeContainerModel;
|
||||||
|
import org.keycloak.models.utils.KeycloakModelUtils;
|
||||||
import org.keycloak.models.utils.ModelToRepresentation;
|
import org.keycloak.models.utils.ModelToRepresentation;
|
||||||
import org.keycloak.representations.idm.ClientMappingsRepresentation;
|
import org.keycloak.representations.idm.ClientMappingsRepresentation;
|
||||||
import org.keycloak.representations.idm.MappingsRepresentation;
|
import org.keycloak.representations.idm.MappingsRepresentation;
|
||||||
|
@ -36,14 +38,14 @@ import java.util.Set;
|
||||||
public class ScopeMappedResource {
|
public class ScopeMappedResource {
|
||||||
protected RealmModel realm;
|
protected RealmModel realm;
|
||||||
private RealmAuth auth;
|
private RealmAuth auth;
|
||||||
protected ClientModel client;
|
protected ScopeContainerModel scopeContainer;
|
||||||
protected KeycloakSession session;
|
protected KeycloakSession session;
|
||||||
protected AdminEventBuilder adminEvent;
|
protected AdminEventBuilder adminEvent;
|
||||||
|
|
||||||
public ScopeMappedResource(RealmModel realm, RealmAuth auth, ClientModel client, KeycloakSession session, AdminEventBuilder adminEvent) {
|
public ScopeMappedResource(RealmModel realm, RealmAuth auth, ScopeContainerModel scopeContainer, KeycloakSession session, AdminEventBuilder adminEvent) {
|
||||||
this.realm = realm;
|
this.realm = realm;
|
||||||
this.auth = auth;
|
this.auth = auth;
|
||||||
this.client = client;
|
this.scopeContainer = scopeContainer;
|
||||||
this.session = session;
|
this.session = session;
|
||||||
this.adminEvent = adminEvent;
|
this.adminEvent = adminEvent;
|
||||||
}
|
}
|
||||||
|
@ -60,7 +62,7 @@ public class ScopeMappedResource {
|
||||||
auth.requireView();
|
auth.requireView();
|
||||||
|
|
||||||
MappingsRepresentation all = new MappingsRepresentation();
|
MappingsRepresentation all = new MappingsRepresentation();
|
||||||
Set<RoleModel> realmMappings = client.getRealmScopeMappings();
|
Set<RoleModel> realmMappings = scopeContainer.getRealmScopeMappings();
|
||||||
if (realmMappings.size() > 0) {
|
if (realmMappings.size() > 0) {
|
||||||
List<RoleRepresentation> realmRep = new ArrayList<RoleRepresentation>();
|
List<RoleRepresentation> realmRep = new ArrayList<RoleRepresentation>();
|
||||||
for (RoleModel roleModel : realmMappings) {
|
for (RoleModel roleModel : realmMappings) {
|
||||||
|
@ -73,7 +75,7 @@ public class ScopeMappedResource {
|
||||||
if (clients.size() > 0) {
|
if (clients.size() > 0) {
|
||||||
Map<String, ClientMappingsRepresentation> clientMappings = new HashMap<String, ClientMappingsRepresentation>();
|
Map<String, ClientMappingsRepresentation> clientMappings = new HashMap<String, ClientMappingsRepresentation>();
|
||||||
for (ClientModel client : clients) {
|
for (ClientModel client : clients) {
|
||||||
Set<RoleModel> roleMappings = client.getClientScopeMappings(this.client);
|
Set<RoleModel> roleMappings = KeycloakModelUtils.getClientScopeMappings(client, this.scopeContainer); //client.getClientScopeMappings(this.client);
|
||||||
if (roleMappings.size() > 0) {
|
if (roleMappings.size() > 0) {
|
||||||
ClientMappingsRepresentation mappings = new ClientMappingsRepresentation();
|
ClientMappingsRepresentation mappings = new ClientMappingsRepresentation();
|
||||||
mappings.setId(client.getId());
|
mappings.setId(client.getId());
|
||||||
|
@ -103,7 +105,7 @@ public class ScopeMappedResource {
|
||||||
public List<RoleRepresentation> getRealmScopeMappings() {
|
public List<RoleRepresentation> getRealmScopeMappings() {
|
||||||
auth.requireView();
|
auth.requireView();
|
||||||
|
|
||||||
Set<RoleModel> realmMappings = client.getRealmScopeMappings();
|
Set<RoleModel> realmMappings = scopeContainer.getRealmScopeMappings();
|
||||||
List<RoleRepresentation> realmMappingsRep = new ArrayList<RoleRepresentation>();
|
List<RoleRepresentation> realmMappingsRep = new ArrayList<RoleRepresentation>();
|
||||||
for (RoleModel roleModel : realmMappings) {
|
for (RoleModel roleModel : realmMappings) {
|
||||||
realmMappingsRep.add(ModelToRepresentation.toRepresentation(roleModel));
|
realmMappingsRep.add(ModelToRepresentation.toRepresentation(roleModel));
|
||||||
|
@ -124,10 +126,10 @@ public class ScopeMappedResource {
|
||||||
auth.requireView();
|
auth.requireView();
|
||||||
|
|
||||||
Set<RoleModel> roles = realm.getRoles();
|
Set<RoleModel> roles = realm.getRoles();
|
||||||
return getAvailable(client, roles);
|
return getAvailable(scopeContainer, roles);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static List<RoleRepresentation> getAvailable(ClientModel client, Set<RoleModel> roles) {
|
public static List<RoleRepresentation> getAvailable(ScopeContainerModel client, Set<RoleModel> roles) {
|
||||||
List<RoleRepresentation> available = new ArrayList<RoleRepresentation>();
|
List<RoleRepresentation> available = new ArrayList<RoleRepresentation>();
|
||||||
for (RoleModel roleModel : roles) {
|
for (RoleModel roleModel : roles) {
|
||||||
if (client.hasScope(roleModel)) continue;
|
if (client.hasScope(roleModel)) continue;
|
||||||
|
@ -153,10 +155,10 @@ public class ScopeMappedResource {
|
||||||
auth.requireView();
|
auth.requireView();
|
||||||
|
|
||||||
Set<RoleModel> roles = realm.getRoles();
|
Set<RoleModel> roles = realm.getRoles();
|
||||||
return getComposite(client, roles);
|
return getComposite(scopeContainer, roles);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static List<RoleRepresentation> getComposite(ClientModel client, Set<RoleModel> roles) {
|
public static List<RoleRepresentation> getComposite(ScopeContainerModel client, Set<RoleModel> roles) {
|
||||||
List<RoleRepresentation> composite = new ArrayList<RoleRepresentation>();
|
List<RoleRepresentation> composite = new ArrayList<RoleRepresentation>();
|
||||||
for (RoleModel roleModel : roles) {
|
for (RoleModel roleModel : roles) {
|
||||||
if (client.hasScope(roleModel)) composite.add(ModelToRepresentation.toRepresentation(roleModel));
|
if (client.hasScope(roleModel)) composite.add(ModelToRepresentation.toRepresentation(roleModel));
|
||||||
|
@ -180,7 +182,7 @@ public class ScopeMappedResource {
|
||||||
if (roleModel == null) {
|
if (roleModel == null) {
|
||||||
throw new NotFoundException("Role not found");
|
throw new NotFoundException("Role not found");
|
||||||
}
|
}
|
||||||
client.addScopeMapping(roleModel);
|
scopeContainer.addScopeMapping(roleModel);
|
||||||
adminEvent.operation(OperationType.CREATE).resourcePath(session.getContext().getUri(), role.getId()).representation(roles).success();
|
adminEvent.operation(OperationType.CREATE).resourcePath(session.getContext().getUri(), role.getId()).representation(roles).success();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -197,9 +199,9 @@ public class ScopeMappedResource {
|
||||||
auth.requireManage();
|
auth.requireManage();
|
||||||
|
|
||||||
if (roles == null) {
|
if (roles == null) {
|
||||||
Set<RoleModel> roleModels = client.getRealmScopeMappings();
|
Set<RoleModel> roleModels = scopeContainer.getRealmScopeMappings();
|
||||||
for (RoleModel roleModel : roleModels) {
|
for (RoleModel roleModel : roleModels) {
|
||||||
client.deleteScopeMapping(roleModel);
|
scopeContainer.deleteScopeMapping(roleModel);
|
||||||
}
|
}
|
||||||
adminEvent.operation(OperationType.DELETE).resourcePath(session.getContext().getUri()).representation(roles).success();
|
adminEvent.operation(OperationType.DELETE).resourcePath(session.getContext().getUri()).representation(roles).success();
|
||||||
} else {
|
} else {
|
||||||
|
@ -208,7 +210,7 @@ public class ScopeMappedResource {
|
||||||
if (roleModel == null) {
|
if (roleModel == null) {
|
||||||
throw new NotFoundException("Client not found");
|
throw new NotFoundException("Client not found");
|
||||||
}
|
}
|
||||||
client.deleteScopeMapping(roleModel);
|
scopeContainer.deleteScopeMapping(roleModel);
|
||||||
adminEvent.operation(OperationType.DELETE).resourcePath(session.getContext().getUri(), roleModel.getId()).representation(roles).success();
|
adminEvent.operation(OperationType.DELETE).resourcePath(session.getContext().getUri(), roleModel.getId()).representation(roles).success();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -221,6 +223,6 @@ public class ScopeMappedResource {
|
||||||
if (clientModel == null) {
|
if (clientModel == null) {
|
||||||
throw new NotFoundException("Client not found");
|
throw new NotFoundException("Client not found");
|
||||||
}
|
}
|
||||||
return new ScopeMappedClientResource(realm, auth, this.client, session, clientModel, adminEvent);
|
return new ScopeMappedClientResource(realm, auth, this.scopeContainer, session, clientModel, adminEvent);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -168,7 +168,7 @@ public class AccountTest {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
//@Test
|
@Test
|
||||||
public void ideTesting() throws Exception {
|
public void ideTesting() throws Exception {
|
||||||
Thread.sleep(100000000);
|
Thread.sleep(100000000);
|
||||||
}
|
}
|
||||||
|
|
|
@ -25,6 +25,7 @@ import org.keycloak.models.UserFederationProviderFactory;
|
||||||
import org.keycloak.models.UserFederationProviderModel;
|
import org.keycloak.models.UserFederationProviderModel;
|
||||||
import org.keycloak.models.UserModel;
|
import org.keycloak.models.UserModel;
|
||||||
import org.keycloak.models.utils.DefaultAuthenticationFlows;
|
import org.keycloak.models.utils.DefaultAuthenticationFlows;
|
||||||
|
import org.keycloak.models.utils.KeycloakModelUtils;
|
||||||
import org.keycloak.protocol.oidc.OIDCLoginProtocol;
|
import org.keycloak.protocol.oidc.OIDCLoginProtocol;
|
||||||
import org.keycloak.protocol.oidc.mappers.OIDCAttributeMapperHelper;
|
import org.keycloak.protocol.oidc.mappers.OIDCAttributeMapperHelper;
|
||||||
import org.keycloak.protocol.oidc.mappers.UserSessionNoteMapper;
|
import org.keycloak.protocol.oidc.mappers.UserSessionNoteMapper;
|
||||||
|
@ -191,7 +192,7 @@ public class ImportTest extends AbstractModelTest {
|
||||||
Set<RoleModel> realmScopes = oauthClient.getRealmScopeMappings();
|
Set<RoleModel> realmScopes = oauthClient.getRealmScopeMappings();
|
||||||
Assert.assertTrue(realmScopes.contains(realm.getRole("admin")));
|
Assert.assertTrue(realmScopes.contains(realm.getRole("admin")));
|
||||||
|
|
||||||
Set<RoleModel> appScopes = application.getClientScopeMappings(oauthClient);
|
Set<RoleModel> appScopes = KeycloakModelUtils.getClientScopeMappings(application, oauthClient);//application.getClientScopeMappings(oauthClient);
|
||||||
Assert.assertTrue(appScopes.contains(application.getRole("app-user")));
|
Assert.assertTrue(appScopes.contains(application.getRole("app-user")));
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -62,6 +62,8 @@ import org.keycloak.representations.IDToken;
|
||||||
import org.keycloak.representations.idm.ClientRepresentation;
|
import org.keycloak.representations.idm.ClientRepresentation;
|
||||||
import org.keycloak.representations.idm.ClientTemplateRepresentation;
|
import org.keycloak.representations.idm.ClientTemplateRepresentation;
|
||||||
import org.keycloak.representations.idm.ProtocolMapperRepresentation;
|
import org.keycloak.representations.idm.ProtocolMapperRepresentation;
|
||||||
|
import org.keycloak.representations.idm.RoleRepresentation;
|
||||||
|
import org.keycloak.representations.idm.UserRepresentation;
|
||||||
import org.keycloak.services.managers.RealmManager;
|
import org.keycloak.services.managers.RealmManager;
|
||||||
import org.keycloak.testsuite.AssertEvents;
|
import org.keycloak.testsuite.AssertEvents;
|
||||||
import org.keycloak.testsuite.OAuthClient;
|
import org.keycloak.testsuite.OAuthClient;
|
||||||
|
@ -803,6 +805,25 @@ public class AccessTokenTest {
|
||||||
@Test
|
@Test
|
||||||
public void testClientTemplate() throws Exception {
|
public void testClientTemplate() throws Exception {
|
||||||
RealmResource realm = keycloak.realms().realm("test");
|
RealmResource realm = keycloak.realms().realm("test");
|
||||||
|
RoleRepresentation realmRole = new RoleRepresentation();
|
||||||
|
realmRole.setName("realm-test-role");
|
||||||
|
realm.roles().create(realmRole);
|
||||||
|
realmRole = realm.roles().get("realm-test-role").toRepresentation();
|
||||||
|
RoleRepresentation realmRole2 = new RoleRepresentation();
|
||||||
|
realmRole2.setName("realm-test-role2");
|
||||||
|
realm.roles().create(realmRole2);
|
||||||
|
realmRole2 = realm.roles().get("realm-test-role2").toRepresentation();
|
||||||
|
|
||||||
|
|
||||||
|
List<UserRepresentation> users = realm.users().search("test-user@localhost", -1, -1);
|
||||||
|
Assert.assertEquals(1, users.size());
|
||||||
|
UserRepresentation user = users.get(0);
|
||||||
|
|
||||||
|
List<RoleRepresentation> addRoles = new LinkedList<>();
|
||||||
|
addRoles.add(realmRole);
|
||||||
|
addRoles.add(realmRole2);
|
||||||
|
realm.users().get(user.getId()).roles().realmLevel().add(addRoles);
|
||||||
|
|
||||||
ClientTemplateRepresentation rep = new ClientTemplateRepresentation();
|
ClientTemplateRepresentation rep = new ClientTemplateRepresentation();
|
||||||
rep.setName("template");
|
rep.setName("template");
|
||||||
rep.setProtocol("oidc");
|
rep.setProtocol("oidc");
|
||||||
|
@ -825,8 +846,8 @@ public class AccessTokenTest {
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
Assert.assertNotNull(clientRep);
|
|
||||||
clientRep.setClientTemplate("template");
|
clientRep.setClientTemplate("template");
|
||||||
|
clientRep.setFullScopeAllowed(false);
|
||||||
realm.clients().get(clientRep.getId()).update(clientRep);
|
realm.clients().get(clientRep.getId()).update(clientRep);
|
||||||
|
|
||||||
{
|
{
|
||||||
|
@ -844,13 +865,150 @@ public class AccessTokenTest {
|
||||||
AccessToken accessToken = getAccessToken(tokenResponse);
|
AccessToken accessToken = getAccessToken(tokenResponse);
|
||||||
Assert.assertEquals("coded", accessToken.getOtherClaims().get("hard"));
|
Assert.assertEquals("coded", accessToken.getOtherClaims().get("hard"));
|
||||||
|
|
||||||
|
// check zero scope for template
|
||||||
|
Assert.assertFalse(accessToken.getRealmAccess().getRoles().contains(realmRole.getName()));
|
||||||
|
Assert.assertFalse(accessToken.getRealmAccess().getRoles().contains(realmRole2.getName()));
|
||||||
|
|
||||||
|
|
||||||
response.close();
|
response.close();
|
||||||
client.close();
|
client.close();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// test that scope is added
|
||||||
|
List<RoleRepresentation> addRole1 = new LinkedList<>();
|
||||||
|
addRole1.add(realmRole);
|
||||||
|
templateResource.getScopeMappings().realmLevel().add(addRole1);
|
||||||
|
|
||||||
|
{
|
||||||
|
Client client = ClientBuilder.newClient();
|
||||||
|
UriBuilder builder = UriBuilder.fromUri(org.keycloak.testsuite.Constants.AUTH_SERVER_ROOT);
|
||||||
|
URI grantUri = OIDCLoginProtocolService.tokenUrl(builder).build("test");
|
||||||
|
WebTarget grantTarget = client.target(grantUri);
|
||||||
|
|
||||||
|
response = executeGrantAccessTokenRequest(grantTarget);
|
||||||
|
Assert.assertEquals(200, response.getStatus());
|
||||||
|
org.keycloak.representations.AccessTokenResponse tokenResponse = response.readEntity(org.keycloak.representations.AccessTokenResponse.class);
|
||||||
|
AccessToken accessToken = getAccessToken(tokenResponse);
|
||||||
|
// check zero scope for template
|
||||||
|
Assert.assertNotNull(accessToken.getRealmAccess());
|
||||||
|
Assert.assertTrue(accessToken.getRealmAccess().getRoles().contains(realmRole.getName()));
|
||||||
|
Assert.assertFalse(accessToken.getRealmAccess().getRoles().contains(realmRole2.getName()));
|
||||||
|
|
||||||
|
|
||||||
|
response.close();
|
||||||
|
client.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
// test combined scopes
|
||||||
|
List<RoleRepresentation> addRole2 = new LinkedList<>();
|
||||||
|
addRole2.add(realmRole2);
|
||||||
|
realm.clients().get(clientRep.getId()).getScopeMappings().realmLevel().add(addRole2);
|
||||||
|
|
||||||
|
{
|
||||||
|
Client client = ClientBuilder.newClient();
|
||||||
|
UriBuilder builder = UriBuilder.fromUri(org.keycloak.testsuite.Constants.AUTH_SERVER_ROOT);
|
||||||
|
URI grantUri = OIDCLoginProtocolService.tokenUrl(builder).build("test");
|
||||||
|
WebTarget grantTarget = client.target(grantUri);
|
||||||
|
|
||||||
|
response = executeGrantAccessTokenRequest(grantTarget);
|
||||||
|
Assert.assertEquals(200, response.getStatus());
|
||||||
|
org.keycloak.representations.AccessTokenResponse tokenResponse = response.readEntity(org.keycloak.representations.AccessTokenResponse.class);
|
||||||
|
|
||||||
|
AccessToken accessToken = getAccessToken(tokenResponse);
|
||||||
|
|
||||||
|
// check zero scope for template
|
||||||
|
Assert.assertNotNull(accessToken.getRealmAccess());
|
||||||
|
Assert.assertTrue(accessToken.getRealmAccess().getRoles().contains(realmRole.getName()));
|
||||||
|
Assert.assertTrue(accessToken.getRealmAccess().getRoles().contains(realmRole2.getName()));
|
||||||
|
|
||||||
|
|
||||||
|
response.close();
|
||||||
|
client.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
// remove scopes and retest
|
||||||
|
templateResource.getScopeMappings().realmLevel().remove(addRole1);
|
||||||
|
realm.clients().get(clientRep.getId()).getScopeMappings().realmLevel().remove(addRole2);
|
||||||
|
|
||||||
|
{
|
||||||
|
Client client = ClientBuilder.newClient();
|
||||||
|
UriBuilder builder = UriBuilder.fromUri(org.keycloak.testsuite.Constants.AUTH_SERVER_ROOT);
|
||||||
|
URI grantUri = OIDCLoginProtocolService.tokenUrl(builder).build("test");
|
||||||
|
WebTarget grantTarget = client.target(grantUri);
|
||||||
|
|
||||||
|
response = executeGrantAccessTokenRequest(grantTarget);
|
||||||
|
Assert.assertEquals(200, response.getStatus());
|
||||||
|
org.keycloak.representations.AccessTokenResponse tokenResponse = response.readEntity(org.keycloak.representations.AccessTokenResponse.class);
|
||||||
|
|
||||||
|
AccessToken accessToken = getAccessToken(tokenResponse);
|
||||||
|
Assert.assertFalse(accessToken.getRealmAccess().getRoles().contains(realmRole.getName()));
|
||||||
|
Assert.assertFalse(accessToken.getRealmAccess().getRoles().contains(realmRole2.getName()));
|
||||||
|
|
||||||
|
|
||||||
|
response.close();
|
||||||
|
client.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
// test full scope on template
|
||||||
|
rep.setFullScopeAllowed(true);
|
||||||
|
templateResource.update(rep);
|
||||||
|
|
||||||
|
{
|
||||||
|
Client client = ClientBuilder.newClient();
|
||||||
|
UriBuilder builder = UriBuilder.fromUri(org.keycloak.testsuite.Constants.AUTH_SERVER_ROOT);
|
||||||
|
URI grantUri = OIDCLoginProtocolService.tokenUrl(builder).build("test");
|
||||||
|
WebTarget grantTarget = client.target(grantUri);
|
||||||
|
|
||||||
|
response = executeGrantAccessTokenRequest(grantTarget);
|
||||||
|
Assert.assertEquals(200, response.getStatus());
|
||||||
|
org.keycloak.representations.AccessTokenResponse tokenResponse = response.readEntity(org.keycloak.representations.AccessTokenResponse.class);
|
||||||
|
|
||||||
|
AccessToken accessToken = getAccessToken(tokenResponse);
|
||||||
|
|
||||||
|
// check zero scope for template
|
||||||
|
Assert.assertNotNull(accessToken.getRealmAccess());
|
||||||
|
Assert.assertTrue(accessToken.getRealmAccess().getRoles().contains(realmRole.getName()));
|
||||||
|
Assert.assertTrue(accessToken.getRealmAccess().getRoles().contains(realmRole2.getName()));
|
||||||
|
|
||||||
|
|
||||||
|
response.close();
|
||||||
|
client.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
// test don't use template scope
|
||||||
|
clientRep.setUseTemplateScope(false);
|
||||||
|
realm.clients().get(clientRep.getId()).update(clientRep);
|
||||||
|
|
||||||
|
{
|
||||||
|
Client client = ClientBuilder.newClient();
|
||||||
|
UriBuilder builder = UriBuilder.fromUri(org.keycloak.testsuite.Constants.AUTH_SERVER_ROOT);
|
||||||
|
URI grantUri = OIDCLoginProtocolService.tokenUrl(builder).build("test");
|
||||||
|
WebTarget grantTarget = client.target(grantUri);
|
||||||
|
|
||||||
|
response = executeGrantAccessTokenRequest(grantTarget);
|
||||||
|
Assert.assertEquals(200, response.getStatus());
|
||||||
|
org.keycloak.representations.AccessTokenResponse tokenResponse = response.readEntity(org.keycloak.representations.AccessTokenResponse.class);
|
||||||
|
|
||||||
|
AccessToken accessToken = getAccessToken(tokenResponse);
|
||||||
|
Assert.assertFalse(accessToken.getRealmAccess().getRoles().contains(realmRole.getName()));
|
||||||
|
Assert.assertFalse(accessToken.getRealmAccess().getRoles().contains(realmRole2.getName()));
|
||||||
|
|
||||||
|
|
||||||
|
response.close();
|
||||||
|
client.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// undo mappers
|
// undo mappers
|
||||||
clientRep.setClientTemplate(ClientTemplateRepresentation.NONE);
|
clientRep.setClientTemplate(ClientTemplateRepresentation.NONE);
|
||||||
|
clientRep.setFullScopeAllowed(true);
|
||||||
realm.clients().get(clientRep.getId()).update(clientRep);
|
realm.clients().get(clientRep.getId()).update(clientRep);
|
||||||
|
realm.users().get(user.getId()).roles().realmLevel().remove(addRoles);
|
||||||
|
realm.roles().get(realmRole.getName()).remove();
|
||||||
|
realm.roles().get(realmRole2.getName()).remove();
|
||||||
|
templateResource.remove();
|
||||||
|
|
||||||
{
|
{
|
||||||
Client client = ClientBuilder.newClient();
|
Client client = ClientBuilder.newClient();
|
||||||
|
|
Loading…
Reference in a new issue