From 1586f461bef88721a42e866dcbd8a4e8abbf9ce0 Mon Sep 17 00:00:00 2001 From: Bill Burke Date: Fri, 5 Jul 2013 14:23:16 -0400 Subject: [PATCH] more --- .../java/org/keycloak/RSATokenVerifier.java | 6 +- .../idm/PublishedRealmRepresentation.java | 13 + .../idm/RealmRepresentation.java | 12 + .../idm/RoleMappingRepresentation.java | 19 - .../services/IdentityManagerAdapter.java | 84 ----- .../AuthenticationManager.java | 53 ++- .../{service => managers}/TokenManager.java | 8 +- .../services/model/data/RealmModel.java | 194 ---------- .../model/data/RequiredCredentialModel.java | 58 --- .../services/model/data/ResourceModel.java | 46 --- .../services/model/data/RoleMappingModel.java | 59 --- .../services/model/data/RoleModel.java | 35 -- .../model/data/ScopeMappingModel.java | 49 --- .../model/data/UserAttributeModel.java | 46 --- .../model/data/UserCredentialModel.java | 58 --- .../services/model/data/UserModel.java | 46 --- .../{model => models}/RealmManager.java | 2 +- .../{model => models}/RealmModel.java | 25 +- .../RequiredCredentialModel.java | 2 +- .../{model => models}/ResourceModel.java | 7 +- .../UserCredentialModel.java | 2 +- .../relationships/RealmAdminRelationship.java | 58 +++ .../RealmResourceRelationship.java | 2 +- .../RequiredCredentialRelationship.java | 2 +- .../relationships}/ScopeRelationship.java | 2 +- .../services/resources/RealmFactory.java | 343 +++++++++++++++++ .../{service => resources}/RealmResource.java | 78 ++-- .../RegistrationService.java | 12 +- .../SkeletonKeyApplication.java | 4 +- .../{service => resources}/TokenService.java | 18 +- .../services/service/RealmFactory.java | 354 ------------------ .../java/org/keycloak/test/AdapterTest.java | 14 +- 32 files changed, 562 insertions(+), 1149 deletions(-) delete mode 100755 services/src/main/java/org/keycloak/services/IdentityManagerAdapter.java rename services/src/main/java/org/keycloak/services/{service => managers}/AuthenticationManager.java (57%) rename services/src/main/java/org/keycloak/services/{service => managers}/TokenManager.java (93%) delete mode 100755 services/src/main/java/org/keycloak/services/model/data/RealmModel.java delete mode 100755 services/src/main/java/org/keycloak/services/model/data/RequiredCredentialModel.java delete mode 100755 services/src/main/java/org/keycloak/services/model/data/ResourceModel.java delete mode 100755 services/src/main/java/org/keycloak/services/model/data/RoleMappingModel.java delete mode 100755 services/src/main/java/org/keycloak/services/model/data/RoleModel.java delete mode 100755 services/src/main/java/org/keycloak/services/model/data/ScopeMappingModel.java delete mode 100755 services/src/main/java/org/keycloak/services/model/data/UserAttributeModel.java delete mode 100755 services/src/main/java/org/keycloak/services/model/data/UserCredentialModel.java delete mode 100755 services/src/main/java/org/keycloak/services/model/data/UserModel.java rename services/src/main/java/org/keycloak/services/{model => models}/RealmManager.java (93%) rename services/src/main/java/org/keycloak/services/{model => models}/RealmModel.java (89%) rename services/src/main/java/org/keycloak/services/{model => models}/RequiredCredentialModel.java (88%) rename services/src/main/java/org/keycloak/services/{model => models}/ResourceModel.java (97%) rename services/src/main/java/org/keycloak/services/{model => models}/UserCredentialModel.java (92%) create mode 100755 services/src/main/java/org/keycloak/services/models/relationships/RealmAdminRelationship.java rename services/src/main/java/org/keycloak/services/{model => models/relationships}/RealmResourceRelationship.java (92%) rename services/src/main/java/org/keycloak/services/{model => models/relationships}/RequiredCredentialRelationship.java (92%) rename services/src/main/java/org/keycloak/services/{model => models/relationships}/ScopeRelationship.java (91%) create mode 100755 services/src/main/java/org/keycloak/services/resources/RealmFactory.java rename services/src/main/java/org/keycloak/services/{service => resources}/RealmResource.java (57%) rename services/src/main/java/org/keycloak/services/{service => resources}/RegistrationService.java (77%) rename services/src/main/java/org/keycloak/services/{service => resources}/SkeletonKeyApplication.java (89%) rename services/src/main/java/org/keycloak/services/{service => resources}/TokenService.java (94%) delete mode 100755 services/src/main/java/org/keycloak/services/service/RealmFactory.java diff --git a/core/src/main/java/org/keycloak/RSATokenVerifier.java b/core/src/main/java/org/keycloak/RSATokenVerifier.java index 92c23c8704..7b4b2a0976 100755 --- a/core/src/main/java/org/keycloak/RSATokenVerifier.java +++ b/core/src/main/java/org/keycloak/RSATokenVerifier.java @@ -18,7 +18,11 @@ public class RSATokenVerifier { PublicKey realmKey = metadata.getRealmKey(); String realm = metadata.getRealm(); - String resource = metadata.getResourceName(); + return verifyToken(tokenString, realmKey, realm); + } + + public static SkeletonKeyToken verifyToken(String tokenString, PublicKey realmKey, String realm) throws VerificationException + { JWSInput input = new JWSInput(tokenString); boolean verified = false; try diff --git a/core/src/main/java/org/keycloak/representations/idm/PublishedRealmRepresentation.java b/core/src/main/java/org/keycloak/representations/idm/PublishedRealmRepresentation.java index 76933637c9..11050e964a 100755 --- a/core/src/main/java/org/keycloak/representations/idm/PublishedRealmRepresentation.java +++ b/core/src/main/java/org/keycloak/representations/idm/PublishedRealmRepresentation.java @@ -30,6 +30,9 @@ public class PublishedRealmRepresentation @JsonProperty("grants") protected String grantUrl; + @JsonProperty("identity-grants") + protected String identityGrantUrl; + @JsonIgnore protected volatile transient PublicKey publicKey; @@ -133,4 +136,14 @@ public class PublishedRealmRepresentation { this.grantUrl = grantUrl; } + + public String getIdentityGrantUrl() + { + return identityGrantUrl; + } + + public void setIdentityGrantUrl(String identityGrantUrl) + { + this.identityGrantUrl = identityGrantUrl; + } } 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 17a1bb2dde..166447cbdd 100755 --- a/core/src/main/java/org/keycloak/representations/idm/RealmRepresentation.java +++ b/core/src/main/java/org/keycloak/representations/idm/RealmRepresentation.java @@ -2,6 +2,7 @@ package org.keycloak.representations.idm; import java.util.ArrayList; import java.util.List; +import java.util.Set; /** * @author Bill Burke @@ -16,6 +17,7 @@ public class RealmRepresentation protected boolean enabled; protected boolean sslNotRequired; protected boolean cookieLoginAllowed; + protected Set roles; protected List requiredCredentials; protected List users; protected List roleMappings; @@ -168,4 +170,14 @@ public class RealmRepresentation { this.accessCodeLifespan = accessCodeLifespan; } + + public Set getRoles() + { + return roles; + } + + public void setRoles(Set roles) + { + this.roles = roles; + } } diff --git a/core/src/main/java/org/keycloak/representations/idm/RoleMappingRepresentation.java b/core/src/main/java/org/keycloak/representations/idm/RoleMappingRepresentation.java index 05915c1909..aca2206581 100755 --- a/core/src/main/java/org/keycloak/representations/idm/RoleMappingRepresentation.java +++ b/core/src/main/java/org/keycloak/representations/idm/RoleMappingRepresentation.java @@ -14,7 +14,6 @@ public class RoleMappingRepresentation protected String self; // link protected String username; protected Set roles; - protected Set surrogates; public String getSelf() { @@ -41,24 +40,6 @@ public class RoleMappingRepresentation return roles; } - public Set getSurrogates() - { - return surrogates; - } - - public void setSurrogates(Set surrogates) - { - this.surrogates = surrogates; - } - - public RoleMappingRepresentation surrogate(String surrogate) - { - if (this.surrogates == null) this.surrogates = new HashSet(); - this.surrogates.add(surrogate); - return this; - } - - public void setRoles(Set roles) { this.roles = roles; diff --git a/services/src/main/java/org/keycloak/services/IdentityManagerAdapter.java b/services/src/main/java/org/keycloak/services/IdentityManagerAdapter.java deleted file mode 100755 index 0df74ffab1..0000000000 --- a/services/src/main/java/org/keycloak/services/IdentityManagerAdapter.java +++ /dev/null @@ -1,84 +0,0 @@ -package org.keycloak.services; - -import org.keycloak.services.model.data.RealmModel; -import org.keycloak.services.model.data.RequiredCredentialModel; -import org.keycloak.services.model.data.ResourceModel; -import org.keycloak.services.model.data.RoleMappingModel; -import org.keycloak.services.model.data.RoleModel; -import org.keycloak.services.model.data.ScopeMappingModel; -import org.keycloak.services.model.data.UserAttributeModel; -import org.keycloak.services.model.data.UserCredentialModel; -import org.keycloak.services.model.data.UserModel; - -import java.util.List; - -/** - * @author Bill Burke - * @version $Revision: 1 $ - */ -@Deprecated -public interface IdentityManagerAdapter -{ - RealmModel getRealm(String id); - RealmModel create(RealmModel realm); - void update(RealmModel realm); - void delete(RealmModel realm); - List getRequiredCredentials(RealmModel realm); - RequiredCredentialModel getRealmCredential(String id); - RequiredCredentialModel create(RealmModel realm, RequiredCredentialModel cred); - void update(RequiredCredentialModel cred); - void delete(RequiredCredentialModel cred); - - UserModel getUser(RealmModel realm, String username); - UserModel create(RealmModel realm, UserModel user); - void update(RealmModel realm, UserModel user); - void delete(RealmModel realm,UserModel user); - - List getCredentials(UserModel user); - UserCredentialModel getCredential(String id); - UserCredentialModel create(UserModel user, UserCredentialModel cred); - void update(UserCredentialModel cred); - void delete(UserCredentialModel cred); - - UserAttributeModel getUserAttribute(String id); - UserAttributeModel create(UserModel user, UserAttributeModel attribute); - void update(UserAttributeModel attribute); - void delete(UserAttributeModel attribute); - - ResourceModel getResource(String resourceid); - List getResources(RealmModel realm); - ResourceModel create(RealmModel realm, ResourceModel resource); - void update(ResourceModel resource); - void delete(ResourceModel resource); - - - RoleModel getRoleByName(RealmModel realm, String roleName); - RoleModel getRoleByName(ResourceModel resource, String roleName); - List getRoles(RealmModel realm, ResourceModel resource); - List getRoles(RealmModel realm); - RoleModel getRole(String id); - RoleModel create(RealmModel realm, ResourceModel resource, String role); - RoleModel create(RealmModel realm, String role); - void delete(RoleModel role); - - List getRoleMappings(RealmModel realm); - List getRoleMappings(RealmModel realm, ResourceModel resource); - RoleMappingModel getRoleMapping(RealmModel realm, UserModel user); - RoleMappingModel getRoleMapping(RealmModel realm, ResourceModel resource, UserModel user); - RoleMappingModel getRoleMapping(String id); - RoleMappingModel create(RealmModel realm, UserModel user, RoleMappingModel mapping); - RoleMappingModel create(RealmModel realm, ResourceModel resource, UserModel user, RoleMappingModel mapping); - void delete(RoleMappingModel role); - - List getScopeMappings(RealmModel realm); - List getScopeMappings(RealmModel realm, ResourceModel resource); - ScopeMappingModel getScopeMapping(RealmModel realm, UserModel user); - ScopeMappingModel getScopeMapping(RealmModel realm, ResourceModel resource, UserModel user); - ScopeMappingModel getScopeMapping(String id); - ScopeMappingModel create(RealmModel realm, UserModel user, ScopeMappingModel mapping); - ScopeMappingModel create(RealmModel realm, ResourceModel resource, UserModel user, ScopeMappingModel mapping); - void delete(ScopeMappingModel scope); - - - List getRealmsByName(String name); -} diff --git a/services/src/main/java/org/keycloak/services/service/AuthenticationManager.java b/services/src/main/java/org/keycloak/services/managers/AuthenticationManager.java similarity index 57% rename from services/src/main/java/org/keycloak/services/service/AuthenticationManager.java rename to services/src/main/java/org/keycloak/services/managers/AuthenticationManager.java index 6412afd8cf..74fc03fd74 100755 --- a/services/src/main/java/org/keycloak/services/service/AuthenticationManager.java +++ b/services/src/main/java/org/keycloak/services/managers/AuthenticationManager.java @@ -1,16 +1,21 @@ -package org.keycloak.services.service; +package org.keycloak.services.managers; import org.jboss.resteasy.logging.Logger; +import org.keycloak.RSATokenVerifier; +import org.keycloak.VerificationException; +import org.keycloak.representations.SkeletonKeyToken; import org.keycloak.representations.idm.RequiredCredentialRepresentation; -import org.keycloak.services.model.RealmManager; -import org.keycloak.services.model.RealmModel; -import org.keycloak.services.model.RequiredCredentialModel; +import org.keycloak.services.models.RealmManager; +import org.keycloak.services.models.RealmModel; +import org.keycloak.services.models.RequiredCredentialModel; import org.picketlink.idm.credential.Credentials; import org.picketlink.idm.credential.Password; import org.picketlink.idm.credential.TOTPCredentials; import org.picketlink.idm.credential.UsernamePasswordCredentials; import org.picketlink.idm.model.User; +import javax.ws.rs.NotAuthorizedException; +import javax.ws.rs.core.HttpHeaders; import javax.ws.rs.core.MultivaluedMap; import java.util.HashSet; import java.util.Set; @@ -30,7 +35,45 @@ public class AuthenticationManager this.adapter = adapter; } - public boolean authenticate(RealmModel realm, User user, MultivaluedMap formData) + public User authenticateToken(RealmModel realm, HttpHeaders headers) + { + String tokenString = null; + String authHeader = headers.getHeaderString(HttpHeaders.AUTHORIZATION); + if (authHeader == null) + { + throw new NotAuthorizedException("Bearer"); + } + else + { + String[] split = authHeader.trim().split("\\s+"); + if (split == null || split.length != 2) throw new NotAuthorizedException("Bearer"); + if (!split[0].equalsIgnoreCase("Bearer")) throw new NotAuthorizedException("Bearer"); + tokenString = split[1]; + } + + + try + { + SkeletonKeyToken token = RSATokenVerifier.verifyToken(tokenString, realm.getPublicKey(), realm.getId()); + if (!token.isActive()) + { + throw new NotAuthorizedException("token_expired"); + } + User user = realm.getIdm().getUser(token.getPrincipal()); + if (user == null || !user.isEnabled()) + { + throw new NotAuthorizedException("invalid_user"); + } + return user; + } + catch (VerificationException e) + { + logger.error("Failed to verify token", e); + throw new NotAuthorizedException("invalid_token"); + } + } + + public boolean authenticateForm(RealmModel realm, User user, MultivaluedMap formData) { String username = user.getLoginName(); Set types = new HashSet(); diff --git a/services/src/main/java/org/keycloak/services/service/TokenManager.java b/services/src/main/java/org/keycloak/services/managers/TokenManager.java similarity index 93% rename from services/src/main/java/org/keycloak/services/service/TokenManager.java rename to services/src/main/java/org/keycloak/services/managers/TokenManager.java index b2580319ef..4d1428c6e3 100755 --- a/services/src/main/java/org/keycloak/services/service/TokenManager.java +++ b/services/src/main/java/org/keycloak/services/managers/TokenManager.java @@ -1,13 +1,13 @@ -package org.keycloak.services.service; +package org.keycloak.services.managers; import org.jboss.resteasy.jose.Base64Url; import org.jboss.resteasy.jose.jws.JWSBuilder; import org.jboss.resteasy.jwt.JsonSerialization; import org.keycloak.representations.SkeletonKeyScope; import org.keycloak.representations.SkeletonKeyToken; -import org.keycloak.services.model.RealmManager; -import org.keycloak.services.model.RealmModel; -import org.keycloak.services.model.ResourceModel; +import org.keycloak.services.models.RealmManager; +import org.keycloak.services.models.RealmModel; +import org.keycloak.services.models.ResourceModel; import org.picketlink.idm.model.User; import javax.ws.rs.ForbiddenException; diff --git a/services/src/main/java/org/keycloak/services/model/data/RealmModel.java b/services/src/main/java/org/keycloak/services/model/data/RealmModel.java deleted file mode 100755 index ab3711a943..0000000000 --- a/services/src/main/java/org/keycloak/services/model/data/RealmModel.java +++ /dev/null @@ -1,194 +0,0 @@ -package org.keycloak.services.model.data; - -import org.bouncycastle.openssl.PEMWriter; -import org.jboss.resteasy.security.PemUtils; - -import java.io.IOException; -import java.io.Serializable; -import java.io.StringWriter; -import java.security.PrivateKey; -import java.security.PublicKey; - -/** - * @author Bill Burke - * @version $Revision: 1 $ - */ -@Deprecated -public class RealmModel implements Serializable -{ - private static final long serialVersionUID = 1L; - - protected String id; - protected String name; - protected long tokenLifespan = 3600 * 24; // one day - protected long accessCodeLifespan = 300; // 5 minutes - protected boolean enabled; - protected boolean sslNotRequired; - protected boolean cookieLoginAllowed; - protected String publicKeyPem; - protected String privateKeyPem; - protected volatile transient PublicKey publicKey; - protected volatile transient PrivateKey privateKey; - - public String getId() - { - return id; - } - - public void setId(String id) - { - this.id = id; - } - - public String getName() - { - return name; - } - - public void setName(String name) - { - this.name = name; - } - - public boolean isEnabled() - { - return enabled; - } - - public void setEnabled(boolean enabled) - { - this.enabled = enabled; - } - - public boolean isSslNotRequired() - { - return sslNotRequired; - } - - public void setSslNotRequired(boolean sslNotRequired) - { - this.sslNotRequired = sslNotRequired; - } - - public boolean isCookieLoginAllowed() - { - return cookieLoginAllowed; - } - - public void setCookieLoginAllowed(boolean cookieLoginAllowed) - { - this.cookieLoginAllowed = cookieLoginAllowed; - } - - public long getTokenLifespan() - { - return tokenLifespan; - } - - public void setTokenLifespan(long tokenLifespan) - { - this.tokenLifespan = tokenLifespan; - } - - public long getAccessCodeLifespan() - { - return accessCodeLifespan; - } - - public void setAccessCodeLifespan(long accessCodeLifespan) - { - this.accessCodeLifespan = accessCodeLifespan; - } - - public String getPublicKeyPem() - { - return publicKeyPem; - } - - public void setPublicKeyPem(String publicKeyPem) - { - this.publicKeyPem = publicKeyPem; - this.publicKey = null; - } - - public String getPrivateKeyPem() - { - return privateKeyPem; - } - - public void setPrivateKeyPem(String privateKeyPem) - { - this.privateKeyPem = privateKeyPem; - this.privateKey = null; - } - - public PublicKey getPublicKey() - { - if (publicKey != null) return publicKey; - if (publicKeyPem != null) - { - try - { - publicKey = PemUtils.decodePublicKey(publicKeyPem); - } - catch (Exception e) - { - throw new RuntimeException(e); - } - } - return publicKey; - } - - public void setPublicKey(PublicKey publicKey) - { - this.publicKey = publicKey; - StringWriter writer = new StringWriter(); - PEMWriter pemWriter = new PEMWriter(writer); - try - { - pemWriter.writeObject(publicKey); - pemWriter.flush(); - } - catch (IOException e) - { - throw new RuntimeException(e); - } - String s = writer.toString(); - this.publicKeyPem = PemUtils.removeBeginEnd(s); - } - - public PrivateKey getPrivateKey() - { - if (privateKey != null) return privateKey; - if (privateKeyPem != null) - { - try - { - privateKey = PemUtils.decodePrivateKey(privateKeyPem); - } - catch (Exception e) - { - throw new RuntimeException(e); - } - } - return privateKey; - } - - public void setPrivateKey(PrivateKey privateKey) - { - this.privateKey = privateKey; - StringWriter writer = new StringWriter(); - PEMWriter pemWriter = new PEMWriter(writer); - try - { - pemWriter.writeObject(privateKey); - pemWriter.flush(); - } - catch (IOException e) - { - throw new RuntimeException(e); - } - String s = writer.toString(); - this.privateKeyPem = PemUtils.removeBeginEnd(s); - } -} diff --git a/services/src/main/java/org/keycloak/services/model/data/RequiredCredentialModel.java b/services/src/main/java/org/keycloak/services/model/data/RequiredCredentialModel.java deleted file mode 100755 index 5ab0159142..0000000000 --- a/services/src/main/java/org/keycloak/services/model/data/RequiredCredentialModel.java +++ /dev/null @@ -1,58 +0,0 @@ -package org.keycloak.services.model.data; - -import java.io.Serializable; - -/** - * @author Bill Burke - * @version $Revision: 1 $ - */ -@Deprecated -public class RequiredCredentialModel implements Serializable -{ - private static final long serialVersionUID = 1L; - - protected String id; - protected String type; - protected boolean input; - protected boolean secret; - - public String getId() - { - return id; - } - - public void setId(String id) - { - this.id = id; - } - - public String getType() - { - return type; - } - - public void setType(String type) - { - this.type = type; - } - - public boolean isInput() - { - return input; - } - - public void setInput(boolean input) - { - this.input = input; - } - - public boolean isSecret() - { - return secret; - } - - public void setSecret(boolean secret) - { - this.secret = secret; - } -} diff --git a/services/src/main/java/org/keycloak/services/model/data/ResourceModel.java b/services/src/main/java/org/keycloak/services/model/data/ResourceModel.java deleted file mode 100755 index e8f2421124..0000000000 --- a/services/src/main/java/org/keycloak/services/model/data/ResourceModel.java +++ /dev/null @@ -1,46 +0,0 @@ -package org.keycloak.services.model.data; - -import java.io.Serializable; - -/** - * @author Bill Burke - * @version $Revision: 1 $ - */ -@Deprecated -public class ResourceModel implements Serializable -{ - private static final long serialVersionUID = 1L; - protected String id; - protected String name; - protected boolean surrogateAuthRequired; - - public String getId() - { - return id; - } - - public void setId(String id) - { - this.id = id; - } - - public String getName() - { - return name; - } - - public void setName(String name) - { - this.name = name; - } - - public boolean isSurrogateAuthRequired() - { - return surrogateAuthRequired; - } - - public void setSurrogateAuthRequired(boolean surrogateAuthRequired) - { - this.surrogateAuthRequired = surrogateAuthRequired; - } -} diff --git a/services/src/main/java/org/keycloak/services/model/data/RoleMappingModel.java b/services/src/main/java/org/keycloak/services/model/data/RoleMappingModel.java deleted file mode 100755 index 06e96d86e4..0000000000 --- a/services/src/main/java/org/keycloak/services/model/data/RoleMappingModel.java +++ /dev/null @@ -1,59 +0,0 @@ -package org.keycloak.services.model.data; - -import java.io.Serializable; -import java.util.HashSet; -import java.util.Set; - -/** - * @author Bill Burke - * @version $Revision: 1 $ - */ -@Deprecated -public class RoleMappingModel implements Serializable -{ - private static final long serialVersionUID = 1L; - protected String id; - protected String userid; - protected Set roles = new HashSet(); - protected Set surrogateIds = new HashSet(); - - public String getId() - { - return id; - } - - public void setId(String id) - { - this.id = id; - } - - public String getUserid() - { - return userid; - } - - public void setUserid(String userid) - { - this.userid = userid; - } - - public Set getRoles() - { - return roles; - } - - public void setRoles(Set roles) - { - this.roles = roles; - } - - public Set getSurrogateIds() - { - return surrogateIds; - } - - public void setSurrogateIds(Set surrogateIds) - { - this.surrogateIds = surrogateIds; - } -} diff --git a/services/src/main/java/org/keycloak/services/model/data/RoleModel.java b/services/src/main/java/org/keycloak/services/model/data/RoleModel.java deleted file mode 100755 index a0740d1679..0000000000 --- a/services/src/main/java/org/keycloak/services/model/data/RoleModel.java +++ /dev/null @@ -1,35 +0,0 @@ -package org.keycloak.services.model.data; - -import java.io.Serializable; - -/** - * @author Bill Burke - * @version $Revision: 1 $ - */ -@Deprecated -public class RoleModel implements Serializable -{ - private static final long serialVersionUID = 1L; - protected String id; - protected String name; - - public String getId() - { - return id; - } - - public void setId(String id) - { - this.id = id; - } - - public String getName() - { - return name; - } - - public void setName(String name) - { - this.name = name; - } -} diff --git a/services/src/main/java/org/keycloak/services/model/data/ScopeMappingModel.java b/services/src/main/java/org/keycloak/services/model/data/ScopeMappingModel.java deleted file mode 100755 index 3e3bc01726..0000000000 --- a/services/src/main/java/org/keycloak/services/model/data/ScopeMappingModel.java +++ /dev/null @@ -1,49 +0,0 @@ -package org.keycloak.services.model.data; - -import java.io.Serializable; -import java.util.HashSet; -import java.util.Set; - -/** - * @author Bill Burke - * @version $Revision: 1 $ - */ -@Deprecated -public class ScopeMappingModel implements Serializable -{ - private static final long serialVersionUID = 1L; - protected String id; - protected String userid; - protected Set roles = new HashSet(); - - public String getId() - { - return id; - } - - public void setId(String id) - { - this.id = id; - } - - public String getUserid() - { - return userid; - } - - public void setUserid(String userid) - { - this.userid = userid; - } - - public Set getRoles() - { - return roles; - } - - public void setRoles(Set roles) - { - this.roles = roles; - } - -} diff --git a/services/src/main/java/org/keycloak/services/model/data/UserAttributeModel.java b/services/src/main/java/org/keycloak/services/model/data/UserAttributeModel.java deleted file mode 100755 index 1f7e2ba465..0000000000 --- a/services/src/main/java/org/keycloak/services/model/data/UserAttributeModel.java +++ /dev/null @@ -1,46 +0,0 @@ -package org.keycloak.services.model.data; - -import java.io.Serializable; - -/** - * @author Bill Burke - * @version $Revision: 1 $ - */ -@Deprecated -public class UserAttributeModel implements Serializable -{ - private static final long serialVersionUID = 1L; - protected String id; - protected String name; - protected String value; - - public String getId() - { - return id; - } - - public void setId(String id) - { - this.id = id; - } - - public String getName() - { - return name; - } - - public void setName(String name) - { - this.name = name; - } - - public String getValue() - { - return value; - } - - public void setValue(String value) - { - this.value = value; - } -} diff --git a/services/src/main/java/org/keycloak/services/model/data/UserCredentialModel.java b/services/src/main/java/org/keycloak/services/model/data/UserCredentialModel.java deleted file mode 100755 index b1cf95a079..0000000000 --- a/services/src/main/java/org/keycloak/services/model/data/UserCredentialModel.java +++ /dev/null @@ -1,58 +0,0 @@ -package org.keycloak.services.model.data; - -import java.io.Serializable; - -/** - * @author Bill Burke - * @version $Revision: 1 $ - */ -@Deprecated -public class UserCredentialModel implements Serializable -{ - private static final long serialVersionUID = 1L; - - protected String id; - protected String type; - protected String value; - protected boolean hashed; - - public String getId() - { - return id; - } - - public void setId(String id) - { - this.id = id; - } - - public String getType() - { - return type; - } - - public void setType(String type) - { - this.type = type; - } - - public String getValue() - { - return value; - } - - public void setValue(String value) - { - this.value = value; - } - - public boolean isHashed() - { - return hashed; - } - - public void setHashed(boolean hashed) - { - this.hashed = hashed; - } -} diff --git a/services/src/main/java/org/keycloak/services/model/data/UserModel.java b/services/src/main/java/org/keycloak/services/model/data/UserModel.java deleted file mode 100755 index d878348a84..0000000000 --- a/services/src/main/java/org/keycloak/services/model/data/UserModel.java +++ /dev/null @@ -1,46 +0,0 @@ -package org.keycloak.services.model.data; - -import java.io.Serializable; - -/** - * @author Bill Burke - * @version $Revision: 1 $ - */ -@Deprecated -public class UserModel implements Serializable -{ - private static final long serialVersionUID = 1L; - protected String id; - protected String username; - protected boolean enabled; - - public String getId() - { - return id; - } - - public void setId(String id) - { - this.id = id; - } - - public String getUsername() - { - return username; - } - - public void setUsername(String username) - { - this.username = username; - } - - public boolean isEnabled() - { - return enabled; - } - - public void setEnabled(boolean enabled) - { - this.enabled = enabled; - } -} diff --git a/services/src/main/java/org/keycloak/services/model/RealmManager.java b/services/src/main/java/org/keycloak/services/models/RealmManager.java similarity index 93% rename from services/src/main/java/org/keycloak/services/model/RealmManager.java rename to services/src/main/java/org/keycloak/services/models/RealmManager.java index 270a86c499..02485bf163 100755 --- a/services/src/main/java/org/keycloak/services/model/RealmManager.java +++ b/services/src/main/java/org/keycloak/services/models/RealmManager.java @@ -1,4 +1,4 @@ -package org.keycloak.services.model; +package org.keycloak.services.models; import org.picketlink.idm.IdentityManager; import org.picketlink.idm.internal.IdentityManagerFactory; diff --git a/services/src/main/java/org/keycloak/services/model/RealmModel.java b/services/src/main/java/org/keycloak/services/models/RealmModel.java similarity index 89% rename from services/src/main/java/org/keycloak/services/model/RealmModel.java rename to services/src/main/java/org/keycloak/services/models/RealmModel.java index 1b48554f59..6028bbf65d 100755 --- a/services/src/main/java/org/keycloak/services/model/RealmModel.java +++ b/services/src/main/java/org/keycloak/services/models/RealmModel.java @@ -1,8 +1,12 @@ -package org.keycloak.services.model; +package org.keycloak.services.models; import org.bouncycastle.openssl.PEMWriter; import org.jboss.resteasy.security.PemUtils; import org.keycloak.representations.idm.RequiredCredentialRepresentation; +import org.keycloak.services.models.relationships.RealmAdminRelationship; +import org.keycloak.services.models.relationships.RealmResourceRelationship; +import org.keycloak.services.models.relationships.RequiredCredentialRelationship; +import org.keycloak.services.models.relationships.ScopeRelationship; import org.picketlink.idm.IdentityManager; import org.picketlink.idm.credential.Password; import org.picketlink.idm.credential.TOTPCredential; @@ -386,4 +390,23 @@ public class RealmModel } return set; } + + public boolean isRealmAdmin(Agent agent) + { + IdentityManager idm = getIdm(); + RelationshipQuery query = idm.createRelationshipQuery(RealmAdminRelationship.class); + query.setParameter(RealmAdminRelationship.REALM, realm); + query.setParameter(RealmAdminRelationship.ADMIN, agent); + List results = query.getResultList(); + return results.size() > 0; + } + + public void addRealmAdmin(Agent agent) + { + IdentityManager idm = getIdm(); + RealmAdminRelationship relationship = new RealmAdminRelationship(); + relationship.setAdmin(agent); + relationship.setRealm(realm); + idm.add(relationship); + } } diff --git a/services/src/main/java/org/keycloak/services/model/RequiredCredentialModel.java b/services/src/main/java/org/keycloak/services/models/RequiredCredentialModel.java similarity index 88% rename from services/src/main/java/org/keycloak/services/model/RequiredCredentialModel.java rename to services/src/main/java/org/keycloak/services/models/RequiredCredentialModel.java index 8506e440dd..6476ef70e6 100755 --- a/services/src/main/java/org/keycloak/services/model/RequiredCredentialModel.java +++ b/services/src/main/java/org/keycloak/services/models/RequiredCredentialModel.java @@ -1,4 +1,4 @@ -package org.keycloak.services.model; +package org.keycloak.services.models; /** * @author Bill Burke diff --git a/services/src/main/java/org/keycloak/services/model/ResourceModel.java b/services/src/main/java/org/keycloak/services/models/ResourceModel.java similarity index 97% rename from services/src/main/java/org/keycloak/services/model/ResourceModel.java rename to services/src/main/java/org/keycloak/services/models/ResourceModel.java index a50dcdade7..b41edd6c6c 100755 --- a/services/src/main/java/org/keycloak/services/model/ResourceModel.java +++ b/services/src/main/java/org/keycloak/services/models/ResourceModel.java @@ -1,5 +1,6 @@ -package org.keycloak.services.model; +package org.keycloak.services.models; +import org.keycloak.services.models.relationships.ScopeRelationship; import org.picketlink.idm.IdentityManager; import org.picketlink.idm.internal.IdentityManagerFactory; import org.picketlink.idm.model.Agent; @@ -115,7 +116,6 @@ public class ResourceModel } - public Set getScope(Agent agent) { RelationshipQuery query = getIdm().createRelationshipQuery(ScopeRelationship.class); @@ -128,7 +128,4 @@ public class ResourceModel } return set; } - - - } diff --git a/services/src/main/java/org/keycloak/services/model/UserCredentialModel.java b/services/src/main/java/org/keycloak/services/models/UserCredentialModel.java similarity index 92% rename from services/src/main/java/org/keycloak/services/model/UserCredentialModel.java rename to services/src/main/java/org/keycloak/services/models/UserCredentialModel.java index ee8c7e7251..e2a3603615 100755 --- a/services/src/main/java/org/keycloak/services/model/UserCredentialModel.java +++ b/services/src/main/java/org/keycloak/services/models/UserCredentialModel.java @@ -1,4 +1,4 @@ -package org.keycloak.services.model; +package org.keycloak.services.models; /** * @author Bill Burke diff --git a/services/src/main/java/org/keycloak/services/models/relationships/RealmAdminRelationship.java b/services/src/main/java/org/keycloak/services/models/relationships/RealmAdminRelationship.java new file mode 100755 index 0000000000..cb24a98cae --- /dev/null +++ b/services/src/main/java/org/keycloak/services/models/relationships/RealmAdminRelationship.java @@ -0,0 +1,58 @@ +package org.keycloak.services.models.relationships; + +import org.picketlink.idm.model.AbstractAttributedType; +import org.picketlink.idm.model.Agent; +import org.picketlink.idm.model.Realm; +import org.picketlink.idm.model.Relationship; +import org.picketlink.idm.model.annotation.IdentityProperty; +import org.picketlink.idm.query.RelationshipQueryParameter; + +/** + * @author Bill Burke + * @version $Revision: 1 $ + */ +public class RealmAdminRelationship extends AbstractAttributedType implements Relationship +{ + private static final long serialVersionUID = 1L; + + public static final RelationshipQueryParameter REALM = new RelationshipQueryParameter() { + + @Override + public String getName() { + return "realm"; + } + }; + + public static final RelationshipQueryParameter ADMIN = new RelationshipQueryParameter() { + + @Override + public String getName() { + return "admin"; + } + }; + + protected Realm realm; + protected Agent admin; + + @IdentityProperty + public Realm getRealm() + { + return realm; + } + + public void setRealm(Realm realm) + { + this.realm = realm; + } + + @IdentityProperty + public Agent getAdmin() + { + return admin; + } + + public void setAdmin(Agent admin) + { + this.admin = admin; + } +} diff --git a/services/src/main/java/org/keycloak/services/model/RealmResourceRelationship.java b/services/src/main/java/org/keycloak/services/models/relationships/RealmResourceRelationship.java similarity index 92% rename from services/src/main/java/org/keycloak/services/model/RealmResourceRelationship.java rename to services/src/main/java/org/keycloak/services/models/relationships/RealmResourceRelationship.java index b6011602ff..ed5a8f28b3 100755 --- a/services/src/main/java/org/keycloak/services/model/RealmResourceRelationship.java +++ b/services/src/main/java/org/keycloak/services/models/relationships/RealmResourceRelationship.java @@ -1,4 +1,4 @@ -package org.keycloak.services.model; +package org.keycloak.services.models.relationships; import org.picketlink.idm.model.AbstractAttributedType; import org.picketlink.idm.model.Agent; diff --git a/services/src/main/java/org/keycloak/services/model/RequiredCredentialRelationship.java b/services/src/main/java/org/keycloak/services/models/relationships/RequiredCredentialRelationship.java similarity index 92% rename from services/src/main/java/org/keycloak/services/model/RequiredCredentialRelationship.java rename to services/src/main/java/org/keycloak/services/models/relationships/RequiredCredentialRelationship.java index c2e94db5a2..48a1c907ca 100755 --- a/services/src/main/java/org/keycloak/services/model/RequiredCredentialRelationship.java +++ b/services/src/main/java/org/keycloak/services/models/relationships/RequiredCredentialRelationship.java @@ -1,4 +1,4 @@ -package org.keycloak.services.model; +package org.keycloak.services.models.relationships; import org.picketlink.idm.model.AbstractAttributedType; import org.picketlink.idm.model.Agent; diff --git a/services/src/main/java/org/keycloak/services/model/ScopeRelationship.java b/services/src/main/java/org/keycloak/services/models/relationships/ScopeRelationship.java similarity index 91% rename from services/src/main/java/org/keycloak/services/model/ScopeRelationship.java rename to services/src/main/java/org/keycloak/services/models/relationships/ScopeRelationship.java index 0f01be7423..b8bea48d75 100755 --- a/services/src/main/java/org/keycloak/services/model/ScopeRelationship.java +++ b/services/src/main/java/org/keycloak/services/models/relationships/ScopeRelationship.java @@ -1,4 +1,4 @@ -package org.keycloak.services.model; +package org.keycloak.services.models.relationships; import org.picketlink.idm.model.AbstractAttributedType; import org.picketlink.idm.model.Agent; diff --git a/services/src/main/java/org/keycloak/services/resources/RealmFactory.java b/services/src/main/java/org/keycloak/services/resources/RealmFactory.java new file mode 100755 index 0000000000..0ea5dd97dd --- /dev/null +++ b/services/src/main/java/org/keycloak/services/resources/RealmFactory.java @@ -0,0 +1,343 @@ +package org.keycloak.services.resources; + +import org.jboss.resteasy.logging.Logger; +import org.keycloak.representations.idm.RequiredCredentialRepresentation; +import org.keycloak.representations.idm.ResourceRepresentation; +import org.keycloak.representations.idm.RoleMappingRepresentation; +import org.keycloak.representations.idm.ScopeMappingRepresentation; +import org.keycloak.representations.idm.UserRepresentation; +import org.keycloak.services.managers.AuthenticationManager; +import org.keycloak.services.models.RealmManager; +import org.keycloak.representations.idm.RealmRepresentation; +import org.keycloak.services.models.RealmModel; +import org.keycloak.services.models.RequiredCredentialModel; +import org.keycloak.services.models.ResourceModel; +import org.keycloak.services.models.UserCredentialModel; +import org.picketlink.idm.model.Attribute; +import org.picketlink.idm.model.Realm; +import org.picketlink.idm.model.Role; +import org.picketlink.idm.model.SimpleRole; +import org.picketlink.idm.model.SimpleUser; +import org.picketlink.idm.model.User; + +import javax.ws.rs.Consumes; +import javax.ws.rs.NotAuthorizedException; +import javax.ws.rs.POST; +import javax.ws.rs.Path; +import javax.ws.rs.WebApplicationException; +import javax.ws.rs.core.Context; +import javax.ws.rs.core.HttpHeaders; +import javax.ws.rs.core.MediaType; +import javax.ws.rs.core.Response; +import javax.ws.rs.core.UriBuilder; +import javax.ws.rs.core.UriInfo; +import java.security.KeyPair; +import java.security.KeyPairGenerator; +import java.security.NoSuchAlgorithmException; +import java.util.HashMap; +import java.util.Map; + +/** + * @author Bill Burke + * @version $Revision: 1 $ + */ +@Path("/realmfactory") +public class RealmFactory +{ + protected Logger logger = Logger.getLogger(RealmFactory.class); + + protected RealmManager adapter; + protected AuthenticationManager authenticationManager; + protected RealmModel defaultRealm; + + + @Context + protected UriInfo uriInfo; + + @Context + protected HttpHeaders headers; + + + public RealmFactory(RealmManager adapter) + { + this.adapter = adapter; + defaultRealm = adapter.getRealm(Realm.DEFAULT_REALM); + } + + @POST + @Consumes("application/json") + public Response importDomain(RealmRepresentation rep) + { + RealmModel realm = createRealm(rep); + UriBuilder builder = uriInfo.getRequestUriBuilder().path(realm.getId()); + return Response.created(builder.build()) + .entity(RealmResource.realmRep(realm, uriInfo)) + .type(MediaType.APPLICATION_JSON_TYPE).build(); + } + + protected RealmModel createRealm(RealmRepresentation rep) + { + User realmCreator = authenticationManager.authenticateToken(defaultRealm, headers); + Role creatorRole = defaultRealm.getIdm().getRole(RegistrationService.REALM_CREATOR_ROLE); + if (!defaultRealm.getIdm().hasRole(realmCreator, creatorRole)) + { + logger.warn("not a realm creator"); + throw new NotAuthorizedException("Bearer"); + } + verifyRealmRepresentation(rep); + + RealmModel realm = adapter.create(rep.getRealm()); + realm.addRealmAdmin(realmCreator); + KeyPair keyPair = null; + try + { + keyPair = KeyPairGenerator.getInstance("RSA").generateKeyPair(); + } + catch (NoSuchAlgorithmException e) + { + throw new RuntimeException(e); + } + realm.setPrivateKey(keyPair.getPrivate()); + realm.setPublicKey(keyPair.getPublic()); + realm.setName(rep.getRealm()); + realm.setEnabled(rep.isEnabled()); + realm.setTokenLifespan(rep.getTokenLifespan()); + realm.setAccessCodeLifespan(rep.getAccessCodeLifespan()); + realm.setSslNotRequired(rep.isSslNotRequired()); + realm.setCookieLoginAllowed(rep.isCookieLoginAllowed()); + realm.updateRealm(); + + + Map userMap = new HashMap(); + + for (RequiredCredentialRepresentation requiredCred : rep.getRequiredCredentials()) + { + RequiredCredentialModel credential = new RequiredCredentialModel(); + credential.setType(requiredCred.getType()); + credential.setInput(requiredCred.isInput()); + credential.setSecret(requiredCred.isSecret()); + realm.addRequiredCredential(credential); + } + + for (UserRepresentation userRep : rep.getUsers()) + { + User user = new SimpleUser(userRep.getUsername()); + user.setEnabled(userRep.isEnabled()); + if (userRep.getAttributes() != null) + { + for (Map.Entry entry : userRep.getAttributes().entrySet()) + { + user.setAttribute(new Attribute(entry.getKey(), entry.getValue())); + } + } + realm.getIdm().add(user); + if (userRep.getCredentials() != null) + { + for (UserRepresentation.Credential cred : userRep.getCredentials()) + { + UserCredentialModel credential = new UserCredentialModel(); + credential.setType(cred.getType()); + credential.setValue(cred.getValue()); + realm.updateCredential(user, credential); + } + } + userMap.put(user.getLoginName(), user); + } + + Map roles = new HashMap(); + + if (rep.getRoles() != null) + { + for (String roleString : rep.getRoles()) + { + SimpleRole role = new SimpleRole(roleString.trim()); + realm.getIdm().add(role); + roles.put(role.getName(), role); + } + } + + if (rep.getRoleMappings() != null) + { + for (RoleMappingRepresentation mapping : rep.getRoleMappings()) + { + User user = userMap.get(mapping.getUsername()); + for (String roleString : mapping.getRoles()) + { + Role role = roles.get(roleString.trim()); + if (role == null) + { + role = new SimpleRole(roleString.trim()); + realm.getIdm().add(role); + roles.put(role.getName(), role); + } + realm.getIdm().grantRole(user, role); + } + } + } + + if (rep.getScopeMappings() != null) + { + for (ScopeMappingRepresentation scope : rep.getScopeMappings()) + { + for (String roleString : scope.getRoles()) + { + Role role = roles.get(roleString.trim()); + if (role == null) + { + role = new SimpleRole(roleString.trim()); + realm.getIdm().add(role); + roles.put(role.getName(), role); + } + User user = userMap.get(scope.getUsername()); + realm.addScope(user, role.getName()); + } + + } + } + + if (!roles.containsKey("*")) + { + SimpleRole wildcard = new SimpleRole("*"); + realm.getIdm().add(wildcard); + roles.put("*", wildcard); + } + + if (rep.getResources() != null) + { + createResources(rep, realm, userMap); + } + return realm; + } + + protected void createResources(RealmRepresentation rep, RealmModel realm, Map userMap) + { + for (ResourceRepresentation resourceRep : rep.getResources()) + { + ResourceModel resource = realm.addResource(resourceRep.getName()); + resource.setSurrogateAuthRequired(resourceRep.isSurrogateAuthRequired()); + resource.updateResource(); + Map roles = new HashMap(); + if (resourceRep.getRoles() != null) + { + for (String roleString : rep.getRoles()) + { + SimpleRole role = new SimpleRole(roleString.trim()); + resource.getIdm().add(role); + roles.put(role.getName(), role); + } + } + if (resourceRep.getRoleMappings() != null) + { + for (RoleMappingRepresentation mapping : resourceRep.getRoleMappings()) + { + User user = userMap.get(mapping.getUsername()); + for (String roleString : mapping.getRoles()) + { + Role role = roles.get(roleString.trim()); + if (role == null) + { + role = new SimpleRole(roleString.trim()); + resource.getIdm().add(role); + roles.put(role.getName(), role); + } + resource.getIdm().grantRole(user, role); + } + } + } + if (resourceRep.getScopeMappings() != null) + { + for (ScopeMappingRepresentation mapping : resourceRep.getScopeMappings()) + { + User user = userMap.get(mapping.getUsername()); + for (String roleString : mapping.getRoles()) + { + Role role = roles.get(roleString.trim()); + if (role == null) + { + role = new SimpleRole(roleString.trim()); + resource.getIdm().add(role); + roles.put(role.getName(), role); + } + resource.addScope(user, role.getName()); + } + } + } + if (!roles.containsKey("*")) + { + SimpleRole wildcard = new SimpleRole("*"); + resource.getIdm().add(wildcard); + roles.put("*", wildcard); + } + + } + } + + protected void verifyRealmRepresentation(RealmRepresentation rep) + { + if (rep.getRequiredCredentials() == null) + { + throw new WebApplicationException(Response.status(Response.Status.BAD_REQUEST) + .entity("Realm credential requirements not defined").type("text/plain").build()); + + } + + HashMap userReps = new HashMap(); + for (UserRepresentation userRep : rep.getUsers()) userReps.put(userRep.getUsername(), userRep); + + // override enabled to false if user does not have at least all of browser or client credentials + for (UserRepresentation userRep : rep.getUsers()) + { + if (userRep.getCredentials() == null) + { + userRep.setEnabled(false); + } + else + { + boolean hasBrowserCredentials = true; + for (RequiredCredentialRepresentation credential : rep.getRequiredCredentials()) + { + boolean hasCredential = false; + for (UserRepresentation.Credential cred : userRep.getCredentials()) + { + if (cred.getType().equals(credential.getType())) + { + hasCredential = true; + break; + } + } + if (!hasCredential) + { + hasBrowserCredentials = false; + break; + } + } + if (!hasBrowserCredentials) + { + userRep.setEnabled(false); + } + + } + } + + if (rep.getResources() != null) + { + // check mappings + for (ResourceRepresentation resourceRep : rep.getResources()) + { + if (resourceRep.getRoleMappings() != null) + { + for (RoleMappingRepresentation mapping : resourceRep.getRoleMappings()) + { + if (!userReps.containsKey(mapping.getUsername())) + { + throw new WebApplicationException(Response.status(Response.Status.BAD_REQUEST) + .entity("No users declared for role mapping").type("text/plain").build()); + + } + } + } + } + } + } + +} diff --git a/services/src/main/java/org/keycloak/services/service/RealmResource.java b/services/src/main/java/org/keycloak/services/resources/RealmResource.java similarity index 57% rename from services/src/main/java/org/keycloak/services/service/RealmResource.java rename to services/src/main/java/org/keycloak/services/resources/RealmResource.java index a5baf404fc..a2ec89a3ca 100755 --- a/services/src/main/java/org/keycloak/services/service/RealmResource.java +++ b/services/src/main/java/org/keycloak/services/resources/RealmResource.java @@ -1,48 +1,42 @@ -package org.keycloak.services.service; +package org.keycloak.services.resources; -import org.keycloak.services.IdentityManagerAdapter; -import org.keycloak.services.model.data.RealmModel; +import org.keycloak.services.models.RealmManager; import org.jboss.resteasy.logging.Logger; import org.keycloak.representations.idm.PublishedRealmRepresentation; +import org.keycloak.services.models.RealmModel; import javax.ws.rs.GET; import javax.ws.rs.NotFoundException; import javax.ws.rs.Path; import javax.ws.rs.PathParam; import javax.ws.rs.Produces; -import javax.ws.rs.QueryParam; import javax.ws.rs.core.Context; -import javax.ws.rs.core.GenericEntity; -import javax.ws.rs.core.MediaType; -import javax.ws.rs.core.Response; import javax.ws.rs.core.UriBuilder; import javax.ws.rs.core.UriInfo; -import java.util.ArrayList; -import java.util.List; /** * @author Bill Burke * @version $Revision: 1 $ */ -@Path("/") +@Path("/realms") public class RealmResource { protected Logger logger = Logger.getLogger(RealmResource.class); - protected IdentityManagerAdapter identityManager; + protected RealmManager adapter; @Context protected UriInfo uriInfo; - public RealmResource(IdentityManagerAdapter identityManager) + public RealmResource(RealmManager adapter) { - this.identityManager = identityManager; + this.adapter = adapter; } @GET - @Path("realms/{realm}") + @Path("{realm}") @Produces("application/json") public PublishedRealmRepresentation getRealm(@PathParam("realm") String id) { - RealmModel realm = identityManager.getRealm(id); + RealmModel realm = adapter.getRealm(id); if (realm == null) { logger.debug("realm not found"); @@ -52,11 +46,11 @@ public class RealmResource } @GET - @Path("realms/{realm}.html") + @Path("{realm}.html") @Produces("text/html") public String getRealmHtml(@PathParam("realm") String id) { - RealmModel realm = identityManager.getRealm(id); + RealmModel realm = adapter.getRealm(id); if (realm == null) { logger.debug("realm not found"); @@ -82,10 +76,15 @@ public class RealmResource grant.path(TokenService.class).path(TokenService.class, "accessTokenGrant"); String grantUrl = grant.build(realm.getId()).toString(); + UriBuilder idGrant = uriInfo.getBaseUriBuilder(); + grant.path(TokenService.class).path(TokenService.class, "identityTokenGrant"); + String idGrantUrl = idGrant.build(realm.getId()).toString(); + html.append("

Realm: ").append(realm.getName()).append("

"); html.append("

auth: ").append(authUri).append("

"); html.append("

code: ").append(codeUri).append("

"); html.append("

grant: ").append(grantUrl).append("

"); + html.append("

identity grant: ").append(idGrantUrl).append("

"); html.append("

public key: ").append(realm.getPublicKeyPem()).append("

"); html.append(""); @@ -93,46 +92,6 @@ public class RealmResource } - @GET - @Path("realms") - @Produces("application/json") - public Response getRealmsByName(@QueryParam("name") String name) - { - if (name == null) return Response.noContent().build(); - List realms = identityManager.getRealmsByName(name); - if (realms.size() == 0) return Response.noContent().build(); - - List list = new ArrayList(); - for (RealmModel realm : realms) - { - list.add(realmRep(realm, uriInfo)); - } - GenericEntity> entity = new GenericEntity>(list){}; - return Response.ok(entity).type(MediaType.APPLICATION_JSON_TYPE).build(); - } - - @GET - @Path("realms.html") - @Produces("text/html") - public String getRealmsByNameHtml(@QueryParam("name") String name) - { - if (name == null) return "

No realms with that name

"; - List realms = identityManager.getRealmsByName(name); - if (realms.size() == 0) return "

No realms with that name

"; - if (realms.size() == 1) return realmHtml(realms.get(0)); - - StringBuffer html = new StringBuffer(); - html.append("

Realms

"); - for (RealmModel realm : realms) - { - html.append("

").append(realm.getId()).append("

"); - } - html.append(""); - return html.toString(); - } - - public static PublishedRealmRepresentation realmRep(RealmModel realm, UriInfo uriInfo) { PublishedRealmRepresentation rep = new PublishedRealmRepresentation(); @@ -153,6 +112,11 @@ public class RealmResource grant.path(TokenService.class).path(TokenService.class, "accessTokenGrant"); String grantUrl = grant.build(realm.getId()).toString(); rep.setGrantUrl(grantUrl); + + UriBuilder idGrant = uriInfo.getBaseUriBuilder(); + grant.path(TokenService.class).path(TokenService.class, "identityTokenGrant"); + String idGrantUrl = idGrant.build(realm.getId()).toString(); + rep.setIdentityGrantUrl(idGrantUrl); return rep; } } diff --git a/services/src/main/java/org/keycloak/services/service/RegistrationService.java b/services/src/main/java/org/keycloak/services/resources/RegistrationService.java similarity index 77% rename from services/src/main/java/org/keycloak/services/service/RegistrationService.java rename to services/src/main/java/org/keycloak/services/resources/RegistrationService.java index e8ff93deb2..c4c9b05015 100755 --- a/services/src/main/java/org/keycloak/services/service/RegistrationService.java +++ b/services/src/main/java/org/keycloak/services/resources/RegistrationService.java @@ -1,10 +1,11 @@ -package org.keycloak.services.service; +package org.keycloak.services.resources; import org.keycloak.representations.idm.UserRepresentation; -import org.keycloak.services.model.RealmManager; -import org.keycloak.services.model.RealmModel; -import org.keycloak.services.model.UserCredentialModel; +import org.keycloak.services.models.RealmManager; +import org.keycloak.services.models.RealmModel; +import org.keycloak.services.models.UserCredentialModel; import org.picketlink.idm.model.Realm; +import org.picketlink.idm.model.Role; import org.picketlink.idm.model.SimpleUser; import org.picketlink.idm.model.User; @@ -24,6 +25,7 @@ import java.net.URI; @Path("/registrations") public class RegistrationService { + public static final String REALM_CREATOR_ROLE = "realm-creator"; protected RealmManager adapter; protected RealmModel defaultRealm; @@ -57,6 +59,8 @@ public class RegistrationService credModel.setValue(cred.getValue()); defaultRealm.updateCredential(user, credModel); } + Role realmCreator = defaultRealm.getIdm().getRole(REALM_CREATOR_ROLE); + defaultRealm.getIdm().grantRole(user, realmCreator); URI uri = uriInfo.getBaseUriBuilder().path(RealmFactory.class).path(user.getLoginName()).build(); return Response.created(uri).build(); } diff --git a/services/src/main/java/org/keycloak/services/service/SkeletonKeyApplication.java b/services/src/main/java/org/keycloak/services/resources/SkeletonKeyApplication.java similarity index 89% rename from services/src/main/java/org/keycloak/services/service/SkeletonKeyApplication.java rename to services/src/main/java/org/keycloak/services/resources/SkeletonKeyApplication.java index 96ead5ea1f..6517a870d8 100755 --- a/services/src/main/java/org/keycloak/services/service/SkeletonKeyApplication.java +++ b/services/src/main/java/org/keycloak/services/resources/SkeletonKeyApplication.java @@ -1,10 +1,9 @@ -package org.keycloak.services.service; +package org.keycloak.services.resources; import org.infinispan.Cache; import org.infinispan.manager.DefaultCacheManager; import org.keycloak.SkeletonKeyContextResolver; -import javax.ws.rs.ApplicationPath; import javax.ws.rs.core.Application; import java.io.IOException; import java.io.InputStream; @@ -15,7 +14,6 @@ import java.util.Set; * @author Bill Burke * @version $Revision: 1 $ */ -@ApplicationPath("/") public class SkeletonKeyApplication extends Application { protected Set singletons = new HashSet(); diff --git a/services/src/main/java/org/keycloak/services/service/TokenService.java b/services/src/main/java/org/keycloak/services/resources/TokenService.java similarity index 94% rename from services/src/main/java/org/keycloak/services/service/TokenService.java rename to services/src/main/java/org/keycloak/services/resources/TokenService.java index 6edd0afe15..ebdf2a9520 100755 --- a/services/src/main/java/org/keycloak/services/service/TokenService.java +++ b/services/src/main/java/org/keycloak/services/resources/TokenService.java @@ -1,4 +1,4 @@ -package org.keycloak.services.service; +package org.keycloak.services.resources; import org.jboss.resteasy.jose.Base64Url; import org.jboss.resteasy.jose.jws.JWSBuilder; @@ -9,10 +9,12 @@ import org.jboss.resteasy.logging.Logger; import org.keycloak.representations.AccessTokenResponse; import org.keycloak.representations.SkeletonKeyScope; import org.keycloak.representations.SkeletonKeyToken; -import org.keycloak.services.model.RealmManager; -import org.keycloak.services.model.RealmModel; -import org.keycloak.services.model.RequiredCredentialModel; -import org.keycloak.services.model.ResourceModel; +import org.keycloak.services.managers.AuthenticationManager; +import org.keycloak.services.managers.TokenManager; +import org.keycloak.services.models.RealmManager; +import org.keycloak.services.models.RealmModel; +import org.keycloak.services.models.RequiredCredentialModel; +import org.keycloak.services.models.ResourceModel; import org.picketlink.idm.model.User; import javax.ws.rs.Consumes; @@ -188,7 +190,7 @@ public class TokenService { throw new NotAuthorizedException("Disabled user."); } - if (authManager.authenticate(realm, user, form)) + if (authManager.authenticateForm(realm, user, form)) { throw new NotAuthorizedException("Auth failed"); } @@ -239,7 +241,7 @@ public class TokenService return Response.ok("Your account is not enabled").type("text/html").build(); } - boolean authenticated = authManager.authenticate(realm, user, formData); + boolean authenticated = authManager.authenticateForm(realm, user, formData); if (!authenticated) return loginForm("Unable to authenticate, try again", redirect, clientId, scopeParam, state, realm, client); SkeletonKeyToken token = null; @@ -322,7 +324,7 @@ public class TokenService return Response.status(Response.Status.BAD_REQUEST).entity(error).type("application/json").build(); } - boolean authenticated = authManager.authenticate(realm, client, formData); + boolean authenticated = authManager.authenticateForm(realm, client, formData); if (!authenticated) { Map error = new HashMap(); diff --git a/services/src/main/java/org/keycloak/services/service/RealmFactory.java b/services/src/main/java/org/keycloak/services/service/RealmFactory.java deleted file mode 100755 index 821acc5f87..0000000000 --- a/services/src/main/java/org/keycloak/services/service/RealmFactory.java +++ /dev/null @@ -1,354 +0,0 @@ -package org.keycloak.services.service; - -import org.keycloak.services.model.RealmManager; -import org.keycloak.representations.idm.RealmRepresentation; -import org.keycloak.services.model.RealmModel; -import org.picketlink.idm.model.User; - -import javax.ws.rs.Consumes; -import javax.ws.rs.POST; -import javax.ws.rs.Path; -import javax.ws.rs.core.Context; -import javax.ws.rs.core.MediaType; -import javax.ws.rs.core.Response; -import javax.ws.rs.core.UriBuilder; -import javax.ws.rs.core.UriInfo; -import java.security.KeyPair; -import java.security.KeyPairGenerator; -import java.security.NoSuchAlgorithmException; -import java.util.HashMap; -import java.util.Map; - -/** - * @author Bill Burke - * @version $Revision: 1 $ - */ -@Path("/realmfactory") -public class RealmFactory -{ - protected RealmManager adapter; - - @Context - protected UriInfo uriInfo; - - public RealmFactory(RealmManager adapter) - { - this.adapter = adapter; - } - - - @POST - @Consumes("application/json") - public Response importDomain(RealmRepresentation rep) - { - RealmModel realm = createRealm(rep); - UriBuilder builder = uriInfo.getRequestUriBuilder().path(realm.getId()); - return Response.created(builder.build()) - //.entity(RealmResource.realmRep(realm, uriInfo)) - .type(MediaType.APPLICATION_JSON_TYPE).build(); - } - - protected RealmModel createRealm(RealmRepresentation rep) - { - //verifyRealmRepresentation(rep); - - RealmModel realm = adapter.create(rep.getRealm()); - KeyPair keyPair = null; - try - { - keyPair = KeyPairGenerator.getInstance("RSA").generateKeyPair(); - } - catch (NoSuchAlgorithmException e) - { - throw new RuntimeException(e); - } - realm.setPrivateKey(keyPair.getPrivate()); - realm.setPublicKey(keyPair.getPublic()); - realm.setName(rep.getRealm()); - realm.setEnabled(rep.isEnabled()); - realm.setTokenLifespan(rep.getTokenLifespan()); - realm.setAccessCodeLifespan(rep.getAccessCodeLifespan()); - realm.setSslNotRequired(rep.isSslNotRequired()); - realm.updateRealm(); - - - Map userMap = new HashMap(); - return null; - }/* - RoleModel adminRole = identityManager.create(realm, "admin"); - - for (RequiredCredentialRepresentation requiredCred : rep.getRequiredCredentials()) - { - RequiredCredentialModel credential = new RequiredCredentialModel(); - credential.setType(requiredCred.getType()); - credential.setInput(requiredCred.isInput()); - credential.setSecret(requiredCred.isSecret()); - identityManager.create(realm, credential); - } - - for (UserRepresentation userRep : rep.getUsers()) - { - UserModel user = new UserModel(); - user.setUsername(userRep.getUsername()); - user.setEnabled(userRep.isEnabled()); - user = identityManager.create(realm, user); - userMap.put(user.getUsername(), user); - if (userRep.getCredentials() != null) - { - for (UserRepresentation.Credential cred : userRep.getCredentials()) - { - UserCredentialModel credential = new UserCredentialModel(); - credential.setType(cred.getType()); - credential.setValue(cred.getValue()); - credential.setHashed(cred.isHashed()); - identityManager.create(user, credential); - } - } - - if (userRep.getAttributes() != null) - { - for (Map.Entry entry : userRep.getAttributes().entrySet()) - { - UserAttributeModel attribute = new UserAttributeModel(); - attribute.setName(entry.getKey()); - attribute.setValue(entry.getValue()); - identityManager.create(user, attribute); - } - } - } - - for (RoleMappingRepresentation mapping : rep.getRoleMappings()) - { - RoleMappingModel roleMapping = createRoleMapping(userMap, mapping); - UserModel user = userMap.get(mapping.getUsername()); - identityManager.create(realm, user, roleMapping); - } - - if (rep.getScopeMappings() != null) - { - for (ScopeMappingRepresentation scope : rep.getScopeMappings()) - { - ScopeMappingModel scopeMapping = createScopeMapping(userMap, scope); - UserModel user = userMap.get(scope.getUsername()); - identityManager.create(realm, user, scopeMapping); - - } - } - - if (rep.getResources() != null) - { - for (ResourceRepresentation resourceRep : rep.getResources()) - { - ResourceModel resource = new ResourceModel(); - resource.setName(resourceRep.getName()); - resource.setSurrogateAuthRequired(resourceRep.isSurrogateAuthRequired()); - resource = identityManager.create(realm, resource); - if (resourceRep.getRoles() != null) - { - for (String role : resourceRep.getRoles()) - { - RoleModel r = identityManager.create(realm, resource, role); - } - } - if (resourceRep.getRoleMappings() != null) - { - for (RoleMappingRepresentation mapping : resourceRep.getRoleMappings()) - { - RoleMappingModel roleMapping = createRoleMapping(userMap, mapping); - UserModel user = userMap.get(mapping.getUsername()); - identityManager.create(realm, resource, user, roleMapping); - } - } - if (resourceRep.getScopeMappings() != null) - { - for (ScopeMappingRepresentation mapping : resourceRep.getScopeMappings()) - { - ScopeMappingModel scopeMapping = createScopeMapping(userMap, mapping); - UserModel user = userMap.get(mapping.getUsername()); - identityManager.create(realm, resource, user, scopeMapping); - } - } - - } - } - return realm; - } - - protected RoleMappingModel createRoleMapping(Map userMap, RoleMappingRepresentation mapping) - { - RoleMappingModel roleMapping = new RoleMappingModel(); - UserModel user = userMap.get(mapping.getUsername()); - roleMapping.setUserid(user.getId()); - if (mapping.getSurrogates() != null) - { - for (String s : mapping.getSurrogates()) - { - UserModel surrogate = userMap.get(s); - roleMapping.getSurrogateIds().add(surrogate.getId()); - - } - } - for (String role : mapping.getRoles()) - { - roleMapping.getRoles().add(role); - } - return roleMapping; - } - - protected ScopeMappingModel createScopeMapping(Map userMap, ScopeMappingRepresentation mapping) - { - ScopeMappingModel scopeMapping = new ScopeMappingModel(); - UserModel user = userMap.get(mapping.getUsername()); - scopeMapping.setUserid(user.getId()); - for (String role : mapping.getRoles()) - { - scopeMapping.getRoles().add(role); - } - return scopeMapping; - } - - - protected void verifyRealmRepresentation(RealmRepresentation rep) - { - if (rep.getUsers() == null) - { - throw new WebApplicationException(Response.status(Response.Status.BAD_REQUEST) - .entity("No realm admin users defined for realm").type("text/plain").build()); - } - - if (rep.getRequiredCredentials() == null) - { - throw new WebApplicationException(Response.status(Response.Status.BAD_REQUEST) - .entity("Realm credential requirements not defined").type("text/plain").build()); - - } - - if (rep.getRoleMappings() == null) - { - throw new WebApplicationException(Response.status(Response.Status.BAD_REQUEST) - .entity("No realm admin users defined for realm").type("text/plain").build()); - } - - HashMap userReps = new HashMap(); - for (UserRepresentation userRep : rep.getUsers()) userReps.put(userRep.getUsername(), userRep); - - // make sure there is a user that has admin privileges for the realm - Set admins = new HashSet(); - for (RoleMappingRepresentation mapping : rep.getRoleMappings()) - { - if (!userReps.containsKey(mapping.getUsername())) - { - throw new WebApplicationException(Response.status(Response.Status.BAD_REQUEST) - .entity("No users declared for role mapping").type("text/plain").build()); - - } - for (String role : mapping.getRoles()) - { - if (!role.equals("admin")) - { - throw new WebApplicationException(Response.status(Response.Status.BAD_REQUEST) - .entity("There is only an 'admin' role for realms").type("text/plain").build()); - - } - else - { - admins.add(userReps.get(mapping.getUsername())); - } - } - } - if (admins.size() == 0) - { - throw new WebApplicationException(Response.status(Response.Status.BAD_REQUEST) - .entity("No realm admin users defined for realm").type("text/plain").build()); - } - - // override enabled to false if user does not have at least all of browser or client credentials - for (UserRepresentation userRep : rep.getUsers()) - { - if (!userRep.isEnabled()) - { - admins.remove(userRep); - continue; - } - if (userRep.getCredentials() == null) - { - admins.remove(userRep); - userRep.setEnabled(false); - } - else - { - boolean hasBrowserCredentials = true; - for (RequiredCredentialRepresentation credential : rep.getRequiredCredentials()) - { - boolean hasCredential = false; - for (UserRepresentation.Credential cred : userRep.getCredentials()) - { - if (cred.getType().equals(credential.getType())) - { - hasCredential = true; - break; - } - } - if (!hasCredential) - { - hasBrowserCredentials = false; - break; - } - } - if (!hasBrowserCredentials) - { - userRep.setEnabled(false); - admins.remove(userRep); - } - - } - } - - if (admins.size() == 0) - { - throw new WebApplicationException(Response.status(Response.Status.BAD_REQUEST) - .entity("No realm admin users are enabled or have appropriate credentials").type("text/plain").build()); - } - - if (rep.getResources() != null) - { - // check mappings - for (ResourceRepresentation resourceRep : rep.getResources()) - { - if (resourceRep.getRoleMappings() != null) - { - for (RoleMappingRepresentation mapping : resourceRep.getRoleMappings()) - { - if (!userReps.containsKey(mapping.getUsername())) - { - throw new WebApplicationException(Response.status(Response.Status.BAD_REQUEST) - .entity("No users declared for role mapping").type("text/plain").build()); - - } - if (mapping.getSurrogates() != null) - { - for (String surrogate : mapping.getSurrogates()) - { - if (!userReps.containsKey(surrogate)) - { - throw new WebApplicationException(Response.status(Response.Status.BAD_REQUEST) - .entity("No users declared for role mapping surrogate").type("text/plain").build()); - } - } - } - for (String role : mapping.getRoles()) - { - if (!resourceRep.getRoles().contains(role)) - { - throw new WebApplicationException(Response.status(Response.Status.BAD_REQUEST) - .entity("No resource role for role mapping").type("text/plain").build()); - } - } - } - } - } - } - } - */ - -} diff --git a/services/src/test/java/org/keycloak/test/AdapterTest.java b/services/src/test/java/org/keycloak/test/AdapterTest.java index 998bedd018..6605780e5d 100755 --- a/services/src/test/java/org/keycloak/test/AdapterTest.java +++ b/services/src/test/java/org/keycloak/test/AdapterTest.java @@ -7,13 +7,13 @@ import org.junit.FixMethodOrder; import org.junit.Test; import org.junit.runners.MethodSorters; import org.keycloak.representations.idm.RequiredCredentialRepresentation; -import org.keycloak.services.model.RealmManager; -import org.keycloak.services.model.RealmModel; -import org.keycloak.services.model.RealmResourceRelationship; -import org.keycloak.services.model.RequiredCredentialModel; -import org.keycloak.services.model.RequiredCredentialRelationship; -import org.keycloak.services.model.ScopeRelationship; -import org.keycloak.services.model.UserCredentialModel; +import org.keycloak.services.models.RealmManager; +import org.keycloak.services.models.RealmModel; +import org.keycloak.services.models.relationships.RealmResourceRelationship; +import org.keycloak.services.models.RequiredCredentialModel; +import org.keycloak.services.models.relationships.RequiredCredentialRelationship; +import org.keycloak.services.models.relationships.ScopeRelationship; +import org.keycloak.services.models.UserCredentialModel; import org.picketlink.idm.IdentityManager; import org.picketlink.idm.config.IdentityConfigurationBuilder; import org.picketlink.idm.credential.Credentials;