Merge pull request #755 from patriot1burke/master

admin console and model attributes
This commit is contained in:
Bill Burke 2014-10-09 18:31:16 -04:00
commit 23d0361168
44 changed files with 928 additions and 499 deletions

View file

@ -1,6 +1,7 @@
package org.keycloak.representations.idm;
import java.util.List;
import java.util.Map;
/**
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
@ -21,6 +22,8 @@ public class ApplicationRepresentation {
protected Integer notBefore;
protected Boolean bearerOnly;
protected Boolean publicClient;
protected String protocol;
protected Map<String, String> attributes;
protected Boolean fullScopeAllowed;
@ -143,4 +146,20 @@ public class ApplicationRepresentation {
public void setFullScopeAllowed(Boolean fullScopeAllowed) {
this.fullScopeAllowed = fullScopeAllowed;
}
public String getProtocol() {
return protocol;
}
public void setProtocol(String protocol) {
this.protocol = protocol;
}
public Map<String, String> getAttributes() {
return attributes;
}
public void setAttributes(Map<String, String> attributes) {
this.attributes = attributes;
}
}

View file

@ -1,6 +1,7 @@
package org.keycloak.representations.idm;
import java.util.List;
import java.util.Map;
/**
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
@ -16,6 +17,8 @@ public class OAuthClientRepresentation {
protected ClaimRepresentation claims;
protected Integer notBefore;
protected Boolean publicClient;
protected String protocol;
protected Map<String, String> attributes;
protected Boolean directGrantsOnly;
protected Boolean fullScopeAllowed;
@ -108,4 +111,19 @@ public class OAuthClientRepresentation {
this.fullScopeAllowed = fullScopeAllowed;
}
public String getProtocol() {
return protocol;
}
public void setProtocol(String protocol) {
this.protocol = protocol;
}
public Map<String, String> getAttributes() {
return attributes;
}
public void setAttributes(Map<String, String> attributes) {
this.attributes = attributes;
}
}

View file

@ -15,7 +15,7 @@ public class UserSessionRepresentation {
private String ipAddress;
private long start;
private long lastAccess;
private Set<String> applications = new HashSet<String>();
private Map<String, String> applications = new HashMap<String, String>();
private Map<String, String> clients = new HashMap<String, String>();
public String getId() {
@ -58,11 +58,11 @@ public class UserSessionRepresentation {
this.lastAccess = lastAccess;
}
public Set<String> getApplications() {
public Map<String, String> getApplications() {
return applications;
}
public void setApplications(Set<String> applications) {
public void setApplications(Map<String, String> applications) {
this.applications = applications;
}

View file

@ -57,7 +57,6 @@ module.factory('authInterceptor', function($q, Auth) {
module.config([ '$routeProvider', function($routeProvider) {
$routeProvider
/*
.when('/create/realm', {

View file

@ -17,14 +17,14 @@ module.controller('ApplicationRoleListCtrl', function($scope, $location, realm,
module.controller('ApplicationCredentialsCtrl', function($scope, $location, realm, application, ApplicationCredentials, Notifications) {
$scope.realm = realm;
$scope.application = application;
var secret = ApplicationCredentials.get({ realm : realm.realm, application : application.name },
var secret = ApplicationCredentials.get({ realm : realm.realm, application : application.id },
function() {
$scope.secret = secret.value;
}
);
$scope.changePassword = function() {
var secret = ApplicationCredentials.update({ realm : realm.realm, application : application.name },
var secret = ApplicationCredentials.update({ realm : realm.realm, application : application.id },
function() {
Notifications.success('The secret has been changed.');
$scope.secret = secret.value;
@ -54,7 +54,7 @@ module.controller('ApplicationSessionsCtrl', function($scope, realm, sessionCoun
$scope.query = {
realm : realm.realm,
application: $scope.application.name,
application: $scope.application.id,
max : 5,
first : 0
}
@ -110,7 +110,7 @@ module.controller('ApplicationClaimsCtrl', function($scope, realm, application,
$scope.save = function () {
ApplicationClaims.update({
realm: realm.realm,
application: application.name
application: application.id
}, $scope.claims, function () {
$scope.changed = false;
claims = angular.copy($scope.claims);
@ -120,7 +120,7 @@ module.controller('ApplicationClaimsCtrl', function($scope, realm, application,
};
$scope.reset = function () {
$location.url("/realms/" + realm.realm + "/applications/" + application.name + "/claims");
$location.url("/realms/" + realm.realm + "/applications/" + application.id + "/claims");
};
});
@ -140,14 +140,14 @@ module.controller('ApplicationRoleDetailCtrl', function($scope, realm, applicati
if ($scope.create) {
ApplicationRole.save({
realm: realm.realm,
application : application.name
application : application.id
}, $scope.role, function (data, headers) {
$scope.changed = false;
role = angular.copy($scope.role);
var l = headers().location;
var id = l.substring(l.lastIndexOf("/") + 1);
$location.url("/realms/" + realm.realm + "/applications/" + application.name + "/roles/" + id);
$location.url("/realms/" + realm.realm + "/applications/" + application.id + "/roles/" + id);
Notifications.success("The role has been created.");
});
} else {
@ -159,17 +159,17 @@ module.controller('ApplicationRoleDetailCtrl', function($scope, realm, applicati
Dialog.confirmDelete($scope.role.name, 'role', function() {
$scope.role.$remove({
realm : realm.realm,
application : application.name,
application : application.id,
role : $scope.role.name
}, function() {
$location.url("/realms/" + realm.realm + "/applications/" + application.name + "/roles");
$location.url("/realms/" + realm.realm + "/applications/" + application.id + "/roles");
Notifications.success("The role has been deleted.");
});
});
};
$scope.cancel = function () {
$location.url("/realms/" + realm.realm + "/applications/" + application.name + "/roles");
$location.url("/realms/" + realm.realm + "/applications/" + application.id + "/roles");
};
@ -180,7 +180,6 @@ module.controller('ApplicationRoleDetailCtrl', function($scope, realm, applicati
});
module.controller('ApplicationListCtrl', function($scope, realm, applications, Application, $location) {
console.log('ApplicationListCtrl');
$scope.realm = realm;
$scope.applications = applications;
$scope.$watch(function() {
@ -234,9 +233,20 @@ module.controller('ApplicationDetailCtrl', function($scope, realm, application,
"bearer-only"
];
$scope.protocols = [
"openid-connect",
"saml"
];
$scope.realm = realm;
$scope.create = !application.name;
$scope.samlServerSignature = false;
$scope.samlClientSignature = false;
$scope.samlServerEncrypt = false;
if (!$scope.create) {
if (!application.attributes) {
application.attributes = {};
}
$scope.application= angular.copy(application);
$scope.accessType = $scope.accessTypes[0];
if (application.bearerOnly) {
@ -244,10 +254,38 @@ module.controller('ApplicationDetailCtrl', function($scope, realm, application,
} else if (application.publicClient) {
$scope.accessType = $scope.accessTypes[1];
}
if (application.protocol == 'openid-connect') {
$scope.protocol = $scope.protocols[0];
} else if (application.protocol == 'saml') {
$scope.protocol = $scope.protocols[1];
} else { // protocol could be null due to older keycloak installs
$scope.protocol = $scope.protocols[0];
}
} else {
$scope.application = { enabled: true };
$scope.application = { enabled: true, attributes: {}};
$scope.application.redirectUris = [];
$scope.accessType = $scope.accessTypes[0];
$scope.protocol = $scope.protocols[0];
}
if ($scope.application.attributes["samlServerSignature"]) {
if ($scope.application.attributes["samlServerSignature"] == "true") {
$scope.samlServerSignature = true;
}
}
if ($scope.application.attributes["samlClientSignature"]) {
if ($scope.application.attributes["samlClientSignature"] == "true") {
$scope.samlClientSignature = true;
}
}
if ($scope.application.attributes["samlServerEncrypt"]) {
if ($scope.application.attributes["samlServerEncrypt"] == "true") {
$scope.samlServerEncrypt = true;
}
}
$scope.switchChange = function() {
$scope.changed = true;
}
$scope.changeAccessType = function() {
@ -263,6 +301,14 @@ module.controller('ApplicationDetailCtrl', function($scope, realm, application,
}
};
$scope.changeProtocol = function() {
if ($scope.protocol == "openid-connect") {
$scope.application.protocol = "openid-connect";
} else if ($scope.accessType == "saml") {
$scope.application.protocol = "saml";
}
};
$scope.$watch(function() {
return $location.path();
}, function() {
@ -291,6 +337,18 @@ module.controller('ApplicationDetailCtrl', function($scope, realm, application,
}
$scope.save = function() {
if ($scope.samlServerSignature == true) {
$scope.application.attributes["samlServerSignature"] = "true";
}
if ($scope.samlClientSignature == true) {
$scope.application.attributes["samlClientSignature"] = "true";
}
if ($scope.samlServerEncrypt == true) {
$scope.application.attributes["samlServerEncrypt"] = "true";
}
$scope.application.protocol = $scope.protocol;
if (!$scope.application.bearerOnly && (!$scope.application.redirectUris || $scope.application.redirectUris.length == 0)) {
Notifications.error("You must specify at least one redirect uri");
} else {
@ -308,11 +366,11 @@ module.controller('ApplicationDetailCtrl', function($scope, realm, application,
} else {
Application.update({
realm : realm.realm,
application : application.name
application : application.id
}, $scope.application, function() {
$scope.changed = false;
application = angular.copy($scope.application);
$location.url("/realms/" + realm.realm + "/applications/" + application.name);
$location.url("/realms/" + realm.realm + "/applications/" + application.id);
Notifications.success("Your changes have been saved to the application.");
});
}
@ -332,7 +390,7 @@ module.controller('ApplicationDetailCtrl', function($scope, realm, application,
Dialog.confirmDelete($scope.application.name, 'application', function() {
$scope.application.$remove({
realm : realm.realm,
application : $scope.application.name
application : $scope.application.id
}, function() {
$location.url("/realms/" + realm.realm + "/applications");
Notifications.success("The application has been deleted.");
@ -366,7 +424,7 @@ module.controller('ApplicationScopeMappingCtrl', function($scope, $http, realm,
console.log('change full scope');
Application.update({
realm : realm.realm,
application : application.name
application : application.id
}, $scope.application, function() {
$scope.changed = false;
application = angular.copy($scope.application);
@ -378,17 +436,17 @@ module.controller('ApplicationScopeMappingCtrl', function($scope, $http, realm,
function updateRealmRoles() {
$scope.realmRoles = ApplicationAvailableRealmScopeMapping.query({realm : realm.realm, application : application.name});
$scope.realmMappings = ApplicationRealmScopeMapping.query({realm : realm.realm, application : application.name});
$scope.realmComposite = ApplicationCompositeRealmScopeMapping.query({realm : realm.realm, application : application.name});
$scope.realmRoles = ApplicationAvailableRealmScopeMapping.query({realm : realm.realm, application : application.id});
$scope.realmMappings = ApplicationRealmScopeMapping.query({realm : realm.realm, application : application.id});
$scope.realmComposite = ApplicationCompositeRealmScopeMapping.query({realm : realm.realm, application : application.id});
}
function updateAppRoles() {
if ($scope.targetApp) {
console.debug($scope.targetApp.name);
$scope.applicationRoles = ApplicationAvailableApplicationScopeMapping.query({realm : realm.realm, application : application.name, targetApp : $scope.targetApp.name});
$scope.applicationMappings = ApplicationApplicationScopeMapping.query({realm : realm.realm, application : application.name, targetApp : $scope.targetApp.name});
$scope.applicationComposite = ApplicationCompositeApplicationScopeMapping.query({realm : realm.realm, application : application.name, targetApp : $scope.targetApp.name});
$scope.applicationRoles = ApplicationAvailableApplicationScopeMapping.query({realm : realm.realm, application : application.id, targetApp : $scope.targetApp.id});
$scope.applicationMappings = ApplicationApplicationScopeMapping.query({realm : realm.realm, application : application.id, targetApp : $scope.targetApp.id});
$scope.applicationComposite = ApplicationCompositeApplicationScopeMapping.query({realm : realm.realm, application : application.id, targetApp : $scope.targetApp.id});
} else {
$scope.applicationRoles = null;
$scope.applicationMappings = null;
@ -401,7 +459,7 @@ module.controller('ApplicationScopeMappingCtrl', function($scope, $http, realm,
};
$scope.addRealmRole = function() {
$http.post(authUrl + '/admin/realms/' + realm.realm + '/applications/' + application.name + '/scope-mappings/realm',
$http.post(authUrl + '/admin/realms/' + realm.realm + '/applications-by-id/' + application.id + '/scope-mappings/realm',
$scope.selectedRealmRoles).success(function() {
updateRealmRoles();
Notifications.success("Scope mappings updated.");
@ -409,7 +467,7 @@ module.controller('ApplicationScopeMappingCtrl', function($scope, $http, realm,
};
$scope.deleteRealmRole = function() {
$http.delete(authUrl + '/admin/realms/' + realm.realm + '/applications/' + application.name + '/scope-mappings/realm',
$http.delete(authUrl + '/admin/realms/' + realm.realm + '/applications-by-id/' + application.id + '/scope-mappings/realm',
{data : $scope.selectedRealmMappings, headers : {"content-type" : "application/json"}}).success(function () {
updateRealmRoles();
Notifications.success("Scope mappings updated.");
@ -417,7 +475,7 @@ module.controller('ApplicationScopeMappingCtrl', function($scope, $http, realm,
};
$scope.addApplicationRole = function() {
$http.post(authUrl + '/admin/realms/' + realm.realm + '/applications/' + application.name + '/scope-mappings/applications/' + $scope.targetApp.name,
$http.post(authUrl + '/admin/realms/' + realm.realm + '/applications-by-id/' + application.id + '/scope-mappings/applications-by-id/' + $scope.targetApp.id,
$scope.selectedApplicationRoles).success(function () {
updateAppRoles();
Notifications.success("Scope mappings updated.");
@ -425,7 +483,7 @@ module.controller('ApplicationScopeMappingCtrl', function($scope, $http, realm,
};
$scope.deleteApplicationRole = function() {
$http.delete(authUrl + '/admin/realms/' + realm.realm + '/applications/' + application.name + '/scope-mappings/applications/' + $scope.targetApp.name,
$http.delete(authUrl + '/admin/realms/' + realm.realm + '/applications-by-id/' + application.id + '/scope-mappings/applications-by-id/' + $scope.targetApp.id,
{data : $scope.selectedApplicationMappings, headers : {"content-type" : "application/json"}}).success(function () {
updateAppRoles();
Notifications.success("Scope mappings updated.");
@ -450,7 +508,7 @@ module.controller('ApplicationRevocationCtrl', function($scope, realm, applicati
setNotBefore();
var refresh = function() {
Application.get({ realm : realm.realm, application: $scope.application.name }, function(updated) {
Application.get({ realm : realm.realm, application: $scope.application.id }, function(updated) {
$scope.application = updated;
setNotBefore();
})
@ -459,7 +517,7 @@ module.controller('ApplicationRevocationCtrl', function($scope, realm, applicati
$scope.clear = function() {
$scope.application.notBefore = 0;
Application.update({ realm : realm.realm, application: application.name}, $scope.application, function () {
Application.update({ realm : realm.realm, application: application.id}, $scope.application, function () {
$scope.notBefore = "None";
Notifications.success('Not Before cleared for application.');
refresh();
@ -467,13 +525,13 @@ module.controller('ApplicationRevocationCtrl', function($scope, realm, applicati
}
$scope.setNotBeforeNow = function() {
$scope.application.notBefore = new Date().getTime()/1000;
Application.update({ realm : realm.realm, application: $scope.application.name}, $scope.application, function () {
Application.update({ realm : realm.realm, application: $scope.application.id}, $scope.application, function () {
Notifications.success('Not Before cleared for application.');
refresh();
});
}
$scope.pushRevocation = function() {
ApplicationPushRevocation.save({realm : realm.realm, application: $scope.application.name}, function () {
ApplicationPushRevocation.save({realm : realm.realm, application: $scope.application.id}, function () {
Notifications.success('Push sent for application.');
});
}

View file

@ -224,9 +224,9 @@ module.controller('OAuthClientScopeMappingCtrl', function($scope, $http, realm,
function updateAppRoles() {
if ($scope.targetApp) {
console.debug($scope.targetApp.name);
$scope.applicationRoles = OAuthClientAvailableApplicationScopeMapping.query({realm : realm.realm, oauth : oauth.name, targetApp : $scope.targetApp.name});
$scope.applicationMappings = OAuthClientApplicationScopeMapping.query({realm : realm.realm, oauth : oauth.name, targetApp : $scope.targetApp.name});
$scope.applicationComposite = OAuthClientCompositeApplicationScopeMapping.query({realm : realm.realm, oauth : oauth.name, targetApp : $scope.targetApp.name});
$scope.applicationRoles = OAuthClientAvailableApplicationScopeMapping.query({realm : realm.realm, oauth : oauth.name, targetApp : $scope.targetApp.id});
$scope.applicationMappings = OAuthClientApplicationScopeMapping.query({realm : realm.realm, oauth : oauth.name, targetApp : $scope.targetApp.id});
$scope.applicationComposite = OAuthClientCompositeApplicationScopeMapping.query({realm : realm.realm, oauth : oauth.name, targetApp : $scope.targetApp.id});
} else {
$scope.applicationRoles = null;
$scope.applicationMappings = null;
@ -256,7 +256,7 @@ module.controller('OAuthClientScopeMappingCtrl', function($scope, $http, realm,
};
$scope.addApplicationRole = function() {
$http.post(authUrl + '/admin/realms/' + realm.realm + '/oauth-clients/' + oauth.name + '/scope-mappings/applications/' + $scope.targetApp.name,
$http.post(authUrl + '/admin/realms/' + realm.realm + '/oauth-clients/' + oauth.name + '/scope-mappings/applications-by-id/' + $scope.targetApp.id,
$scope.selectedApplicationRoles).success(function () {
updateAppRoles();
Notifications.success("Scope mappings updated.");
@ -265,7 +265,7 @@ module.controller('OAuthClientScopeMappingCtrl', function($scope, $http, realm,
};
$scope.deleteApplicationRole = function() {
$http.delete(authUrl + '/admin/realms/' + realm.realm + '/oauth-clients/' + oauth.name + '/scope-mappings/applications/' + $scope.targetApp.name,
$http.delete(authUrl + '/admin/realms/' + realm.realm + '/oauth-clients/' + oauth.name + '/scope-mappings/applications-by-id/' + $scope.targetApp.id,
{data : $scope.selectedApplicationMappings, headers : {"content-type" : "application/json"}}).success(function () {
updateAppRoles();
Notifications.success("Scope mappings updated.");

View file

@ -541,7 +541,7 @@ module.controller('RealmDefaultRolesCtrl', function ($scope, Realm, realm, appli
// Populate available roles for selected application
if ($scope.application) {
var appDefaultRoles = ApplicationRole.query({realm: $scope.realm.realm, application: $scope.application.name}, function () {
var appDefaultRoles = ApplicationRole.query({realm: $scope.realm.realm, application: $scope.application.id}, function () {
if (!$scope.application.hasOwnProperty('defaultRoles') || $scope.application.defaultRoles === null) {
$scope.application.defaultRoles = [];
@ -582,7 +582,7 @@ module.controller('RealmDefaultRolesCtrl', function ($scope, Realm, realm, appli
// Update/save the selected application with new default roles.
Application.update({
realm: $scope.realm.realm,
application: $scope.application.name
application: $scope.application.id
}, $scope.application, function () {
Notifications.success("Your changes have been saved to the application.");
});
@ -606,7 +606,7 @@ module.controller('RealmDefaultRolesCtrl', function ($scope, Realm, realm, appli
// Update/save the selected application with new default roles.
Application.update({
realm: $scope.realm.realm,
application: $scope.application.name
application: $scope.application.id
}, $scope.application, function () {
Notifications.success("Your changes have been saved to the application.");
});

View file

@ -28,9 +28,9 @@ module.controller('UserRoleMappingCtrl', function($scope, $http, realm, user, ap
$scope.selectRealmRoles = [];
if ($scope.application) {
console.log('load available');
$scope.applicationComposite = CompositeApplicationRoleMapping.query({realm : realm.realm, userId : user.username, application : $scope.application.name});
$scope.applicationRoles = AvailableApplicationRoleMapping.query({realm : realm.realm, userId : user.username, application : $scope.application.name});
$scope.applicationMappings = ApplicationRoleMapping.query({realm : realm.realm, userId : user.username, application : $scope.application.name});
$scope.applicationComposite = CompositeApplicationRoleMapping.query({realm : realm.realm, userId : user.username, application : $scope.application.id});
$scope.applicationRoles = AvailableApplicationRoleMapping.query({realm : realm.realm, userId : user.username, application : $scope.application.id});
$scope.applicationMappings = ApplicationRoleMapping.query({realm : realm.realm, userId : user.username, application : $scope.application.id});
$scope.selectedApplicationRoles = [];
$scope.selectedApplicationMappings = [];
}
@ -49,9 +49,9 @@ module.controller('UserRoleMappingCtrl', function($scope, $http, realm, user, ap
$scope.selectRealmRoles = [];
if ($scope.application) {
console.log('load available');
$scope.applicationComposite = CompositeApplicationRoleMapping.query({realm : realm.realm, userId : user.username, application : $scope.application.name});
$scope.applicationRoles = AvailableApplicationRoleMapping.query({realm : realm.realm, userId : user.username, application : $scope.application.name});
$scope.applicationMappings = ApplicationRoleMapping.query({realm : realm.realm, userId : user.username, application : $scope.application.name});
$scope.applicationComposite = CompositeApplicationRoleMapping.query({realm : realm.realm, userId : user.username, application : $scope.application.id});
$scope.applicationRoles = AvailableApplicationRoleMapping.query({realm : realm.realm, userId : user.username, application : $scope.application.id});
$scope.applicationMappings = ApplicationRoleMapping.query({realm : realm.realm, userId : user.username, application : $scope.application.id});
$scope.selectedApplicationRoles = [];
$scope.selectedApplicationMappings = [];
}
@ -60,11 +60,11 @@ module.controller('UserRoleMappingCtrl', function($scope, $http, realm, user, ap
};
$scope.addApplicationRole = function() {
$http.post(authUrl + '/admin/realms/' + realm.realm + '/users/' + user.username + '/role-mappings/applications/' + $scope.application.name,
$http.post(authUrl + '/admin/realms/' + realm.realm + '/users/' + user.username + '/role-mappings/applications-by-id/' + $scope.application.id,
$scope.selectedApplicationRoles).success(function() {
$scope.applicationMappings = ApplicationRoleMapping.query({realm : realm.realm, userId : user.username, application : $scope.application.name});
$scope.applicationRoles = AvailableApplicationRoleMapping.query({realm : realm.realm, userId : user.username, application : $scope.application.name});
$scope.applicationComposite = CompositeApplicationRoleMapping.query({realm : realm.realm, userId : user.username, application : $scope.application.name});
$scope.applicationMappings = ApplicationRoleMapping.query({realm : realm.realm, userId : user.username, application : $scope.application.id});
$scope.applicationRoles = AvailableApplicationRoleMapping.query({realm : realm.realm, userId : user.username, application : $scope.application.id});
$scope.applicationComposite = CompositeApplicationRoleMapping.query({realm : realm.realm, userId : user.username, application : $scope.application.id});
$scope.selectedApplicationRoles = [];
$scope.selectedApplicationMappings = [];
Notifications.success("Role mappings updated.");
@ -72,11 +72,11 @@ module.controller('UserRoleMappingCtrl', function($scope, $http, realm, user, ap
};
$scope.deleteApplicationRole = function() {
$http.delete(authUrl + '/admin/realms/' + realm.realm + '/users/' + user.username + '/role-mappings/applications/' + $scope.application.name,
$http.delete(authUrl + '/admin/realms/' + realm.realm + '/users/' + user.username + '/role-mappings/applications-by-id/' + $scope.application.id,
{data : $scope.selectedApplicationMappings, headers : {"content-type" : "application/json"}}).success(function() {
$scope.applicationMappings = ApplicationRoleMapping.query({realm : realm.realm, userId : user.username, application : $scope.application.name});
$scope.applicationRoles = AvailableApplicationRoleMapping.query({realm : realm.realm, userId : user.username, application : $scope.application.name});
$scope.applicationComposite = CompositeApplicationRoleMapping.query({realm : realm.realm, userId : user.username, application : $scope.application.name});
$scope.applicationMappings = ApplicationRoleMapping.query({realm : realm.realm, userId : user.username, application : $scope.application.id});
$scope.applicationRoles = AvailableApplicationRoleMapping.query({realm : realm.realm, userId : user.username, application : $scope.application.id});
$scope.applicationComposite = CompositeApplicationRoleMapping.query({realm : realm.realm, userId : user.username, application : $scope.application.id});
$scope.selectedApplicationRoles = [];
$scope.selectedApplicationMappings = [];
Notifications.success("Role mappings updated.");
@ -88,9 +88,9 @@ module.controller('UserRoleMappingCtrl', function($scope, $http, realm, user, ap
console.log('changeApplication');
if ($scope.application) {
console.log('load available');
$scope.applicationComposite = CompositeApplicationRoleMapping.query({realm : realm.realm, userId : user.username, application : $scope.application.name});
$scope.applicationRoles = AvailableApplicationRoleMapping.query({realm : realm.realm, userId : user.username, application : $scope.application.name});
$scope.applicationMappings = ApplicationRoleMapping.query({realm : realm.realm, userId : user.username, application : $scope.application.name});
$scope.applicationComposite = CompositeApplicationRoleMapping.query({realm : realm.realm, userId : user.username, application : $scope.application.id});
$scope.applicationRoles = AvailableApplicationRoleMapping.query({realm : realm.realm, userId : user.username, application : $scope.application.id});
$scope.applicationMappings = ApplicationRoleMapping.query({realm : realm.realm, userId : user.username, application : $scope.application.id});
} else {
$scope.applicationRoles = null;
$scope.applicationMappings = null;

View file

@ -72,7 +72,7 @@ module.factory('RealmSessionStatsLoader', function(Loader, RealmSessionStats, $r
});
module.factory('RealmApplicationSessionStatsLoader', function(Loader, RealmApplicationSessionStats, $route, $q) {
return Loader.get(RealmApplicationSessionStats, function() {
return Loader.query(RealmApplicationSessionStats, function() {
return {
realm : $route.current.params.realm
}
@ -213,6 +213,8 @@ module.factory('ApplicationRoleListLoader', function(Loader, ApplicationRole, $r
module.factory('ApplicationLoader', function(Loader, Application, $route, $q) {
return Loader.get(Application, function() {
console.log('application loader****');
console.log($route.current.params.application);
return {
realm : $route.current.params.realm,
application : $route.current.params.application

View file

@ -311,7 +311,7 @@ module.factory('AvailableRealmRoleMapping', function($resource) {
module.factory('ApplicationRoleMapping', function($resource) {
return $resource(authUrl + '/admin/realms/:realm/users/:userId/role-mappings/applications/:application', {
return $resource(authUrl + '/admin/realms/:realm/users/:userId/role-mappings/applications-by-id/:application', {
realm : '@realm',
userId : '@userId',
application : "@application"
@ -319,7 +319,7 @@ module.factory('ApplicationRoleMapping', function($resource) {
});
module.factory('AvailableApplicationRoleMapping', function($resource) {
return $resource(authUrl + '/admin/realms/:realm/users/:userId/role-mappings/applications/:application/available', {
return $resource(authUrl + '/admin/realms/:realm/users/:userId/role-mappings/applications-by-id/:application/available', {
realm : '@realm',
userId : '@userId',
application : "@application"
@ -327,7 +327,7 @@ module.factory('AvailableApplicationRoleMapping', function($resource) {
});
module.factory('CompositeApplicationRoleMapping', function($resource) {
return $resource(authUrl + '/admin/realms/:realm/users/:userId/role-mappings/applications/:application/composite', {
return $resource(authUrl + '/admin/realms/:realm/users/:userId/role-mappings/applications-by-id/:application/composite', {
realm : '@realm',
userId : '@userId',
application : "@application"
@ -335,28 +335,28 @@ module.factory('CompositeApplicationRoleMapping', function($resource) {
});
module.factory('ApplicationRealmScopeMapping', function($resource) {
return $resource(authUrl + '/admin/realms/:realm/applications/:application/scope-mappings/realm', {
return $resource(authUrl + '/admin/realms/:realm/applications-by-id/:application/scope-mappings/realm', {
realm : '@realm',
application : '@application'
});
});
module.factory('ApplicationAvailableRealmScopeMapping', function($resource) {
return $resource(authUrl + '/admin/realms/:realm/applications/:application/scope-mappings/realm/available', {
return $resource(authUrl + '/admin/realms/:realm/applications-by-id/:application/scope-mappings/realm/available', {
realm : '@realm',
application : '@application'
});
});
module.factory('ApplicationCompositeRealmScopeMapping', function($resource) {
return $resource(authUrl + '/admin/realms/:realm/applications/:application/scope-mappings/realm/composite', {
return $resource(authUrl + '/admin/realms/:realm/applications-by-id/:application/scope-mappings/realm/composite', {
realm : '@realm',
application : '@application'
});
});
module.factory('ApplicationApplicationScopeMapping', function($resource) {
return $resource(authUrl + '/admin/realms/:realm/applications/:application/scope-mappings/applications/:targetApp', {
return $resource(authUrl + '/admin/realms/:realm/applications-by-id/:application/scope-mappings/applications-by-id/:targetApp', {
realm : '@realm',
application : '@application',
targetApp : '@targetApp'
@ -364,7 +364,7 @@ module.factory('ApplicationApplicationScopeMapping', function($resource) {
});
module.factory('ApplicationAvailableApplicationScopeMapping', function($resource) {
return $resource(authUrl + '/admin/realms/:realm/applications/:application/scope-mappings/applications/:targetApp/available', {
return $resource(authUrl + '/admin/realms/:realm/applications-by-id/:application/scope-mappings/applications-by-id/:targetApp/available', {
realm : '@realm',
application : '@application',
targetApp : '@targetApp'
@ -372,7 +372,7 @@ module.factory('ApplicationAvailableApplicationScopeMapping', function($resource
});
module.factory('ApplicationCompositeApplicationScopeMapping', function($resource) {
return $resource(authUrl + '/admin/realms/:realm/applications/:application/scope-mappings/applications/:targetApp/composite', {
return $resource(authUrl + '/admin/realms/:realm/applications-by-id/:application/scope-mappings/applications-by-id/:targetApp/composite', {
realm : '@realm',
application : '@application',
targetApp : '@targetApp'
@ -407,14 +407,14 @@ module.factory('RealmSessionStats', function($resource) {
});
module.factory('RealmApplicationSessionStats', function($resource) {
return $resource(authUrl + '/admin/realms/:realm/application-session-stats', {
return $resource(authUrl + '/admin/realms/:realm/application-by-id-session-stats', {
realm : '@realm'
});
});
module.factory('RoleApplicationComposites', function($resource) {
return $resource(authUrl + '/admin/realms/:realm/roles-by-id/:role/composites/applications/:application', {
return $resource(authUrl + '/admin/realms/:realm/roles-by-id/:role/composites/applications-by-id/:application', {
realm : '@realm',
role : '@role',
application : "@application"
@ -468,7 +468,6 @@ function roleControl($scope, realm, role, roles, applications,
$scope.selectedApplicationMappings = [];
$scope.applicationMappings = [];
console.log('remove self');
for (var j = 0; j < $scope.realmRoles.length; j++) {
if ($scope.realmRoles[j].id == role.id) {
var realmRole = $scope.realmRoles[j];
@ -561,8 +560,8 @@ function roleControl($scope, realm, role, roles, applications,
$scope.changeApplication = function() {
$scope.applicationRoles = ApplicationRole.query({realm : realm.realm, application : $scope.compositeApp.name}, function() {
$scope.applicationMappings = RoleApplicationComposites.query({realm : realm.realm, role : role.id, application : $scope.compositeApp.name}, function(){
$scope.applicationRoles = ApplicationRole.query({realm : realm.realm, application : $scope.compositeApp.id}, function() {
$scope.applicationMappings = RoleApplicationComposites.query({realm : realm.realm, role : role.id, application : $scope.compositeApp.id}, function(){
for (var i = 0; i < $scope.applicationMappings.length; i++) {
var role = $scope.applicationMappings[i];
for (var j = 0; j < $scope.applicationRoles.length; j++) {
@ -618,7 +617,7 @@ module.factory('RoleById', function($resource) {
});
module.factory('ApplicationRole', function($resource) {
return $resource(authUrl + '/admin/realms/:realm/applications/:application/roles/:role', {
return $resource(authUrl + '/admin/realms/:realm/applications-by-id/:application/roles/:role', {
realm : '@realm',
application : "@application",
role : '@role'
@ -630,7 +629,7 @@ module.factory('ApplicationRole', function($resource) {
});
module.factory('ApplicationClaims', function($resource) {
return $resource(authUrl + '/admin/realms/:realm/applications/:application/claims', {
return $resource(authUrl + '/admin/realms/:realm/applications-by-id/:application/claims', {
realm : '@realm',
application : "@application"
}, {
@ -641,41 +640,41 @@ module.factory('ApplicationClaims', function($resource) {
});
module.factory('ApplicationSessionStats', function($resource) {
return $resource(authUrl + '/admin/realms/:realm/applications/:application/session-stats', {
return $resource(authUrl + '/admin/realms/:realm/applications-by-id/:application/session-stats', {
realm : '@realm',
application : "@application"
});
});
module.factory('ApplicationSessionStatsWithUsers', function($resource) {
return $resource(authUrl + '/admin/realms/:realm/applications/:application/session-stats?users=true', {
return $resource(authUrl + '/admin/realms/:realm/applications-by-id/:application/session-stats?users=true', {
realm : '@realm',
application : "@application"
});
});
module.factory('ApplicationSessionCount', function($resource) {
return $resource(authUrl + '/admin/realms/:realm/applications/:application/session-count', {
return $resource(authUrl + '/admin/realms/:realm/applications-by-id/:application/session-count', {
realm : '@realm',
application : "@application"
});
});
module.factory('ApplicationUserSessions', function($resource) {
return $resource(authUrl + '/admin/realms/:realm/applications/:application/user-sessions', {
return $resource(authUrl + '/admin/realms/:realm/applications-by-id/:application/user-sessions', {
realm : '@realm',
application : "@application"
});
});
module.factory('ApplicationLogoutAll', function($resource) {
return $resource(authUrl + '/admin/realms/:realm/applications/:application/logout-all', {
return $resource(authUrl + '/admin/realms/:realm/applications-by-id/:application/logout-all', {
realm : '@realm',
application : "@application"
});
});
module.factory('ApplicationLogoutUser', function($resource) {
return $resource(authUrl + '/admin/realms/:realm/applications/:application/logout-user/:user', {
return $resource(authUrl + '/admin/realms/:realm/applications-by-id/:application/logout-user/:user', {
realm : '@realm',
application : "@application",
user : "@user"
@ -688,7 +687,7 @@ module.factory('RealmLogoutAll', function($resource) {
});
module.factory('ApplicationPushRevocation', function($resource) {
return $resource(authUrl + '/admin/realms/:realm/applications/:application/push-revocation', {
return $resource(authUrl + '/admin/realms/:realm/applications-by-id/:application/push-revocation', {
realm : '@realm',
application : "@application"
});
@ -697,7 +696,7 @@ module.factory('ApplicationPushRevocation', function($resource) {
module.factory('Application', function($resource) {
return $resource(authUrl + '/admin/realms/:realm/applications/:application', {
return $resource(authUrl + '/admin/realms/:realm/applications-by-id/:application', {
realm : '@realm',
application : '@application'
}, {
@ -708,7 +707,7 @@ module.factory('Application', function($resource) {
});
module.factory('ApplicationInstallation', function($resource) {
var url = authUrl + '/admin/realms/:realm/applications/:application/installation/json';
var url = authUrl + '/admin/realms/:realm/applications-by-id/:application/installation/json';
return {
url : function(parameters)
{
@ -717,7 +716,7 @@ module.factory('ApplicationInstallation', function($resource) {
}
});
module.factory('ApplicationInstallationJBoss', function($resource) {
var url = authUrl + '/admin/realms/:realm/applications/:application/installation/jboss';
var url = authUrl + '/admin/realms/:realm/applications-by-id/:application/installation/jboss';
return {
url : function(parameters)
{
@ -727,7 +726,7 @@ module.factory('ApplicationInstallationJBoss', function($resource) {
});
module.factory('ApplicationCredentials', function($resource) {
return $resource(authUrl + '/admin/realms/:realm/applications/:application/client-secret', {
return $resource(authUrl + '/admin/realms/:realm/applications-by-id/:application/client-secret', {
realm : '@realm',
application : '@application'
}, {
@ -738,7 +737,7 @@ module.factory('ApplicationCredentials', function($resource) {
});
module.factory('ApplicationOrigins', function($resource) {
return $resource(authUrl + '/admin/realms/:realm/applications/:application/allowed-origins', {
return $resource(authUrl + '/admin/realms/:realm/applications-by-id/:application/allowed-origins', {
realm : '@realm',
application : '@application'
}, {
@ -806,7 +805,7 @@ module.factory('OAuthClientAvailableRealmScopeMapping', function($resource) {
});
module.factory('OAuthClientApplicationScopeMapping', function($resource) {
return $resource(authUrl + '/admin/realms/:realm/oauth-clients/:oauth/scope-mappings/applications/:targetApp', {
return $resource(authUrl + '/admin/realms/:realm/oauth-clients/:oauth/scope-mappings/applications-by-id/:targetApp', {
realm : '@realm',
oauth : '@oauth',
targetApp : '@targetApp'
@ -814,7 +813,7 @@ module.factory('OAuthClientApplicationScopeMapping', function($resource) {
});
module.factory('OAuthClientCompositeApplicationScopeMapping', function($resource) {
return $resource(authUrl + '/admin/realms/:realm/oauth-clients/:oauth/scope-mappings/applications/:targetApp/composite', {
return $resource(authUrl + '/admin/realms/:realm/oauth-clients/:oauth/scope-mappings/applications-by-id/:targetApp/composite', {
realm : '@realm',
oauth : '@oauth',
targetApp : '@targetApp'
@ -822,7 +821,7 @@ module.factory('OAuthClientCompositeApplicationScopeMapping', function($resource
});
module.factory('OAuthClientAvailableApplicationScopeMapping', function($resource) {
return $resource(authUrl + '/admin/realms/:realm/oauth-clients/:oauth/scope-mappings/applications/:targetApp/available', {
return $resource(authUrl + '/admin/realms/:realm/oauth-clients/:oauth/scope-mappings/applications-by-id/:targetApp/available', {
realm : '@realm',
oauth : '@oauth',
targetApp : '@targetApp'

View file

@ -4,7 +4,7 @@
<div id="content">
<ol class="breadcrumb" data-ng-hide="create">
<li><a href="#/realms/{{realm.realm}}/applications">Applications</a></li>
<li><a href="#/realms/{{realm.realm}}/applications/{{application.name}}">{{application.name}}</a></li>
<li><a href="#/realms/{{realm.realm}}/applications/{{application.id}}">{{application.name}}</a></li>
<li class="active">Claims</li>
</ol>
<h2 data-ng-hide="create"><span>{{application.name}}</span> Allowed Claims <span tooltip-placement="right" tooltip="Allows you to restrict which claim information is stored in the access token generated for the application." class="fa fa-info-circle"></span></h2>

View file

@ -4,7 +4,7 @@
<div id="content">
<ol class="breadcrumb" data-ng-hide="create">
<li><a href="#/realms/{{realm.realm}}/applications">Applications</a></li>
<li><a href="#/realms/{{realm.realm}}/applications/{{application.name}}">{{application.name}}</a></li>
<li><a href="#/realms/{{realm.realm}}/applications/{{application.id}}">{{application.name}}</a></li>
<li class="active">Claims</li>
</ol>
<h2 data-ng-hide="create"><span>{{application.name}}</span> Credentials</h2>

View file

@ -4,7 +4,7 @@
<div id="content">
<ol class="breadcrumb" data-ng-hide="create">
<li><a href="#/realms/{{realm.realm}}/applications">Applications</a></li>
<li><a href="#/realms/{{realm.realm}}/applications/{{application.name}}">{{application.name}}</a></li>
<li><a href="#/realms/{{realm.realm}}/applications/{{application.id}}">{{application.name}}</a></li>
<li class="active">Settings</li>
</ol>
<ol class="breadcrumb" data-ng-show="create">
@ -31,6 +31,19 @@
<span tooltip-placement="right" tooltip="Disabled applications cannot initiate a login or have obtain access tokens." class="fa fa-info-circle"></span>
</div>
<div class="form-group">
<label class="col-sm-2 control-label" for="protocol">Client Protocol</label>
<div class="col-sm-6">
<div class="select-kc">
<select id="protocol"
ng-change="changeProtocol()"
ng-model="protocol"
ng-options="aProtocol for aProtocol in protocols">
</select>
</div>
</div>
<span tooltip-placement="right" tooltip="'Confidential' applications require a secret to initiate login protocol. 'Public' clients do not require a secret. 'Bearer-only' applications are web services that never initiate a login." class="fa fa-info-circle"></span>
</div>
<div class="form-group" data-ng-show="protocol == 'openid-connect'">
<label class="col-sm-2 control-label" for="accessType">Access Type</label>
<div class="col-sm-6">
<div class="select-kc">
@ -43,6 +56,28 @@
</div>
<span tooltip-placement="right" tooltip="'Confidential' applications require a secret to initiate login protocol. 'Public' clients do not require a secret. 'Bearer-only' applications are web services that never initiate a login." class="fa fa-info-circle"></span>
</div>
<div class="form-group clearfix block" data-ng-show="protocol == 'saml'">
<label class="col-sm-2 control-label" for="samlServerSignature">Server Signatures</label>
<div class="col-sm-6">
<input ng-model="samlServerSignature" ng-click="switchChange()" name="samlServerSignature" id="samlServerSignature" onoffswitch />
</div>
<span tooltip-placement="right" tooltip="Should server sent SAML requests and responses be signed by the realm?" class="fa fa-info-circle"></span>
</div>
<div class="form-group clearfix block" data-ng-show="protocol == 'saml'">
<label class="col-sm-2 control-label" for="samlServerEncrypt">Server Encryption</label>
<div class="col-sm-6">
<input ng-model="samlServerEncrypt" ng-click="switchChange()" name="samlServerEncrypt" id="samlServerEncrypt" onoffswitch />
</div>
<span tooltip-placement="right" tooltip="Should server sent SAML requests and responses be encrypted by the realm?" class="fa fa-info-circle"></span>
</div>
<div class="form-group clearfix block" data-ng-show="protocol == 'saml'">
<label class="col-sm-2 control-label" for="samlClientSignature">Client Signatures</label>
<div class="col-sm-6">
<input ng-model="samlClientSignature" ng-click="switchChange()" name="samlClientSignature" id="samlClientSignature" onoffswitch />
</div>
<span tooltip-placement="right" tooltip="Will the client sign their saml requests and responses? And should they be validated?" class="fa fa-info-circle"></span>
</div>
<div class="form-group" data-ng-show="!application.bearerOnly">
<label class="col-sm-2 control-label" for="newRedirectUri">Redirect URI <span class="required" data-ng-show="create">*</span></label>
<div class="col-sm-6 multiple" ng-repeat="redirectUri in application.redirectUris">

View file

@ -5,7 +5,7 @@
<div id="content">
<ol class="breadcrumb" data-ng-hide="create">
<li><a href="#/realms/{{realm.realm}}/applications">Applications</a></li>
<li><a href="#/realms/{{realm.realm}}/applications/{{application.name}}">{{application.name}}</a></li>
<li><a href="#/realms/{{realm.realm}}/applications/{{application.id}}">{{application.name}}</a></li>
<li class="active">Installation</li>
</ol>
<h2><span>{{application.name}}</span> Adapter Installation <span tooltip-placement="right" tooltip="Helper utility for generating various client adapter configuration formats which you can download or cut and paste to configure your client applications." class="fa fa-info-circle"></span></h2>

View file

@ -43,7 +43,7 @@
</tfoot>-->
<tbody>
<tr ng-repeat="app in applications | filter:search">
<td><a href="#/realms/{{realm.realm}}/applications/{{app.name}}">{{app.name}}</a></td>
<td><a href="#/realms/{{realm.realm}}/applications/{{app.id}}">{{app.name}}</a></td>
<td>{{app.enabled}}</td>
<td ng-class="{'text-muted': !app.baseUrl}">
<a href="{{app.baseUrl}}" data-ng-show="app.baseUrl">{{app.baseUrl}}</a>

View file

@ -4,7 +4,7 @@
<div id="content">
<ol class="breadcrumb">
<li><a href="#/realms/{{realm.realm}}/applications">Applications</a></li>
<li><a href="#/realms/{{realm.realm}}/applications/{{application.name}}">{{application.name}}</a></li>
<li><a href="#/realms/{{realm.realm}}/applications/{{application.id}}">{{application.name}}</a></li>
<li class="active">Revocation</li>
</ol>
<h2 data-ng-hide="create"><span>{{application.name}}</span> Revocation Policies</h2>

View file

@ -4,15 +4,15 @@
<div id="content">
<ol class="breadcrumb" data-ng-show="create">
<li><a href="#/realms/{{realm.realm}}/applications">Applications</a></li>
<li><a href="#/realms/{{realm.realm}}/applications/{{application.name}}">{{application.name}}</a></li>
<li><a href="#/realms/{{realm.realm}}/applications/{{application.name}}/roles">Roles</a></li>
<li><a href="#/realms/{{realm.realm}}/applications/{{application.id}}">{{application.name}}</a></li>
<li><a href="#/realms/{{realm.realm}}/applications/{{application.id}}/roles">Roles</a></li>
<li class="active">Add role</li>
</ol>
<ol class="breadcrumb" data-ng-hide="create">
<li><a href="#/realms/{{realm.realm}}/applications">Applications</a></li>
<li><a href="#/realms/{{realm.realm}}/applications/{{application.name}}">{{application.name}}</a></li>
<li><a href="#/realms/{{realm.realm}}/applications/{{application.name}}/roles">Roles</a></li>
<li><a href="#/realms/{{realm.realm}}/applications/{{application.id}}">{{application.name}}</a></li>
<li><a href="#/realms/{{realm.realm}}/applications/{{application.id}}/roles">Roles</a></li>
<li class="active">{{role.name}}</li>
</ol>

View file

@ -5,7 +5,7 @@
<div id="content">
<ol class="breadcrumb" data-ng-hide="create">
<li><a href="#/realms/{{realm.realm}}/applications">Applications</a></li>
<li><a href="#/realms/{{realm.realm}}/applications/{{application.name}}">{{application.name}}</a></li>
<li><a href="#/realms/{{realm.realm}}/applications/{{application.id}}">{{application.name}}</a></li>
<li class="active">Roles</li>
</ol>
<h2><span>{{application.name}}</span> Application Roles</h2>
@ -14,7 +14,7 @@
<tr>
<th class="kc-table-actions" colspan="3" data-ng-show="access.manageApplications">
<div class="pull-right">
<a class="btn btn-primary" href="#/create/role/{{realm.realm}}/applications/{{application.name}}">Add Role</a>
<a class="btn btn-primary" href="#/create/role/{{realm.realm}}/applications/{{application.id}}">Add Role</a>
<!-- <button class="remove disabled">Remove</button> -->
</div>
</th>
@ -52,7 +52,7 @@
-->
<tbody>
<tr ng-repeat="role in roles">
<td><a href="#/realms/{{realm.realm}}/applications/{{application.name}}/roles/{{role.name}}">{{role.name}}</a></td>
<td><a href="#/realms/{{realm.realm}}/applications/{{application.id}}/roles/{{role.name}}">{{role.name}}</a></td>
<td>{{role.composite}}</td>
<td>{{role.description}}</td>
</tr>

View file

@ -5,7 +5,7 @@
<div id="content">
<ol class="breadcrumb" data-ng-hide="create">
<li><a href="#/realms/{{realm.realm}}/applications">Applications</a></li>
<li><a href="#/realms/{{realm.realm}}/applications/{{application.name}}">{{application.name}}</a></li>
<li><a href="#/realms/{{realm.realm}}/applications/{{application.id}}">{{application.name}}</a></li>
<li class="active">Scope</li>
</ol>
<h2><span>{{application.name}}</span> Scope Mappings <span tooltip-placement="right" tooltip="Scope mappings allow you to restrict which user role mappings are included within the access token requested by the application." class="fa fa-info-circle"></span></h2>

View file

@ -4,7 +4,7 @@
<div id="content">
<ol class="breadcrumb" data-ng-hide="create">
<li><a href="#/realms/{{realm.realm}}/applications">Applications</a></li>
<li><a href="#/realms/{{realm.realm}}/applications/{{application.name}}">{{application.name}}</a></li>
<li><a href="#/realms/{{realm.realm}}/applications/{{application.id}}">{{application.name}}</a></li>
<li class="active">Application Sessions</li>
</ol>
<h2><span>{{application.name}}</span> Active Sessions <span tooltip-placement="right" tooltip="View active sessions for this application. Allows you to see which users are active and when they logged in." class="fa fa-info-circle"></span></h2>

View file

@ -23,9 +23,9 @@
</tr>
</thead>
<tbody>
<tr data-ng-repeat="(application, data) in stats">
<td><a href="#/realms/{{realm.realm}}/applications/{{application}}/sessions">{{application}}</a></td>
<td>{{data}}</td>
<tr data-ng-repeat="data in stats">
<td><a href="#/realms/{{realm.realm}}/applications/{{data.id}}/sessions">{{data.name}}</a></td>
<td>{{data.active}}</td>
</tr>
</tbody>
</table>

View file

@ -38,8 +38,8 @@
<td>{{session.start | date:'medium'}}</td>
<td>{{session.lastAccess | date:'medium'}}</td>
<td>
<div data-ng-repeat="app in session.applications">
<a href="#/realms/{{realm.realm}}/applications/{{app}}/sessions">{{app}}</a>
<div data-ng-repeat="(id, name) in session.applications">
<a href="#/realms/{{realm.realm}}/applications/{{id}}">{{name}}</a>
</div>
</ul>
</td>

View file

@ -1,10 +1,10 @@
<ul class="nav nav-tabs nav-tabs-pf" data-ng-show="!create">
<li ng-class="{active: !path[4]}"><a href="#/realms/{{realm.realm}}/applications/{{application.name}}">Settings</a></li>
<li ng-class="{active: path[4] == 'credentials'}" data-ng-show="!application.bearerOnly && !application.publicClient"><a href="#/realms/{{realm.realm}}/applications/{{application.name}}/credentials">Credentials</a></li>
<li ng-class="{active: path[4] == 'roles'}"><a href="#/realms/{{realm.realm}}/applications/{{application.name}}/roles">Roles</a></li>
<li ng-class="{active: path[4] == 'claims'}" data-ng-show="!application.bearerOnly"><a href="#/realms/{{realm.realm}}/applications/{{application.name}}/claims">Claims</a></li>
<li ng-class="{active: path[4] == 'scope-mappings'}" data-ng-show="!application.bearerOnly"><a href="#/realms/{{realm.realm}}/applications/{{application.name}}/scope-mappings">Scope</a></li>
<li ng-class="{active: path[4] == 'revocation'}"><a href="#/realms/{{realm.realm}}/applications/{{application.name}}/revocation">Revocation</a></li>
<li ng-class="{active: path[4] == 'sessions'}" data-ng-show="!application.bearerOnly"><a href="#/realms/{{realm.realm}}/applications/{{application.name}}/sessions">Sessions</a></li>
<li ng-class="{active: path[4] == 'installation'}"><a href="#/realms/{{realm.realm}}/applications/{{application.name}}/installation">Installation</a></li>
<li ng-class="{active: !path[4]}"><a href="#/realms/{{realm.realm}}/applications/{{application.id}}">Settings</a></li>
<li ng-class="{active: path[4] == 'credentials'}" data-ng-show="!application.bearerOnly && !application.publicClient && application.protocol != 'saml'"><a href="#/realms/{{realm.realm}}/applications/{{application.id}}/credentials">Credentials</a></li>
<li ng-class="{active: path[4] == 'roles'}"><a href="#/realms/{{realm.realm}}/applications/{{application.id}}/roles">Roles</a></li>
<li ng-class="{active: path[4] == 'claims'}" data-ng-show="!application.bearerOnly"><a href="#/realms/{{realm.realm}}/applications/{{application.id}}/claims">Claims</a></li>
<li ng-class="{active: path[4] == 'scope-mappings'}" data-ng-show="!application.bearerOnly"><a href="#/realms/{{realm.realm}}/applications/{{application.id}}/scope-mappings">Scope</a></li>
<li ng-class="{active: path[4] == 'revocation'}"><a href="#/realms/{{realm.realm}}/applications/{{application.id}}/revocation">Revocation</a></li>
<li ng-class="{active: path[4] == 'sessions'}" data-ng-show="!application.bearerOnly"><a href="#/realms/{{realm.realm}}/applications/{{application.id}}/sessions">Sessions</a></li>
<li ng-class="{active: path[4] == 'installation'}"><a href="#/realms/{{realm.realm}}/applications/{{application.id}}/installation">Installation</a></li>
</ul>

View file

@ -1,5 +1,6 @@
package org.keycloak.models;
import java.util.Map;
import java.util.Set;
/**
@ -53,6 +54,15 @@ public interface ClientModel {
boolean isFullScopeAllowed();
void setFullScopeAllowed(boolean value);
String getProtocol();
void setProtocol(String protocol);
void setAttribute(String name, String value);
void removeAttribute(String name);
String getAttribute(String name);
Map<String, String> getAttributes();
boolean isPublicClient();
void setPublicClient(boolean flag);

View file

@ -1,7 +1,9 @@
package org.keycloak.models.entities;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
* @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
@ -11,12 +13,15 @@ public class ClientEntity extends AbstractIdentifiableEntity {
private String name;
private boolean enabled;
private String secret;
private String protocol;
private long allowedClaimsMask;
private int notBefore;
private boolean publicClient;
private boolean fullScopeAllowed;
private String realmId;
private Map<String, String> attributes = new HashMap<String, String>();
private List<String> webOrigins = new ArrayList<String>();
private List<String> redirectUris = new ArrayList<String>();
@ -109,4 +114,20 @@ public class ClientEntity extends AbstractIdentifiableEntity {
public void setFullScopeAllowed(boolean fullScopeAllowed) {
this.fullScopeAllowed = fullScopeAllowed;
}
public String getProtocol() {
return protocol;
}
public void setProtocol(String protocol) {
this.protocol = protocol;
}
public Map<String, String> getAttributes() {
return attributes;
}
public void setAttributes(Map<String, String> attributes) {
this.attributes = attributes;
}
}

View file

@ -197,7 +197,7 @@ public class ModelToRepresentation {
for (ClientSessionModel clientSession : session.getClientSessions()) {
ClientModel client = clientSession.getClient();
if (client instanceof ApplicationModel) {
rep.getApplications().add(client.getClientId());
rep.getApplications().put(client.getId(), client.getClientId());
} else if (client instanceof OAuthClientModel) {
rep.getClients().put(client.getId(), client.getClientId());
}
@ -212,6 +212,8 @@ public class ModelToRepresentation {
rep.setEnabled(applicationModel.isEnabled());
rep.setAdminUrl(applicationModel.getManagementUrl());
rep.setPublicClient(applicationModel.isPublicClient());
rep.setProtocol(applicationModel.getProtocol());
rep.setAttributes(applicationModel.getAttributes());
rep.setFullScopeAllowed(applicationModel.isFullScopeAllowed());
rep.setBearerOnly(applicationModel.isBearerOnly());
rep.setSurrogateAuthRequired(applicationModel.isSurrogateAuthRequired());
@ -241,6 +243,8 @@ public class ModelToRepresentation {
rep.setName(model.getClientId());
rep.setEnabled(model.isEnabled());
rep.setPublicClient(model.isPublicClient());
rep.setProtocol(model.getProtocol());
rep.setAttributes(model.getAttributes());
rep.setFullScopeAllowed(model.isFullScopeAllowed());
rep.setDirectGrantsOnly(model.isDirectGrantsOnly());
Set<String> redirectUris = model.getRedirectUris();

View file

@ -368,6 +368,7 @@ public class RepresentationToModel {
applicationModel.setBaseUrl(resourceRep.getBaseUrl());
if (resourceRep.isBearerOnly() != null) applicationModel.setBearerOnly(resourceRep.isBearerOnly());
if (resourceRep.isPublicClient() != null) applicationModel.setPublicClient(resourceRep.isPublicClient());
if (resourceRep.getProtocol() != null) applicationModel.setProtocol(resourceRep.getProtocol());
if (resourceRep.isFullScopeAllowed() != null) applicationModel.setFullScopeAllowed(resourceRep.isFullScopeAllowed());
else applicationModel.setFullScopeAllowed(true);
applicationModel.updateApplication();
@ -381,6 +382,12 @@ public class RepresentationToModel {
KeycloakModelUtils.generateSecret(applicationModel);
}
if (resourceRep.getAttributes() != null) {
for (Map.Entry<String, String> entry : resourceRep.getAttributes().entrySet()) {
applicationModel.setAttribute(entry.getKey(), entry.getValue());
}
}
if (resourceRep.getRedirectUris() != null) {
for (String redirectUri : resourceRep.getRedirectUris()) {
@ -438,6 +445,14 @@ public class RepresentationToModel {
if (rep.isSurrogateAuthRequired() != null) resource.setSurrogateAuthRequired(rep.isSurrogateAuthRequired());
resource.updateApplication();
if (rep.getProtocol() != null) resource.setProtocol(rep.getProtocol());
if (rep.getAttributes() != null) {
for (Map.Entry<String, String> entry : rep.getAttributes().entrySet()) {
resource.setAttribute(entry.getKey(), entry.getValue());
}
}
if (rep.getNotBefore() != null) {
resource.setNotBefore(rep.getNotBefore());
}
@ -565,6 +580,12 @@ public class RepresentationToModel {
if (rep.getNotBefore() != null) {
model.setNotBefore(rep.getNotBefore());
}
if (rep.getProtocol() != null) model.setProtocol(rep.getProtocol());
if (rep.getAttributes() != null) {
for (Map.Entry<String, String> entry : rep.getAttributes().entrySet()) {
model.setAttribute(entry.getKey(), entry.getValue());
}
}
}

View file

@ -6,7 +6,9 @@ import org.keycloak.models.RoleContainerModel;
import org.keycloak.models.RoleModel;
import org.keycloak.models.cache.entities.CachedClient;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
/**
@ -208,4 +210,43 @@ public abstract class ClientAdapter implements ClientModel {
updatedClient.setNotBefore(notBefore);
}
@Override
public String getProtocol() {
if (updatedClient != null) return updatedClient.getProtocol();
return cachedClient.getProtocol();
}
@Override
public void setProtocol(String protocol) {
getDelegateForUpdate();
updatedClient.setProtocol(protocol);
}
@Override
public void setAttribute(String name, String value) {
getDelegateForUpdate();
updatedClient.setAttribute(name, value);
}
@Override
public void removeAttribute(String name) {
getDelegateForUpdate();
updatedClient.removeAttribute(name);
}
@Override
public String getAttribute(String name) {
if (updatedClient != null) return updatedClient.getAttribute(name);
return cachedClient.getAttributes().get(name);
}
@Override
public Map<String, String> getAttributes() {
if (updatedClient != null) return updatedClient.getAttributes();
Map<String, String> copy = new HashMap<String, String>();
copy.putAll(cachedClient.getAttributes());
return copy;
}
}

View file

@ -6,7 +6,9 @@ import org.keycloak.models.RealmProvider;
import org.keycloak.models.RoleModel;
import org.keycloak.models.cache.RealmCache;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
/**
@ -21,6 +23,8 @@ public class CachedClient {
protected Set<String> redirectUris = new HashSet<String>();
protected boolean enabled;
protected String secret;
protected String protocol;
protected Map<String, String> attributes = new HashMap<String, String>();
protected boolean publicClient;
protected boolean fullScopeAllowed;
protected boolean directGrantsOnly;
@ -34,6 +38,8 @@ public class CachedClient {
name = model.getClientId();
this.realm = realm.getId();
enabled = model.isEnabled();
protocol = model.getProtocol();
attributes.putAll(model.getAttributes());
notBefore = model.getNotBefore();
directGrantsOnly = model.isDirectGrantsOnly();
publicClient = model.isPublicClient();
@ -98,4 +104,12 @@ public class CachedClient {
public boolean isFullScopeAllowed() {
return fullScopeAllowed;
}
public String getProtocol() {
return protocol;
}
public Map<String, String> getAttributes() {
return attributes;
}
}

View file

@ -10,8 +10,10 @@ import org.keycloak.models.jpa.entities.ScopeMappingEntity;
import javax.persistence.EntityManager;
import javax.persistence.TypedQuery;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
/**
@ -247,4 +249,38 @@ public abstract class ClientAdapter implements ClientModel {
public int hashCode() {
return entity.getId().hashCode();
}
@Override
public String getProtocol() {
return entity.getProtocol();
}
@Override
public void setProtocol(String protocol) {
entity.setProtocol(protocol);
}
@Override
public void setAttribute(String name, String value) {
entity.getAttributes().put(name, value);
}
@Override
public void removeAttribute(String name) {
entity.getAttributes().remove(name);
}
@Override
public String getAttribute(String name) {
return entity.getAttributes().get(name);
}
@Override
public Map<String, String> getAttributes() {
Map<String, String> copy = new HashMap<String, String>();
copy.putAll(entity.getAttributes());
return copy;
}
}

View file

@ -1,72 +0,0 @@
package org.keycloak.models.jpa.entities;
import java.util.HashMap;
import java.util.Map;
/**
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
* @version $Revision: 1 $
*/
public class AttributeMap {
Map<String, String> attributes = new HashMap<String, String>();
public void set(String key, String value) {
attributes.put(key, value);
}
public void set(String key, Boolean value) {
attributes.put(key, value.toString());
}
public void set(String key, Integer value) {
attributes.put(key, value.toString());
}
public String get(String key) {
return attributes.get(key);
}
public String get(String key, String defaultValue) {
String value = attributes.get(key);
return value == null ? defaultValue : value;
}
public String[] getArray(String key) {
String value = get(key);
if (value != null) {
String[] a = value.split(",");
for (int i = 0; i < a.length; i++) {
a[i] = a[i].trim();
}
return a;
} else {
return null;
}
}
public Integer getInt(String key) {
return getInt(key, null);
}
public Integer getInt(String key, Integer defaultValue) {
String v = get(key, null);
return v != null ? Integer.parseInt(v) : defaultValue;
}
public Long getLong(String key) {
return getLong(key, null);
}
public Long getLong(String key, Long defaultValue) {
String v = get(key, null);
return v != null ? Long.parseLong(v) : defaultValue;
}
public Boolean getBoolean(String key) {
return getBoolean(key, null);
}
public Boolean getBoolean(String key, Boolean defaultValue) {
String v = get(key, null);
return v != null ? Boolean.parseBoolean(v) : defaultValue;
}}

