diff --git a/core/src/main/java/org/keycloak/representations/idm/RealmRepresentation.java b/core/src/main/java/org/keycloak/representations/idm/RealmRepresentation.java index 0fedfad111..896c1c9ab8 100755 --- a/core/src/main/java/org/keycloak/representations/idm/RealmRepresentation.java +++ b/core/src/main/java/org/keycloak/representations/idm/RealmRepresentation.java @@ -21,6 +21,8 @@ public class RealmRepresentation { protected String publicKey; protected List roles; protected List requiredCredentials; + protected List requiredResourceCredentials; + protected List requiredOAuthClientCredentials; protected List users; protected List roleMappings; protected List scopeMappings; @@ -147,6 +149,22 @@ public class RealmRepresentation { this.requiredCredentials = requiredCredentials; } + public List getRequiredResourceCredentials() { + return requiredResourceCredentials; + } + + public void setRequiredResourceCredentials(List requiredResourceCredentials) { + this.requiredResourceCredentials = requiredResourceCredentials; + } + + public List getRequiredOAuthClientCredentials() { + return requiredOAuthClientCredentials; + } + + public void setRequiredOAuthClientCredentials(List requiredOAuthClientCredentials) { + this.requiredOAuthClientCredentials = requiredOAuthClientCredentials; + } + public int getAccessCodeLifespan() { return accessCodeLifespan; } diff --git a/core/src/main/java/org/keycloak/representations/idm/ResourceRepresentation.java b/core/src/main/java/org/keycloak/representations/idm/ResourceRepresentation.java index 84d499f050..6cf9de6a79 100755 --- a/core/src/main/java/org/keycloak/representations/idm/ResourceRepresentation.java +++ b/core/src/main/java/org/keycloak/representations/idm/ResourceRepresentation.java @@ -11,10 +11,12 @@ import java.util.Set; */ public class ResourceRepresentation { protected String self; // link + protected String id; protected String name; protected String adminUrl; protected boolean surrogateAuthRequired; protected boolean useRealmMappings; + protected boolean enabled; protected List credentials; protected List roles; protected List roleMappings; @@ -28,6 +30,14 @@ public class ResourceRepresentation { this.self = self; } + public String getId() { + return id; + } + + public void setId(String id) { + this.id = id; + } + public String getName() { return name; } @@ -36,6 +46,14 @@ public class ResourceRepresentation { this.name = name; } + public boolean isEnabled() { + return enabled; + } + + public void setEnabled(boolean enabled) { + this.enabled = enabled; + } + public boolean isSurrogateAuthRequired() { return surrogateAuthRequired; } @@ -52,6 +70,13 @@ public class ResourceRepresentation { this.roles = roles; } + public ResourceRepresentation role(RoleRepresentation role) { + if (this.roles == null) this.roles = new ArrayList(); + this.roles.add(role); + return this; + } + + public ResourceRepresentation role(String role, String description) { if (this.roles == null) this.roles = new ArrayList(); this.roles.add(new RoleRepresentation(role, description)); diff --git a/examples/as7-eap-demo/server/src/main/resources/META-INF/testrealm.json b/examples/as7-eap-demo/server/src/main/resources/META-INF/testrealm.json index b81aad6353..642af04a29 100755 --- a/examples/as7-eap-demo/server/src/main/resources/META-INF/testrealm.json +++ b/examples/as7-eap-demo/server/src/main/resources/META-INF/testrealm.json @@ -14,6 +14,20 @@ "secret" : true } ], + "requiredResourceCredentials" : [ + { + "type" : "Password", + "input" : true, + "secret" : true + } + ], + "requiredOAuthClientCredentials" : [ + { + "type" : "Password", + "input" : true, + "secret" : true + } + ], "users" : [ { "username" : "bburke@redhat.com", @@ -58,6 +72,7 @@ "resources" : [ { "name" : "customer-portal", + "enabled" : true, "adminUrl" : "http://localhost:8080/customer-portal/j_admin_request", "useRealmMappings" : true, "credentials" : [ @@ -67,6 +82,7 @@ }, { "name" : "product-portal", + "enabled" : true, "adminUrl" : "http://localhost:8080/product-portal/j_admin_request", "useRealmMappings" : true, "credentials" : [ diff --git a/examples/as7-eap-demo/server/src/main/webapp/saas/admin/js/controllers.js b/examples/as7-eap-demo/server/src/main/webapp/saas/admin/js/controllers.js index a3ed7c2dff..c8474fd796 100755 --- a/examples/as7-eap-demo/server/src/main/webapp/saas/admin/js/controllers.js +++ b/examples/as7-eap-demo/server/src/main/webapp/saas/admin/js/controllers.js @@ -4,6 +4,7 @@ var module = angular.module('keycloak.controllers', [ 'keycloak.services' ]); var realmslist = {}; + module.controller('GlobalCtrl', function($scope, $http, Auth, $location, Notifications) { $scope.addMessage = function() { Notifications.success("test"); @@ -152,20 +153,30 @@ module.controller('ApplicationDetailCtrl', function($scope, application, Applica }); -module.controller('RealmListCtrl', function($scope, Realm) { +module.controller('RealmListCtrl', function($scope, Realm, Current) { $scope.realms = Realm.get(); - realmslist = $scope.realms; + Current.realms = $scope.realms; }); -module.controller('RealmDropdownCtrl', function($scope, Realm) { +module.controller('RealmDropdownCtrl', function($scope, Realm, Current, $location) { console.log('test log writing'); - realmslist = Realm.get(); - $scope.realmslist = function() { - return realmslist; + Current.realms = Realm.get(); + $scope.current = Current; + $scope.changeRealm = function() { + console.log('select box changed'); + for (var id in Current.realms) { + var val = Current.realms[id]; + console.log('checking: ' + val); + if (val == Current.realm) { + console.log("redirect to: /realms/" + id); + $location.url("/realms/" + id); + break; + } + } }; }); -module.controller('RealmDetailCtrl', function($scope, Realm, realm, $location, Dialog, Notifications) { +module.controller('RealmDetailCtrl', function($scope, Current, Realm, realm, $location, Dialog, Notifications) { $scope.realm = angular.copy(realm); $scope.createRealm = !realm.id; @@ -260,13 +271,21 @@ module.controller('RealmDetailCtrl', function($scope, Realm, realm, $location, D Realm.save(realmCopy, function(data, headers) { var l = headers().location; var id = l.substring(l.lastIndexOf("/") + 1); - realmslist = Realm.get(); - $location.url("/realms/" + id); + + var data = Realm.get(function() { + Current.realms = data; + Current.realm = Current.realms[id]; + console.log('Current.realms[id]: ' + Current.realms[id]); + console.log('data[id]: ' + data[id]); + console.log('Current.realm.name: ' + Current.realm.name); + + }); + $location.url("/realms/" + id); Notifications.success("Created realm"); }); } else { Realm.update(realmCopy, function() { - realmslist = Realm.get(); + Current.realms = Realm.get(); $scope.changed = false; realm = angular.copy($scope.realm); Notifications.success("Saved changes to realm"); @@ -290,7 +309,7 @@ module.controller('RealmDetailCtrl', function($scope, Realm, realm, $location, D $scope.remove = function() { Dialog.confirmDelete($scope.realm.name, 'realm', function() { Realm.remove($scope.realm, function() { - realmslist = Realm.get(); + Current.realms = Realm.get(); $location.url("/realms"); Notifications.success("Deleted realm"); }); diff --git a/examples/as7-eap-demo/server/src/main/webapp/saas/admin/js/services.js b/examples/as7-eap-demo/server/src/main/webapp/saas/admin/js/services.js index ba3a26a9d7..02995c8989 100755 --- a/examples/as7-eap-demo/server/src/main/webapp/saas/admin/js/services.js +++ b/examples/as7-eap-demo/server/src/main/webapp/saas/admin/js/services.js @@ -157,4 +157,11 @@ module.factory('Role', function($resource) { method : 'PUT' } }); +}); + +module.factory('Current', function($resource) { + return { + realm : null, + realms : {} + }; }); \ No newline at end of file diff --git a/examples/as7-eap-demo/server/src/main/webapp/saas/admin/partials/menu.html b/examples/as7-eap-demo/server/src/main/webapp/saas/admin/partials/menu.html index effc324437..6d6423d49f 100755 --- a/examples/as7-eap-demo/server/src/main/webapp/saas/admin/partials/menu.html +++ b/examples/as7-eap-demo/server/src/main/webapp/saas/admin/partials/menu.html @@ -3,32 +3,36 @@ diff --git a/examples/as7-eap-demo/server/src/main/webapp/saas/admin/partials/realm-detail.html b/examples/as7-eap-demo/server/src/main/webapp/saas/admin/partials/realm-detail.html index 7a841a1665..a10e742628 100755 --- a/examples/as7-eap-demo/server/src/main/webapp/saas/admin/partials/realm-detail.html +++ b/examples/as7-eap-demo/server/src/main/webapp/saas/admin/partials/realm-detail.html @@ -7,7 +7,7 @@

New Realm

- {{realm.realm}} + Realm Settings

Please fill diff --git a/examples/as7-eap-demo/server/src/main/webapp/saas/admin/partials/realm-menu.html b/examples/as7-eap-demo/server/src/main/webapp/saas/admin/partials/realm-menu.html index d72e57a5ce..bfdbbe5bf0 100755 --- a/examples/as7-eap-demo/server/src/main/webapp/saas/admin/partials/realm-menu.html +++ b/examples/as7-eap-demo/server/src/main/webapp/saas/admin/partials/realm-menu.html @@ -1,21 +1,11 @@
\ No newline at end of file diff --git a/examples/as7-eap-demo/server/src/main/webapp/saas/admin/partials/role-detail.html b/examples/as7-eap-demo/server/src/main/webapp/saas/admin/partials/role-detail.html index 39686d62ad..a2ea839fcd 100755 --- a/examples/as7-eap-demo/server/src/main/webapp/saas/admin/partials/role-detail.html +++ b/examples/as7-eap-demo/server/src/main/webapp/saas/admin/partials/role-detail.html @@ -7,7 +7,7 @@

New Role

- Role {{role.name}} + Realm Role {{role.name}}

Please fill in @@ -49,7 +49,6 @@ - View users » diff --git a/examples/as7-eap-demo/server/src/main/webapp/saas/admin/partials/role-list.html b/examples/as7-eap-demo/server/src/main/webapp/saas/admin/partials/role-list.html index 1693cb1f61..107f6fdfad 100755 --- a/examples/as7-eap-demo/server/src/main/webapp/saas/admin/partials/role-list.html +++ b/examples/as7-eap-demo/server/src/main/webapp/saas/admin/partials/role-list.html @@ -7,7 +7,7 @@ Add Role

- {{realm.realm}} roles + Realm Roles

diff --git a/examples/as7-eap-demo/server/src/main/webapp/saas/realm-login.html b/examples/as7-eap-demo/server/src/main/webapp/saas/realm-login.html deleted file mode 100644 index 3514337086..0000000000 --- a/examples/as7-eap-demo/server/src/main/webapp/saas/realm-login.html +++ /dev/null @@ -1,75 +0,0 @@ - - - - - Log in to Subway - - - - - - - - -

Subway logo

-
-

Log in to Subway

-

Powered by Keycloak

-
- -
-
- - - diff --git a/examples/as7-eap-demo/server/src/main/webapp/saas/realm-register.html b/examples/as7-eap-demo/server/src/main/webapp/saas/realm-register.html deleted file mode 100644 index 0dc054ccea..0000000000 --- a/examples/as7-eap-demo/server/src/main/webapp/saas/realm-register.html +++ /dev/null @@ -1,81 +0,0 @@ - - - - - Register with Subway - - - - - - - - -

Subway logo

-
-

Log in to Subway

-

Powered by Keycloak

-
- -
-
- - - diff --git a/examples/as7-eap-demo/server/src/main/webapp/saas/saas-login.html b/examples/as7-eap-demo/server/src/main/webapp/saas/saas-login.html deleted file mode 100755 index e73d16ebb3..0000000000 --- a/examples/as7-eap-demo/server/src/main/webapp/saas/saas-login.html +++ /dev/null @@ -1,77 +0,0 @@ - - - - - Log in to Keycloak - - - - - - - - -

Red Hat logo

-
-

Log in to Keycloak

-
- -
-
- - - diff --git a/examples/as7-eap-demo/server/src/main/webapp/saas/saas-login.jsp b/examples/as7-eap-demo/server/src/main/webapp/saas/saas-login.jsp index ee004a88ca..e11fc81dfb 100755 --- a/examples/as7-eap-demo/server/src/main/webapp/saas/saas-login.jsp +++ b/examples/as7-eap-demo/server/src/main/webapp/saas/saas-login.jsp @@ -67,7 +67,7 @@

Info area

-

Does not have an account? Register.

+

Does not have an account? Register.

  • Domain: 10.0.0.1
  • Zone: Live
  • diff --git a/examples/as7-eap-demo/server/src/main/webapp/saas/saas-register.html b/examples/as7-eap-demo/server/src/main/webapp/saas/saas-register.html deleted file mode 100644 index 20738c3f0a..0000000000 --- a/examples/as7-eap-demo/server/src/main/webapp/saas/saas-register.html +++ /dev/null @@ -1,80 +0,0 @@ - - - - - Register with Keycloak - - - - - - - - -

    Red Hat logo

    -
    -

    Register with Keycloak

    -
    - -
    -
    - - - diff --git a/examples/as7-eap-demo/server/src/main/webapp/saas/saas-register.jsp b/examples/as7-eap-demo/server/src/main/webapp/saas/saas-register.jsp index ed616486ad..b95d1712ec 100755 --- a/examples/as7-eap-demo/server/src/main/webapp/saas/saas-register.jsp +++ b/examples/as7-eap-demo/server/src/main/webapp/saas/saas-register.jsp @@ -73,7 +73,7 @@

Info area

-

Already have an account? Log in.

+

Already have an account? Log in.

  • Domain: 10.0.0.1
  • Zone: Live
  • diff --git a/sdk-html/src/main/resources/META-INF/resources/sdk/theme/saas/login.xhtml b/sdk-html/src/main/resources/META-INF/resources/sdk/theme/saas/login.xhtml old mode 100644 new mode 100755 index d9618f0520..c1cc3622e6 --- a/sdk-html/src/main/resources/META-INF/resources/sdk/theme/saas/login.xhtml +++ b/sdk-html/src/main/resources/META-INF/resources/sdk/theme/saas/login.xhtml @@ -51,7 +51,7 @@

    Info area

    - Does not have an account? Register. + No account? Register.

    • Domain: 10.0.0.1
    • diff --git a/services/src/main/java/org/keycloak/services/managers/AuthenticationManager.java b/services/src/main/java/org/keycloak/services/managers/AuthenticationManager.java index dc8b79f7e7..02c87eb539 100755 --- a/services/src/main/java/org/keycloak/services/managers/AuthenticationManager.java +++ b/services/src/main/java/org/keycloak/services/managers/AuthenticationManager.java @@ -23,6 +23,7 @@ import javax.ws.rs.core.NewCookie; import javax.ws.rs.core.UriInfo; import java.net.URI; import java.util.HashSet; +import java.util.List; import java.util.Set; /** @@ -203,7 +204,15 @@ public class AuthenticationManager { public boolean authenticateForm(RealmModel realm, UserModel user, MultivaluedMap formData) { Set types = new HashSet(); - for (RequiredCredentialModel credential : realm.getRequiredCredentials()) { + List requiredCredentials = null; + if (realm.hasRole(user, RealmManager.RESOURCE_ROLE)) { + requiredCredentials = realm.getResourceRequiredCredentials(); + } else if (realm.hasRole(user, RealmManager.IDENTITY_REQUESTER_ROLE)) { + requiredCredentials = realm.getOAuthClientRequiredCredentials(); + } else { + requiredCredentials = realm.getRequiredCredentials(); + } + for (RequiredCredentialModel credential : requiredCredentials) { types.add(credential.getType()); } diff --git a/services/src/main/java/org/keycloak/services/managers/RealmManager.java b/services/src/main/java/org/keycloak/services/managers/RealmManager.java index cca17950c9..56d65ca725 100755 --- a/services/src/main/java/org/keycloak/services/managers/RealmManager.java +++ b/services/src/main/java/org/keycloak/services/managers/RealmManager.java @@ -110,6 +110,20 @@ public class RealmManager { } } + if (rep.getRequiredResourceCredentials() != null) { + for (RequiredCredentialRepresentation requiredCred : rep.getRequiredCredentials()) { + addResourceRequiredCredential(newRealm, requiredCred); + } + } + + if (rep.getRequiredOAuthClientCredentials() != null) { + for (RequiredCredentialRepresentation requiredCred : rep.getRequiredCredentials()) { + addOAuthClientRequiredCredential(newRealm, requiredCred); + } + } + + + if (rep.getUsers() != null) { for (UserRepresentation userRep : rep.getUsers()) { UserModel user = createUser(newRealm, userRep); @@ -180,68 +194,42 @@ public class RealmManager { } public void addRequiredCredential(RealmModel newRealm, RequiredCredentialRepresentation requiredCred) { + RequiredCredentialModel credential = initializeCred(requiredCred); + newRealm.addRequiredCredential(credential); + } + public void addResourceRequiredCredential(RealmModel newRealm, RequiredCredentialRepresentation requiredCred) { + RequiredCredentialModel credential = initializeCred(requiredCred); + newRealm.addResourceRequiredCredential(credential); + } + public void addOAuthClientRequiredCredential(RealmModel newRealm, RequiredCredentialRepresentation requiredCred) { + RequiredCredentialModel credential = initializeCred(requiredCred); + newRealm.addOAuthClientRequiredCredential(credential); + } + + + + private RequiredCredentialModel initializeCred(RequiredCredentialRepresentation requiredCred) { RequiredCredentialModel credential = new RequiredCredentialModel(); credential.setType(requiredCred.getType()); credential.setInput(requiredCred.isInput()); credential.setSecret(requiredCred.isSecret()); - newRealm.addRequiredCredential(credential); + return credential; } protected void createResources(RealmRepresentation rep, RealmModel realm) { RoleModel loginRole = realm.getRole(RealmManager.RESOURCE_ROLE); + ResourceManager manager = new ResourceManager(this); for (ResourceRepresentation resourceRep : rep.getResources()) { - createResource(realm, loginRole, resourceRep); + manager.createResource(realm, loginRole, resourceRep); } } - public void createResource(RealmModel realm, RoleModel loginRole, ResourceRepresentation resourceRep) { - ResourceModel resource = realm.addResource(resourceRep.getName()); - resource.setManagementUrl(resourceRep.getAdminUrl()); - resource.setSurrogateAuthRequired(resourceRep.isSurrogateAuthRequired()); - resource.updateResource(); - - UserModel resourceUser = resource.getResourceUser(); - if (resourceRep.getCredentials() != null) { - for (CredentialRepresentation cred : resourceRep.getCredentials()) { - UserCredentialModel credential = new UserCredentialModel(); - credential.setType(cred.getType()); - credential.setValue(cred.getValue()); - realm.updateCredential(resourceUser, credential); - } - } - realm.grantRole(resourceUser, loginRole); - - - if (resourceRep.getRoles() != null) { - for (RoleRepresentation roleRep : resourceRep.getRoles()) { - RoleModel role = resource.addRole(roleRep.getName()); - if (roleRep.getDescription() != null) role.setDescription(roleRep.getDescription()); - } - } - if (resourceRep.getRoleMappings() != null) { - for (RoleMappingRepresentation mapping : resourceRep.getRoleMappings()) { - UserModel user = realm.getUser(mapping.getUsername()); - for (String roleString : mapping.getRoles()) { - RoleModel role = resource.getRole(roleString.trim()); - if (role == null) { - role = resource.addRole(roleString.trim()); - } - realm.grantRole(user, role); - } - } - } - if (resourceRep.getScopeMappings() != null) { - for (ScopeMappingRepresentation mapping : resourceRep.getScopeMappings()) { - UserModel user = realm.getUser(mapping.getUsername()); - for (String roleString : mapping.getRoles()) { - RoleModel role = resource.getRole(roleString.trim()); - if (role == null) { - role = resource.addRole(roleString.trim()); - } - resource.addScope(user, role.getName()); - } - } - } - if (resourceRep.isUseRealmMappings()) realm.addScope(resource.getResourceUser(), "*"); + public RoleRepresentation toRepresentation(RoleModel role) { + RoleRepresentation rep = new RoleRepresentation(); + rep.setId(role.getId()); + rep.setName(role.getName()); + rep.setDescription(role.getDescription()); + return rep; } + } diff --git a/services/src/main/java/org/keycloak/services/managers/ResourceManager.java b/services/src/main/java/org/keycloak/services/managers/ResourceManager.java new file mode 100755 index 0000000000..e1c2ebbd21 --- /dev/null +++ b/services/src/main/java/org/keycloak/services/managers/ResourceManager.java @@ -0,0 +1,105 @@ +package org.keycloak.services.managers; + +import org.keycloak.representations.idm.CredentialRepresentation; +import org.keycloak.representations.idm.ResourceRepresentation; +import org.keycloak.representations.idm.RoleMappingRepresentation; +import org.keycloak.representations.idm.RoleRepresentation; +import org.keycloak.representations.idm.ScopeMappingRepresentation; +import org.keycloak.services.models.RealmModel; +import org.keycloak.services.models.ResourceModel; +import org.keycloak.services.models.RoleModel; +import org.keycloak.services.models.UserCredentialModel; +import org.keycloak.services.models.UserModel; + +import java.util.List; + +/** + * @author Bill Burke + * @version $Revision: 1 $ + */ +public class ResourceManager { + + protected RealmManager realmManager; + + public ResourceManager(RealmManager realmManager) { + this.realmManager = realmManager; + } + + public ResourceModel createResource(RealmModel realm, RoleModel loginRole, ResourceRepresentation resourceRep) { + ResourceModel resource = realm.addResource(resourceRep.getName()); + resource.setEnabled(resourceRep.isEnabled()); + resource.setManagementUrl(resourceRep.getAdminUrl()); + resource.setSurrogateAuthRequired(resourceRep.isSurrogateAuthRequired()); + resource.updateResource(); + + UserModel resourceUser = resource.getResourceUser(); + if (resourceRep.getCredentials() != null) { + for (CredentialRepresentation cred : resourceRep.getCredentials()) { + UserCredentialModel credential = new UserCredentialModel(); + credential.setType(cred.getType()); + credential.setValue(cred.getValue()); + realm.updateCredential(resourceUser, credential); + } + } + realm.grantRole(resourceUser, loginRole); + + + if (resourceRep.getRoles() != null) { + for (RoleRepresentation roleRep : resourceRep.getRoles()) { + RoleModel role = resource.addRole(roleRep.getName()); + if (roleRep.getDescription() != null) role.setDescription(roleRep.getDescription()); + } + } + if (resourceRep.getRoleMappings() != null) { + for (RoleMappingRepresentation mapping : resourceRep.getRoleMappings()) { + UserModel user = realm.getUser(mapping.getUsername()); + for (String roleString : mapping.getRoles()) { + RoleModel role = resource.getRole(roleString.trim()); + if (role == null) { + role = resource.addRole(roleString.trim()); + } + realm.grantRole(user, role); + } + } + } + if (resourceRep.getScopeMappings() != null) { + for (ScopeMappingRepresentation mapping : resourceRep.getScopeMappings()) { + UserModel user = realm.getUser(mapping.getUsername()); + for (String roleString : mapping.getRoles()) { + RoleModel role = resource.getRole(roleString.trim()); + if (role == null) { + role = resource.addRole(roleString.trim()); + } + resource.addScope(user, role.getName()); + } + } + } + if (resourceRep.isUseRealmMappings()) realm.addScope(resource.getResourceUser(), "*"); + return resource; + } + + public ResourceModel createResource(RealmModel realm, ResourceRepresentation resourceRep) { + RoleModel loginRole = realm.getRole(RealmManager.RESOURCE_ROLE); + return createResource(realm, loginRole, resourceRep); + } + + public void updateResource(ResourceRepresentation rep, ResourceModel resource) { + resource.setName(rep.getName()); + resource.setEnabled(rep.isEnabled()); + resource.setManagementUrl(rep.getAdminUrl()); + resource.setSurrogateAuthRequired(rep.isSurrogateAuthRequired()); + resource.updateResource(); + + } + + public ResourceRepresentation toRepresentation(ResourceModel resourceModel) { + ResourceRepresentation rep = new ResourceRepresentation(); + rep.setId(resourceModel.getId()); + rep.setName(resourceModel.getName()); + rep.setEnabled(resourceModel.isEnabled()); + rep.setAdminUrl(resourceModel.getManagementUrl()); + rep.setSurrogateAuthRequired(resourceModel.isSurrogateAuthRequired()); + return rep; + + } +} diff --git a/services/src/main/java/org/keycloak/services/managers/TokenManager.java b/services/src/main/java/org/keycloak/services/managers/TokenManager.java index 121de14c37..6072c51c3e 100755 --- a/services/src/main/java/org/keycloak/services/managers/TokenManager.java +++ b/services/src/main/java/org/keycloak/services/managers/TokenManager.java @@ -9,14 +9,10 @@ import org.keycloak.services.models.RealmModel; import org.keycloak.services.models.ResourceModel; import org.keycloak.services.models.RoleModel; import org.keycloak.services.models.UserModel; -import org.keycloak.services.resources.RealmsResource; import javax.ws.rs.core.MultivaluedMap; -import javax.ws.rs.core.NewCookie; -import javax.ws.rs.core.UriInfo; import java.io.IOException; import java.io.UnsupportedEncodingException; -import java.net.URI; import java.util.List; import java.util.Map; import java.util.Set; @@ -135,7 +131,7 @@ public class TokenManager { } if (accessCodeEntry.getResourceRolesRequested().size() > 0) { - Map resourceMap = realm.getResourceMap(); + Map resourceMap = realm.getResourceNameMap(); for (String resourceName : accessCodeEntry.getResourceRolesRequested().keySet()) { ResourceModel resource = resourceMap.get(resourceName); SkeletonKeyToken.Access access = token.addAccess(resourceName).verifyCaller(resource.isSurrogateAuthRequired()); diff --git a/services/src/main/java/org/keycloak/services/models/RealmModel.java b/services/src/main/java/org/keycloak/services/models/RealmModel.java index abb7e1d112..404f83767d 100755 --- a/services/src/main/java/org/keycloak/services/models/RealmModel.java +++ b/services/src/main/java/org/keycloak/services/models/RealmModel.java @@ -79,7 +79,7 @@ public interface RealmModel { List getRoles(); - Map getResourceMap(); + Map getResourceNameMap(); List getResources(); @@ -100,4 +100,16 @@ public interface RealmModel { void addRealmAdmin(UserModel agent); RoleModel getRoleById(String id); + + void addResourceRequiredCredential(RequiredCredentialModel cred); + + List getResourceRequiredCredentials(); + + void addOAuthClientRequiredCredential(RequiredCredentialModel cred); + + List getOAuthClientRequiredCredentials(); + + boolean hasRole(UserModel user, String role); + + ResourceModel getResourceById(String id); } diff --git a/services/src/main/java/org/keycloak/services/models/picketlink/RealmAdapter.java b/services/src/main/java/org/keycloak/services/models/picketlink/RealmAdapter.java index bb7c2b2274..fe023f7c9d 100755 --- a/services/src/main/java/org/keycloak/services/models/picketlink/RealmAdapter.java +++ b/services/src/main/java/org/keycloak/services/models/picketlink/RealmAdapter.java @@ -13,9 +13,11 @@ import org.keycloak.services.models.UserCredentialModel; import org.keycloak.services.models.UserModel; import org.keycloak.services.models.picketlink.mappings.RealmData; import org.keycloak.services.models.picketlink.mappings.ResourceData; +import org.keycloak.services.models.picketlink.relationships.OAuthClientRequiredCredentialRelationship; import org.keycloak.services.models.picketlink.relationships.RealmAdminRelationship; import org.keycloak.services.models.picketlink.relationships.RequiredCredentialRelationship; import org.keycloak.services.models.picketlink.relationships.ResourceRelationship; +import org.keycloak.services.models.picketlink.relationships.ResourceRequiredCredentialRelationship; import org.keycloak.services.models.picketlink.relationships.ScopeRelationship; import org.picketlink.idm.IdentityManager; import org.picketlink.idm.PartitionManager; @@ -252,6 +254,48 @@ public class RealmAdapter implements RealmModel { RelationshipQuery query = getRelationshipManager().createRelationshipQuery(RequiredCredentialRelationship.class); query.setParameter(RequiredCredentialRelationship.REALM, realm.getName()); List results = query.getResultList(); + return getRequiredCredentialModels(results); + } + + + @Override + public void addResourceRequiredCredential(RequiredCredentialModel cred) { + ResourceRequiredCredentialRelationship relationship = new ResourceRequiredCredentialRelationship(); + addRequiredCredential(cred, relationship); + } + + @Override + public List getResourceRequiredCredentials() { + RelationshipQuery query = getRelationshipManager().createRelationshipQuery(ResourceRequiredCredentialRelationship.class); + query.setParameter(ResourceRequiredCredentialRelationship.REALM, realm.getName()); + List results = query.getResultList(); + return getRequiredCredentialModels(results); + } + + @Override + public void addOAuthClientRequiredCredential(RequiredCredentialModel cred) { + OAuthClientRequiredCredentialRelationship relationship = new OAuthClientRequiredCredentialRelationship(); + addRequiredCredential(cred, relationship); + } + + @Override + public List getOAuthClientRequiredCredentials() { + RelationshipQuery query = getRelationshipManager().createRelationshipQuery(OAuthClientRequiredCredentialRelationship.class); + query.setParameter(ResourceRequiredCredentialRelationship.REALM, realm.getName()); + List results = query.getResultList(); + return getRequiredCredentialModels(results); + } + + + + @Override + public void addRequiredCredential(RequiredCredentialModel cred) { + RequiredCredentialRelationship relationship = new RequiredCredentialRelationship(); + addRequiredCredential(cred, relationship); + } + + + protected List getRequiredCredentialModels(List results) { List rtn = new ArrayList(); for (RequiredCredentialRelationship relationship : results) { RequiredCredentialModel model = new RequiredCredentialModel(); @@ -262,10 +306,7 @@ public class RealmAdapter implements RealmModel { } return rtn; } - - @Override - public void addRequiredCredential(RequiredCredentialModel cred) { - RequiredCredentialRelationship relationship = new RequiredCredentialRelationship(); + protected void addRequiredCredential(RequiredCredentialModel cred, RequiredCredentialRelationship relationship) { relationship.setCredentialType(cred.getType()); relationship.setInput(cred.isInput()); relationship.setSecret(cred.isSecret()); @@ -375,7 +416,7 @@ public class RealmAdapter implements RealmModel { * @return */ @Override - public Map getResourceMap() { + public Map getResourceNameMap() { Map resourceMap = new HashMap(); for (ResourceModel resource : getResources()) { resourceMap.put(resource.getName(), resource); @@ -383,6 +424,24 @@ public class RealmAdapter implements RealmModel { return resourceMap; } + /** + * Makes sure that the resource returned is owned by the realm + * + * @return + */ + @Override + public ResourceModel getResourceById(String id) { + RelationshipQuery query = getRelationshipManager().createRelationshipQuery(ResourceRelationship.class); + query.setParameter(ResourceRelationship.REALM, realm.getName()); + query.setParameter(ResourceRelationship.RESOURCE, id); + List results = query.getResultList(); + if (results.size() == 0) return null; + ResourceData resource = partitionManager.getPartition(ResourceData.class, id); + ResourceModel model = new ResourceAdapter(resource, this, partitionManager); + return model; + } + + @Override public List getResources() { RelationshipQuery query = getRelationshipManager().createRelationshipQuery(ResourceRelationship.class); @@ -422,6 +481,13 @@ public class RealmAdapter implements RealmModel { return SampleModel.hasRole(getRelationshipManager(), ((UserAdapter) user).getUser(), ((RoleAdapter) role).getRole()); } + @Override + public boolean hasRole(UserModel user, String role) { + RoleModel roleModel = getRole(role); + return hasRole(user, roleModel); + } + + @Override public void grantRole(UserModel user, RoleModel role) { SampleModel.grantRole(getRelationshipManager(), ((UserAdapter) user).getUser(), ((RoleAdapter) role).getRole()); diff --git a/services/src/main/java/org/keycloak/services/models/picketlink/relationships/OAuthClientRequiredCredentialRelationship.java b/services/src/main/java/org/keycloak/services/models/picketlink/relationships/OAuthClientRequiredCredentialRelationship.java new file mode 100755 index 0000000000..f14c808243 --- /dev/null +++ b/services/src/main/java/org/keycloak/services/models/picketlink/relationships/OAuthClientRequiredCredentialRelationship.java @@ -0,0 +1,8 @@ +package org.keycloak.services.models.picketlink.relationships; + +/** + * @author Bill Burke + * @version $Revision: 1 $ + */ +public class OAuthClientRequiredCredentialRelationship extends RequiredCredentialRelationship { +} diff --git a/services/src/main/java/org/keycloak/services/models/picketlink/relationships/ResourceRelationship.java b/services/src/main/java/org/keycloak/services/models/picketlink/relationships/ResourceRelationship.java index 429ea2557d..3c48b97788 100755 --- a/services/src/main/java/org/keycloak/services/models/picketlink/relationships/ResourceRelationship.java +++ b/services/src/main/java/org/keycloak/services/models/picketlink/relationships/ResourceRelationship.java @@ -14,6 +14,7 @@ public class ResourceRelationship extends AbstractAttributedType implements Rela private static final long serialVersionUID = 1L; public static final AttributeParameter REALM = new AttributeParameter("realm"); + public static final AttributeParameter RESOURCE = new AttributeParameter("resource"); public ResourceRelationship() { } diff --git a/services/src/main/java/org/keycloak/services/models/picketlink/relationships/ResourceRequiredCredentialRelationship.java b/services/src/main/java/org/keycloak/services/models/picketlink/relationships/ResourceRequiredCredentialRelationship.java new file mode 100755 index 0000000000..5df352ef02 --- /dev/null +++ b/services/src/main/java/org/keycloak/services/models/picketlink/relationships/ResourceRequiredCredentialRelationship.java @@ -0,0 +1,8 @@ +package org.keycloak.services.models.picketlink.relationships; + +/** + * @author Bill Burke + * @version $Revision: 1 $ + */ +public class ResourceRequiredCredentialRelationship extends RequiredCredentialRelationship { +} diff --git a/services/src/main/java/org/keycloak/services/resources/PublicRealmResource.java b/services/src/main/java/org/keycloak/services/resources/PublicRealmResource.java index bef77ff8ed..ab12f38295 100755 --- a/services/src/main/java/org/keycloak/services/resources/PublicRealmResource.java +++ b/services/src/main/java/org/keycloak/services/resources/PublicRealmResource.java @@ -1,5 +1,6 @@ package org.keycloak.services.resources; +import org.jboss.resteasy.annotations.cache.NoCache; import org.jboss.resteasy.logging.Logger; import org.keycloak.representations.idm.PublishedRealmRepresentation; import org.keycloak.services.models.KeycloakSession; @@ -37,6 +38,7 @@ public class PublicRealmResource { } @GET + @NoCache @Produces("application/json") public PublishedRealmRepresentation getRealm(@PathParam("realm") String id) { return new Transaction() { @@ -47,6 +49,7 @@ public class PublicRealmResource { } @GET + @NoCache @Path("html") @Produces("text/html") public String getRealmHtml(@PathParam("realm") String id) { diff --git a/services/src/main/java/org/keycloak/services/resources/TokenService.java b/services/src/main/java/org/keycloak/services/resources/TokenService.java index ba4d2656d1..4f295fefca 100755 --- a/services/src/main/java/org/keycloak/services/resources/TokenService.java +++ b/services/src/main/java/org/keycloak/services/resources/TokenService.java @@ -1,5 +1,6 @@ package org.keycloak.services.resources; +import org.jboss.resteasy.annotations.cache.NoCache; import org.jboss.resteasy.jose.jws.JWSBuilder; import org.jboss.resteasy.jose.jws.JWSInput; import org.jboss.resteasy.jose.jws.crypto.RSAProvider; @@ -381,6 +382,7 @@ public class TokenService extends AbstractLoginService { @Path("logout") @GET + @NoCache public Response logout(final @QueryParam("redirect_uri") String redirectUri) { return new Transaction() { protected Response callImpl() { diff --git a/services/src/main/java/org/keycloak/services/resources/admin/RealmAdminResource.java b/services/src/main/java/org/keycloak/services/resources/admin/RealmAdminResource.java index 255d59ad49..bf2a7caa33 100755 --- a/services/src/main/java/org/keycloak/services/resources/admin/RealmAdminResource.java +++ b/services/src/main/java/org/keycloak/services/resources/admin/RealmAdminResource.java @@ -1,5 +1,6 @@ package org.keycloak.services.resources.admin; +import org.jboss.resteasy.annotations.cache.NoCache; import org.jboss.resteasy.logging.Logger; import org.keycloak.representations.idm.RealmRepresentation; import org.keycloak.representations.idm.RoleRepresentation; @@ -47,7 +48,13 @@ public class RealmAdminResource { this.realm = realm; } + @Path("resources") + public RealmResourcesResource getResources() { + return new RealmResourcesResource(admin, realm); + } + @GET + @NoCache @Produces("application/json") public RealmRepresentation getRealm() { return new Transaction() { @@ -70,6 +77,7 @@ public class RealmAdminResource { @Path("roles") @GET + @NoCache @Produces("application/json") public List getRoles() { return new Transaction() { @@ -88,6 +96,7 @@ public class RealmAdminResource { @Path("roles/{id}") @GET + @NoCache @Produces("application/json") public RoleRepresentation getRole(final @PathParam("id") String id) { return new Transaction() { @@ -147,6 +156,7 @@ public class RealmAdminResource { @Path("users") @GET + @NoCache @Produces("application/json") public List getUsers() { return null; diff --git a/services/src/main/java/org/keycloak/services/resources/admin/RealmResourceResource.java b/services/src/main/java/org/keycloak/services/resources/admin/RealmResourceResource.java new file mode 100755 index 0000000000..5f91f64ed6 --- /dev/null +++ b/services/src/main/java/org/keycloak/services/resources/admin/RealmResourceResource.java @@ -0,0 +1,69 @@ +package org.keycloak.services.resources.admin; + +import org.jboss.resteasy.annotations.cache.NoCache; +import org.jboss.resteasy.logging.Logger; +import org.keycloak.representations.idm.ResourceRepresentation; +import org.keycloak.services.managers.RealmManager; +import org.keycloak.services.managers.ResourceManager; +import org.keycloak.services.models.RealmModel; +import org.keycloak.services.models.ResourceModel; +import org.keycloak.services.models.UserModel; +import org.keycloak.services.resources.Transaction; + +import javax.ws.rs.Consumes; +import javax.ws.rs.GET; +import javax.ws.rs.NotFoundException; +import javax.ws.rs.POST; +import javax.ws.rs.PUT; +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.MediaType; +import javax.ws.rs.core.Response; +import javax.ws.rs.core.UriInfo; +import java.util.ArrayList; +import java.util.List; + +/** + * @author Bill Burke + * @version $Revision: 1 $ + */ +public class RealmResourceResource { + protected static final Logger logger = Logger.getLogger(RealmAdminResource.class); + protected UserModel admin; + protected RealmModel realm; + protected ResourceModel resourceModel; + + public RealmResourceResource(UserModel admin, RealmModel realm, ResourceModel resourceModel) { + this.admin = admin; + this.realm = realm; + this.resourceModel = resourceModel; + } + + @PUT + @Consumes(MediaType.APPLICATION_JSON) + public void update(final ResourceRepresentation rep) { + new Transaction() { + @Override + protected void runImpl() { + ResourceManager resourceManager = new ResourceManager(new RealmManager(session)); + resourceManager.updateResource(rep, resourceModel); + } + }.run(); + } + + + @GET + @NoCache + @Produces(MediaType.APPLICATION_JSON) + public ResourceRepresentation getResource(final @PathParam("id") String id) { + return new Transaction() { + @Override + protected ResourceRepresentation callImpl() { + ResourceManager resourceManager = new ResourceManager(new RealmManager(session)); + return resourceManager.toRepresentation(resourceModel); + } + }.call(); + } +} diff --git a/services/src/main/java/org/keycloak/services/resources/admin/RealmResourcesResource.java b/services/src/main/java/org/keycloak/services/resources/admin/RealmResourcesResource.java new file mode 100755 index 0000000000..99e69db13d --- /dev/null +++ b/services/src/main/java/org/keycloak/services/resources/admin/RealmResourcesResource.java @@ -0,0 +1,88 @@ +package org.keycloak.services.resources.admin; + +import org.jboss.resteasy.annotations.cache.NoCache; +import org.jboss.resteasy.logging.Logger; +import org.keycloak.representations.idm.ResourceRepresentation; +import org.keycloak.services.managers.RealmManager; +import org.keycloak.services.managers.ResourceManager; +import org.keycloak.services.models.RealmModel; +import org.keycloak.services.models.ResourceModel; +import org.keycloak.services.models.UserModel; +import org.keycloak.services.resources.Transaction; + +import javax.ws.rs.Consumes; +import javax.ws.rs.GET; +import javax.ws.rs.NotFoundException; +import javax.ws.rs.POST; +import javax.ws.rs.PUT; +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.MediaType; +import javax.ws.rs.core.Response; +import javax.ws.rs.core.UriInfo; +import java.util.ArrayList; +import java.util.List; + +/** + * @author Bill Burke + * @version $Revision: 1 $ + */ +public class RealmResourcesResource { + protected static final Logger logger = Logger.getLogger(RealmAdminResource.class); + protected UserModel admin; + protected RealmModel realm; + + public RealmResourcesResource(UserModel admin, RealmModel realm) { + this.admin = admin; + this.realm = realm; + } + + @GET + @Produces(MediaType.APPLICATION_JSON) + @NoCache + public List getResources() { + return new Transaction() { + @Override + protected List callImpl() { + List rep = new ArrayList(); + List resourceModels = realm.getResources(); + ResourceManager resourceManager = new ResourceManager(new RealmManager(session)); + for (ResourceModel resourceModel : resourceModels) { + rep.add(resourceManager.toRepresentation(resourceModel)); + } + return rep; + } + }.call(); + } + + @POST + @Consumes(MediaType.APPLICATION_JSON) + public Response createResource(final @Context UriInfo uriInfo, final ResourceRepresentation rep) { + return new Transaction() { + @Override + protected Response callImpl() { + ResourceManager resourceManager = new ResourceManager(new RealmManager(session)); + ResourceModel resourceModel = resourceManager.createResource(realm, rep); + return Response.created(uriInfo.getAbsolutePathBuilder().path(resourceModel.getId()).build()).build(); + } + }.call(); + } + + @Path("{id}") + public RealmResourceResource getResource(final @PathParam("id") String id) { + return new Transaction() { + @Override + protected RealmResourceResource callImpl() { + ResourceModel resourceModel = realm.getResourceById(id); + if (resourceModel == null) { + throw new NotFoundException(); + } + return new RealmResourceResource(admin, realm, resourceModel); + } + }.call(); + + } + +} diff --git a/services/src/main/java/org/keycloak/services/resources/admin/RealmsAdminResource.java b/services/src/main/java/org/keycloak/services/resources/admin/RealmsAdminResource.java index 7980877405..015f150d98 100755 --- a/services/src/main/java/org/keycloak/services/resources/admin/RealmsAdminResource.java +++ b/services/src/main/java/org/keycloak/services/resources/admin/RealmsAdminResource.java @@ -1,5 +1,6 @@ package org.keycloak.services.resources.admin; +import org.jboss.resteasy.annotations.cache.NoCache; import org.jboss.resteasy.logging.Logger; import org.keycloak.representations.idm.RealmRepresentation; import org.keycloak.services.managers.RealmManager; @@ -49,6 +50,7 @@ public class RealmsAdminResource { } @GET + @NoCache @Produces("application/json") public Response getRealms() { return new Transaction() { diff --git a/services/src/test/resources/testrealm.json b/services/src/test/resources/testrealm.json index a8d0cbf067..72390867d9 100755 --- a/services/src/test/resources/testrealm.json +++ b/services/src/test/resources/testrealm.json @@ -10,6 +10,20 @@ "secret" : true } ], + "requiredResourceCredentials" : [ + { + "type" : "Password", + "input" : true, + "secret" : true + } + ], + "requiredOAuthClientCredentials" : [ + { + "type" : "Password", + "input" : true, + "secret" : true + } + ], "users" : [ { "username" : "wburke", @@ -62,6 +76,7 @@ "resources" : [ { "name" : "Application", + "enabled" : true, "roles" : [ { "name" : "admin" }, { "name" : "user" } @@ -83,8 +98,9 @@ } ] }, - { + { "name" : "OtherApp", + "enabled" : true, "roles" : [ { "name" : "admin" }, { "name" : "user" }