View file

@ -10,9 +10,12 @@ import javax.persistence.Inheritance;
import javax.persistence.InheritanceType;
import javax.persistence.JoinColumn;
import javax.persistence.ManyToOne;
import javax.persistence.MapKeyColumn;
import javax.persistence.Table;
import javax.persistence.UniqueConstraint;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
/**
@ -38,6 +41,8 @@ public abstract class ClientEntity {
private int notBefore;
@Column(name="PUBLIC_CLIENT")
private boolean publicClient;
@Column(name="PROTOCOL")
private String protocol;
@Column(name="FULL_SCOPE_ALLOWED")
private boolean fullScopeAllowed;
@ -55,6 +60,12 @@ public abstract class ClientEntity {
@CollectionTable(name = "REDIRECT_URIS", joinColumns={ @JoinColumn(name="CLIENT_ID") })
protected Set<String> redirectUris = new HashSet<String>();
@ElementCollection
@MapKeyColumn(name="NAME")
@Column(name="VALUE", length = 2048)
@CollectionTable(name="CLIENT_ATTRIBUTES", joinColumns={ @JoinColumn(name="CLIENT_ID") })
protected Map<String, String> attributes = new HashMap<String, String>();
public RealmEntity getRealm() {
return realm;
}
@ -142,4 +153,20 @@ public abstract class ClientEntity {
public void setFullScopeAllowed(boolean fullScopeAllowed) {
this.fullScopeAllowed = fullScopeAllowed;
}
public Map<String, String> getAttributes() {
return attributes;
}
public void setAttributes(Map<String, String> attributes) {
this.attributes = attributes;
}
public String getProtocol() {
return protocol;
}
public void setProtocol(String protocol) {
this.protocol = protocol;
}
}

View file

@ -12,8 +12,10 @@ import org.keycloak.models.mongo.keycloak.entities.MongoRoleEntity;
import org.keycloak.models.mongo.utils.MongoModelUtils;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
/**
@ -240,4 +242,42 @@ public abstract class ClientAdapter<T extends MongoIdentifiableEntity> extends A
getMongoStore().pullItemFromList(this.getMongoEntity(), "scopeIds", role.getId(), invocationContext);
}
@Override
public String getProtocol() {
return getMongoEntityAsClient().getProtocol();
}
@Override
public void setProtocol(String protocol) {
getMongoEntityAsClient().setProtocol(protocol);
updateMongoEntity();
}
@Override
public void setAttribute(String name, String value) {
getMongoEntityAsClient().getAttributes().put(name, value);
updateMongoEntity();
}
@Override
public void removeAttribute(String name) {
getMongoEntityAsClient().getAttributes().remove(name);
updateMongoEntity();
}
@Override
public String getAttribute(String name) {
return getMongoEntityAsClient().getAttributes().get(name);
}
@Override
public Map<String, String> getAttributes() {
Map<String, String> copy = new HashMap<String, String>();
copy.putAll(getMongoEntityAsClient().getAttributes());
return copy;
}
}

View file

@ -18,6 +18,7 @@ import org.keycloak.models.UserModel;
import org.keycloak.models.UserSessionProvider;
import org.keycloak.models.utils.KeycloakModelUtils;
import org.keycloak.models.utils.RepresentationToModel;
import org.keycloak.protocol.oidc.OpenIDConnect;
import org.keycloak.representations.idm.ApplicationRepresentation;
import org.keycloak.representations.idm.RealmEventsConfigRepresentation;
import org.keycloak.representations.idm.RealmRepresentation;

View file

@ -0,0 +1,19 @@
package org.keycloak.services.resources.admin;
import org.keycloak.models.ApplicationModel;
import org.keycloak.models.RealmModel;
/**
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
* @version $Revision: 1 $
*/
public class ApplicationsByIdResource extends ApplicationsResource {
public ApplicationsByIdResource(RealmModel realm, RealmAuth auth) {
super(realm, auth);
}
@Override
protected ApplicationModel getApplicationByPathParam(String id) {
return realm.getApplicationById(id);
}
}

View file

@ -102,7 +102,7 @@ public class ApplicationsResource {
*/
@Path("{app-name}")
public ApplicationResource getApplication(final @PathParam("app-name") String name) {
ApplicationModel applicationModel = realm.getApplicationByName(name);
ApplicationModel applicationModel = getApplicationByPathParam(name);
if (applicationModel == null) {
throw new NotFoundException("Could not find application: " + name);
}
@ -112,4 +112,8 @@ public class ApplicationsResource {
return applicationResource;
}
protected ApplicationModel getApplicationByPathParam(String name) {
return realm.getApplicationByName(name);
}
}

View file

@ -42,6 +42,7 @@ import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
import javax.ws.rs.core.UriInfo;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
@ -84,6 +85,19 @@ public class RealmAdminResource {
return applicationsResource;
}
/**
* Base path for managing applications under this realm.
*
* @return
*/
@Path("applications-by-id")
public ApplicationsByIdResource getApplicationsById() {
ApplicationsByIdResource applicationsResource = new ApplicationsByIdResource(realm, auth);
ResteasyProviderFactory.getInstance().injectProperties(applicationsResource);
//resourceContext.initResource(applicationsResource);
return applicationsResource;
}
/**
* base path for managing oauth clients in this realm
*
@ -271,6 +285,7 @@ public class RealmAdminResource {
@GET
@NoCache
@Produces(MediaType.APPLICATION_JSON)
@Deprecated
public Map<String, Integer> getApplicationSessionStats() {
auth.requireView();
Map<String, Integer> stats = new HashMap<String, Integer>();
@ -282,6 +297,31 @@ public class RealmAdminResource {
return stats;
}
/**
* Returns a JSON map. The key is the application id, the value is the number of sessions that currently are active
* with that application. Only application's that actually have a session associated with them will be in this map.
*
* @return
*/
@Path("application-by-id-session-stats")
@GET
@NoCache
@Produces(MediaType.APPLICATION_JSON)
public List<Map<String, String>> getApplicationByIdSessionStats() {
auth.requireView();
List<Map<String, String>> data = new LinkedList<Map<String, String>>();
for (ApplicationModel application : realm.getApplications()) {
int size = session.sessions().getActiveUserSessions(application.getRealm(), application);
if (size == 0) continue;
Map<String, String> map = new HashMap<String, String>();
map.put("id", application.getId());
map.put("name", application.getName());
map.put("active", size + "");
data.add(map);
}
return data;
}
/**
* View the events provider and how it is configured.
*

View file

@ -169,7 +169,35 @@ public class RoleByIdResource extends RoleResource {
final @PathParam("app") String appName) {
RoleModel role = getRoleModel(id);
auth.requireView();
return getApplicationRoleComposites(appName, role);
ApplicationModel app = realm.getApplicationByName(appName);
if (app == null) {
throw new NotFoundException("Could not find application: " + appName);
}
return getApplicationRoleComposites(app, role);
}
/**
* Return a set of application-level roles for a specific app that are in the role's composite
*
* @param id
* @param appId
* @return
*/
@Path("{role-id}/composites/applications-by-id/{appId}")
@GET
@NoCache
@Produces("application/json")
public Set<RoleRepresentation> getApplicationByIdRoleComposites(final @PathParam("role-id") String id,
final @PathParam("appId") String appId) {
RoleModel role = getRoleModel(id);
auth.requireView();
ApplicationModel app = realm.getApplicationById(appId);
if (app == null) {
throw new NotFoundException("Could not find application: " + appId);
}
return getApplicationRoleComposites(app, role);
}
/**

View file

@ -2,6 +2,7 @@ package org.keycloak.services.resources.admin;
import org.jboss.resteasy.annotations.cache.NoCache;
import org.jboss.resteasy.spi.NotFoundException;
import org.keycloak.models.ApplicationModel;
import org.keycloak.models.ModelDuplicateException;
import org.keycloak.models.RealmModel;
import org.keycloak.models.RoleContainerModel;
@ -222,7 +223,40 @@ public class RoleContainerResource extends RoleResource {
if (role == null) {
throw new NotFoundException("Could not find role: " + roleName);
}
return getApplicationRoleComposites(appName, role);
ApplicationModel app = realm.getApplicationByName(appName);
if (app == null) {
throw new NotFoundException("Could not find application: " + appName);
}
return getApplicationRoleComposites(app, role);
}
/**
* An app-level roles for a specific app for this role's composite
*
* @param roleName role's name (not id!)
* @param appId
* @return
*/
@Path("{role-name}/composites/application-by-id/{appId}")
@GET
@NoCache
@Produces("application/json")
public Set<RoleRepresentation> getApplicationByIdRoleComposites(final @PathParam("role-name") String roleName,
final @PathParam("appId") String appId) {
auth.requireManage();
RoleModel role = roleContainer.getRole(roleName);
if (role == null) {
throw new NotFoundException("Could not find role: " + roleName);
}
ApplicationModel app = realm.getApplicationById(appId);
if (app == null) {
throw new NotFoundException("Could not find application: " + appId);
}
return getApplicationRoleComposites(app, role);
}

View file

@ -69,15 +69,9 @@ public abstract class RoleResource {
return composites;
}
protected Set<RoleRepresentation> getApplicationRoleComposites(String appName, RoleModel role) {
protected Set<RoleRepresentation> getApplicationRoleComposites(ApplicationModel app, RoleModel role) {
if (!role.isComposite() || role.getComposites().size() == 0) return Collections.emptySet();
ApplicationModel app = realm.getApplicationByName(appName);
if (app == null) {
throw new NotFoundException("Could not find application: " + appName);
}
Set<RoleRepresentation> composites = new HashSet<RoleRepresentation>(role.getComposites().size());
for (RoleModel composite : role.getComposites()) {
if (composite.getContainer().equals(app))

View file

@ -0,0 +1,140 @@
package org.keycloak.services.resources.admin;
import org.jboss.resteasy.annotations.cache.NoCache;
import org.jboss.resteasy.spi.NotFoundException;
import org.keycloak.models.ApplicationModel;
import org.keycloak.models.ClientModel;
import org.keycloak.models.KeycloakSession;
import org.keycloak.models.RealmModel;
import org.keycloak.models.RoleModel;
import org.keycloak.models.utils.ModelToRepresentation;
import org.keycloak.representations.idm.RoleRepresentation;
import javax.ws.rs.Consumes;
import javax.ws.rs.DELETE;
import javax.ws.rs.GET;
import javax.ws.rs.POST;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import javax.ws.rs.Produces;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;
/**
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
* @version $Revision: 1 $
*/
public class ScopeMappedApplicationResource {
protected RealmModel realm;
private RealmAuth auth;
protected ClientModel client;
protected KeycloakSession session;
protected ApplicationModel app;
public ScopeMappedApplicationResource(RealmModel realm, RealmAuth auth, ClientModel client, KeycloakSession session, ApplicationModel app) {
this.realm = realm;
this.auth = auth;
this.client = client;
this.session = session;
this.app = app;
}
/**
* Get the roles associated with a client's scope for a specific application.
*
* @return
*/
@GET
@Produces("application/json")
@NoCache
public List<RoleRepresentation> getApplicationScopeMappings() {
auth.requireView();
Set<RoleModel> mappings = app.getApplicationScopeMappings(client);
List<RoleRepresentation> mapRep = new ArrayList<RoleRepresentation>();
for (RoleModel roleModel : mappings) {
mapRep.add(ModelToRepresentation.toRepresentation(roleModel));
}
return mapRep;
}
/**
* The available application-level roles that can be associated with the client's scope
*
* @return
*/
@Path("available")
@GET
@Produces("application/json")
@NoCache
public List<RoleRepresentation> getAvailableApplicationScopeMappings() {
auth.requireView();
Set<RoleModel> roles = app.getRoles();
return ScopeMappedResource.getAvailable(client, roles);
}
/**
* Get effective application roles that are associated with the client's scope for a specific application.
*
* @return
*/
@Path("composite")
@GET
@Produces("application/json")
@NoCache
public List<RoleRepresentation> getCompositeApplicationScopeMappings() {
auth.requireView();
Set<RoleModel> roles = app.getRoles();
return ScopeMappedResource.getComposite(client, roles);
}
/**
* Add application-level roles to the client's scope
*
* @param roles
*/
@POST
@Consumes("application/json")
public void addApplicationScopeMapping(List<RoleRepresentation> roles) {
auth.requireManage();
for (RoleRepresentation role : roles) {
RoleModel roleModel = app.getRole(role.getName());
if (roleModel == null) {
throw new NotFoundException("Role not found");
}
client.addScopeMapping(roleModel);
}
}
/**
* Remove application-level roles from the client's scope.
*
* @param roles
*/
@DELETE
@Consumes("application/json")
public void deleteApplicationScopeMapping(List<RoleRepresentation> roles) {
auth.requireManage();
if (roles == null) {
Set<RoleModel> roleModels = app.getApplicationScopeMappings(client);
for (RoleModel roleModel : roleModels) {
client.deleteScopeMapping(roleModel);
}
} else {
for (RoleRepresentation role : roles) {
RoleModel roleModel = app.getRole(role.getName());
if (roleModel == null) {
throw new NotFoundException("Role not found");
}
client.deleteScopeMapping(roleModel);
}
}
}
}

View file

@ -120,10 +120,10 @@ public class ScopeMappedResource {
auth.requireView();
Set<RoleModel> roles = realm.getRoles();
return getAvailable(roles);
return getAvailable(client, roles);
}
private List<RoleRepresentation> getAvailable(Set<RoleModel> roles) {
public static List<RoleRepresentation> getAvailable(ClientModel client, Set<RoleModel> roles) {
List<RoleRepresentation> available = new ArrayList<RoleRepresentation>();
for (RoleModel roleModel : roles) {
if (client.hasScope(roleModel)) continue;
@ -147,10 +147,10 @@ public class ScopeMappedResource {
auth.requireView();
Set<RoleModel> roles = realm.getRoles();
return getComposite(roles);
return getComposite(client, roles);
}
private List<RoleRepresentation> getComposite(Set<RoleModel> roles) {
public static List<RoleRepresentation> getComposite(ClientModel client, Set<RoleModel> roles) {
List<RoleRepresentation> composite = new ArrayList<RoleRepresentation>();
for (RoleModel roleModel : roles) {
if (client.hasScope(roleModel)) composite.add(ModelToRepresentation.toRepresentation(roleModel));
@ -201,146 +201,32 @@ public class ScopeMappedResource {
for (RoleRepresentation role : roles) {
RoleModel roleModel = realm.getRoleById(role.getId());
if (roleModel == null) {
throw new NotFoundException("Role not found");
throw new NotFoundException("Application not found");
}
client.deleteScopeMapping(roleModel);
}
}
}
/**
* Get the roles associated with a client's scope for a specific application.
*
* @param appName roles associated with client's scope for a specific application
* @return
*/
@Path("applications/{app}")
@GET
@Produces("application/json")
@NoCache
public List<RoleRepresentation> getApplicationScopeMappings(@PathParam("app") String appName) {
auth.requireView();
public ScopeMappedApplicationResource getApplicationScopeMappings(@PathParam("app") String appName) {
ApplicationModel app = realm.getApplicationByName(appName);
if (app == null) {
throw new NotFoundException("Role not found");
}
Set<RoleModel> mappings = app.getApplicationScopeMappings(client);
List<RoleRepresentation> mapRep = new ArrayList<RoleRepresentation>();
for (RoleModel roleModel : mappings) {
mapRep.add(ModelToRepresentation.toRepresentation(roleModel));
}
return mapRep;
return new ScopeMappedApplicationResource(realm, auth, client, session, app);
}
/**
* The available application-level roles that can be associated with the client's scope
*
* @param appName available roles for a specific application
* @return
*/
@Path("applications/{app}/available")
@GET
@Produces("application/json")
@NoCache
public List<RoleRepresentation> getAvailableApplicationScopeMappings(@PathParam("app") String appName) {
auth.requireView();
ApplicationModel app = realm.getApplicationByName(appName);
if (app == null) {
throw new NotFoundException("Role not found");
}
Set<RoleModel> roles = app.getRoles();
return getAvailable(roles);
}
/**
* Get effective application roles that are associated with the client's scope for a specific application.
*
* @param appName effective roles for a specific app
* @return
*/
@Path("applications/{app}/composite")
@GET
@Produces("application/json")
@NoCache
public List<RoleRepresentation> getCompositeApplicationScopeMappings(@PathParam("app") String appName) {
auth.requireView();
ApplicationModel app = realm.getApplicationByName(appName);
if (app == null) {
throw new NotFoundException("Role not found");
}
Set<RoleModel> roles = app.getRoles();
return getComposite(roles);
}
/**
* Add application-level roles to the client's scope
*
* @param appName
* @param roles
*/
@Path("applications/{app}")
@POST
@Consumes("application/json")
public void addApplicationScopeMapping(@PathParam("app") String appName, List<RoleRepresentation> roles) {
auth.requireManage();
ApplicationModel app = realm.getApplicationByName(appName);
@Path("applications-by-id/{appId}")
public ScopeMappedApplicationResource getApplicationByIdScopeMappings(@PathParam("appId") String appId) {
ApplicationModel app = realm.getApplicationById(appId);
if (app == null) {
throw new NotFoundException("Application not found");
}
for (RoleRepresentation role : roles) {
RoleModel roleModel = app.getRole(role.getName());
if (roleModel == null) {
throw new NotFoundException("Role not found");
}
client.addScopeMapping(roleModel);
}
}
/**
* Remove application-level roles from the client's scope.
*
* @param appName
* @param roles
*/
@Path("applications/{app}")
@DELETE
@Consumes("application/json")
public void deleteApplicationScopeMapping(@PathParam("app") String appName, List<RoleRepresentation> roles) {
auth.requireManage();
ApplicationModel app = realm.getApplicationByName(appName);
if (app == null) {
throw new NotFoundException("Application not found");
}
if (roles == null) {
Set<RoleModel> roleModels = app.getApplicationScopeMappings(client);
for (RoleModel roleModel : roleModels) {
client.deleteScopeMapping(roleModel);
}
} else {
for (RoleRepresentation role : roles) {
RoleModel roleModel = app.getRole(role.getName());
if (roleModel == null) {
throw new NotFoundException("Role not found");
}
client.deleteScopeMapping(roleModel);
}
}
return new ScopeMappedApplicationResource(realm, auth, client, session, app);
}
}

View file

@ -0,0 +1,175 @@
package org.keycloak.services.resources.admin;
import org.jboss.logging.Logger;
import org.jboss.resteasy.annotations.cache.NoCache;
import org.jboss.resteasy.spi.NotFoundException;
import org.keycloak.ClientConnection;
import org.keycloak.models.ApplicationModel;
import org.keycloak.models.KeycloakSession;
import org.keycloak.models.RealmModel;
import org.keycloak.models.RoleModel;
import org.keycloak.models.UserModel;
import org.keycloak.models.utils.ModelToRepresentation;
import org.keycloak.protocol.oidc.TokenManager;
import org.keycloak.representations.idm.RoleRepresentation;
import javax.ws.rs.Consumes;
import javax.ws.rs.DELETE;
import javax.ws.rs.GET;
import javax.ws.rs.POST;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import javax.ws.rs.Produces;
import javax.ws.rs.core.Context;
import javax.ws.rs.core.UriInfo;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
/**
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
* @version $Revision: 1 $
*/
public class UserApplicationRoleMappingsResource {
protected static final Logger logger = Logger.getLogger(UserApplicationRoleMappingsResource.class);
protected RealmModel realm;
protected RealmAuth auth;
protected UserModel user;
protected ApplicationModel application;
public UserApplicationRoleMappingsResource(RealmModel realm, RealmAuth auth, UserModel user, ApplicationModel application) {
this.realm = realm;
this.auth = auth;
this.user = user;
this.application = application;
}
/**
* Get application-level role mappings for this user for a specific app
*
* @return
*/
@GET
@Produces("application/json")
@NoCache
public List<RoleRepresentation> getApplicationRoleMappings() {
auth.requireView();
logger.debug("getApplicationRoleMappings");
Set<RoleModel> mappings = user.getApplicationRoleMappings(application);
List<RoleRepresentation> mapRep = new ArrayList<RoleRepresentation>();
for (RoleModel roleModel : mappings) {
mapRep.add(ModelToRepresentation.toRepresentation(roleModel));
}
logger.debugv("getApplicationRoleMappings.size() = {0}", mapRep.size());
return mapRep;
}
/**
* Get effective application-level role mappings. This recurses any composite roles
*
* @return
*/
@Path("composite")
@GET
@Produces("application/json")
@NoCache
public List<RoleRepresentation> getCompositeApplicationRoleMappings() {
auth.requireView();
logger.debug("getCompositeApplicationRoleMappings");
Set<RoleModel> roles = application.getRoles();
List<RoleRepresentation> mapRep = new ArrayList<RoleRepresentation>();
for (RoleModel roleModel : roles) {
if (user.hasRole(roleModel)) mapRep.add(ModelToRepresentation.toRepresentation(roleModel));
}
logger.debugv("getCompositeApplicationRoleMappings.size() = {0}", mapRep.size());
return mapRep;
}
/**
* Get available application-level roles that can be mapped to the user
*
* @return
*/
@Path("available")
@GET
@Produces("application/json")
@NoCache
public List<RoleRepresentation> getAvailableApplicationRoleMappings() {
auth.requireView();
Set<RoleModel> available = application.getRoles();
return getAvailableRoles(user, available);
}
public static List<RoleRepresentation> getAvailableRoles(UserModel user, Set<RoleModel> available) {
Set<RoleModel> roles = new HashSet<RoleModel>();
for (RoleModel roleModel : available) {
if (user.hasRole(roleModel)) continue;
roles.add(roleModel);
}
List<RoleRepresentation> mappings = new ArrayList<RoleRepresentation>();
for (RoleModel roleModel : roles) {
mappings.add(ModelToRepresentation.toRepresentation(roleModel));
}
return mappings;
}
/**
* Add application-level roles to the user role mapping.
*
* @param roles
*/
@POST
@Consumes("application/json")
public void addApplicationRoleMapping(List<RoleRepresentation> roles) {
auth.requireManage();
logger.debug("addApplicationRoleMapping");
for (RoleRepresentation role : roles) {
RoleModel roleModel = application.getRole(role.getName());
if (roleModel == null || !roleModel.getId().equals(role.getId())) {
throw new NotFoundException("Role not found");
}
user.grantRole(roleModel);
}
}
/**
* Delete application-level roles from user role mapping.
*
* @param roles
*/
@DELETE
@Consumes("application/json")
public void deleteApplicationRoleMapping(List<RoleRepresentation> roles) {
auth.requireManage();
if (roles == null) {
Set<RoleModel> roleModels = user.getApplicationRoleMappings(application);
for (RoleModel roleModel : roleModels) {
if (!(roleModel.getContainer() instanceof ApplicationModel)) {
ApplicationModel app = (ApplicationModel) roleModel.getContainer();
if (!app.getId().equals(application.getId())) continue;
}
user.deleteRoleMapping(roleModel);
}
} else {
for (RoleRepresentation role : roles) {
RoleModel roleModel = application.getRole(role.getName());
if (roleModel == null || !roleModel.getId().equals(role.getId())) {
throw new NotFoundException("Role not found");
}
user.deleteRoleMapping(roleModel);
}
}
}
}

View file

@ -519,7 +519,7 @@ public class UsersResource {
}
Set<RoleModel> available = realm.getRoles();
return getAvailableRoles(user, available);
return UserApplicationRoleMappingsResource.getAvailableRoles(user, available);
}
/**
@ -586,22 +586,8 @@ public class UsersResource {
}
}
/**
* Get application-level role mappings for this user for a specific app
*
* @param username username (not id!)
* @param appName app name (not id!)
* @return
*/
@Path("{username}/role-mappings/applications/{app}")
@GET
@Produces("application/json")
@NoCache
public List<RoleRepresentation> getApplicationRoleMappings(@PathParam("username") String username, @PathParam("app") String appName) {
auth.requireView();
logger.debug("getApplicationRoleMappings");
public UserApplicationRoleMappingsResource getUserApplicationRoleMappingsResource(@PathParam("username") String username, @PathParam("app") String appName) {
UserModel user = session.users().getUserByUsername(username, realm);
if (user == null) {
throw new NotFoundException("User not found");
@ -613,175 +599,25 @@ public class UsersResource {
throw new NotFoundException("Application not found");
}
Set<RoleModel> mappings = user.getApplicationRoleMappings(application);
List<RoleRepresentation> mapRep = new ArrayList<RoleRepresentation>();
for (RoleModel roleModel : mappings) {
mapRep.add(ModelToRepresentation.toRepresentation(roleModel));
}
logger.debugv("getApplicationRoleMappings.size() = {0}", mapRep.size());
return mapRep;
return new UserApplicationRoleMappingsResource(realm, auth, user, application);
}
/**
* Get effective application-level role mappings. This recurses any composite roles
*
* @param username username (not id!)
* @param appName app name (not id!)
* @return
*/
@Path("{username}/role-mappings/applications/{app}/composite")
@GET
@Produces("application/json")
@NoCache
public List<RoleRepresentation> getCompositeApplicationRoleMappings(@PathParam("username") String username, @PathParam("app") String appName) {
auth.requireView();
logger.debug("getCompositeApplicationRoleMappings");
@Path("{username}/role-mappings/applications-by-id/{appId}")
public UserApplicationRoleMappingsResource getUserApplicationRoleMappingsResourceById(@PathParam("username") String username, @PathParam("appId") String appId) {
UserModel user = session.users().getUserByUsername(username, realm);
if (user == null) {
throw new NotFoundException("User not found");
}
ApplicationModel application = realm.getApplicationByName(appName);
ApplicationModel application = realm.getApplicationById(appId);
if (application == null) {
throw new NotFoundException("Application not found");
}
Set<RoleModel> roles = application.getRoles();
List<RoleRepresentation> mapRep = new ArrayList<RoleRepresentation>();
for (RoleModel roleModel : roles) {
if (user.hasRole(roleModel)) mapRep.add(ModelToRepresentation.toRepresentation(roleModel));
}
logger.debugv("getCompositeApplicationRoleMappings.size() = {0}", mapRep.size());
return mapRep;
}
/**
* Get available application-level roles that can be mapped to the user
*
* @param username username (not id!)
* @param appName app name (not id!)
* @return
*/
@Path("{username}/role-mappings/applications/{app}/available")
@GET
@Produces("application/json")
@NoCache
public List<RoleRepresentation> getAvailableApplicationRoleMappings(@PathParam("username") String username, @PathParam("app") String appName) {
auth.requireView();
logger.debug("getApplicationRoleMappings");
UserModel user = session.users().getUserByUsername(username, realm);
if (user == null) {
throw new NotFoundException("User not found");
}
ApplicationModel application = realm.getApplicationByName(appName);
if (application == null) {
throw new NotFoundException("Application not found");
}
Set<RoleModel> available = application.getRoles();
return getAvailableRoles(user, available);
}
protected List<RoleRepresentation> getAvailableRoles(UserModel user, Set<RoleModel> available) {
Set<RoleModel> roles = new HashSet<RoleModel>();
for (RoleModel roleModel : available) {
if (user.hasRole(roleModel)) continue;
roles.add(roleModel);
}
List<RoleRepresentation> mappings = new ArrayList<RoleRepresentation>();
for (RoleModel roleModel : roles) {
mappings.add(ModelToRepresentation.toRepresentation(roleModel));
}
return mappings;
}
/**
* Add applicaiton-level roles to the user role mapping.
*
* @param username username (not id!)
* @param appName app name (not id!)
* @param roles
*/
@Path("{username}/role-mappings/applications/{app}")
@POST
@Consumes("application/json")
public void addApplicationRoleMapping(@PathParam("username") String username, @PathParam("app") String appName, List<RoleRepresentation> roles) {
auth.requireManage();
logger.debug("addApplicationRoleMapping");
UserModel user = session.users().getUserByUsername(username, realm);
if (user == null) {
throw new NotFoundException("User not found");
}
ApplicationModel application = realm.getApplicationByName(appName);
if (application == null) {
throw new NotFoundException("Application not found");
}
for (RoleRepresentation role : roles) {
RoleModel roleModel = application.getRole(role.getName());
if (roleModel == null || !roleModel.getId().equals(role.getId())) {
throw new NotFoundException("Role not found");
}
user.grantRole(roleModel);
}
return new UserApplicationRoleMappingsResource(realm, auth, user, application);
}
/**
* Delete application-level roles from user role mapping.
*
* @param username username (not id!)
* @param appName app name (not id!)
* @param roles
*/
@Path("{username}/role-mappings/applications/{app}")
@DELETE
@Consumes("application/json")
public void deleteApplicationRoleMapping(@PathParam("username") String username, @PathParam("app") String appName, List<RoleRepresentation> roles) {
auth.requireManage();
UserModel user = session.users().getUserByUsername(username, realm);
if (user == null) {
throw new NotFoundException("User not found");
}
ApplicationModel application = realm.getApplicationByName(appName);
if (application == null) {
throw new NotFoundException("Application not found");
}
if (roles == null) {
Set<RoleModel> roleModels = user.getApplicationRoleMappings(application);
for (RoleModel roleModel : roleModels) {
if (!(roleModel.getContainer() instanceof ApplicationModel)) {
ApplicationModel app = (ApplicationModel) roleModel.getContainer();
if (!app.getId().equals(application.getId())) continue;
}
user.deleteRoleMapping(roleModel);
}
} else {
for (RoleRepresentation role : roles) {
RoleModel roleModel = application.getRole(role.getName());
if (roleModel == null || !roleModel.getId().equals(role.getId())) {
throw new NotFoundException("Role not found");
}
user.deleteRoleMapping(roleModel);
}
}
}
/**
* Set up a temporary password for this user. User will have to reset this temporary password when they log
* in next.