diff --git a/core/src/main/java/org/keycloak/representations/idm/ApplicationRepresentation.java b/core/src/main/java/org/keycloak/representations/idm/ApplicationRepresentation.java index 3580e3924f6..5a3a8fd7ae2 100755 --- a/core/src/main/java/org/keycloak/representations/idm/ApplicationRepresentation.java +++ b/core/src/main/java/org/keycloak/representations/idm/ApplicationRepresentation.java @@ -1,6 +1,7 @@ package org.keycloak.representations.idm; import java.util.List; +import java.util.Map; /** * @author Bill Burke @@ -21,6 +22,8 @@ public class ApplicationRepresentation { protected Integer notBefore; protected Boolean bearerOnly; protected Boolean publicClient; + protected String protocol; + protected Map attributes; protected Boolean fullScopeAllowed; @@ -143,4 +146,20 @@ public class ApplicationRepresentation { public void setFullScopeAllowed(Boolean fullScopeAllowed) { this.fullScopeAllowed = fullScopeAllowed; } + + public String getProtocol() { + return protocol; + } + + public void setProtocol(String protocol) { + this.protocol = protocol; + } + + public Map getAttributes() { + return attributes; + } + + public void setAttributes(Map attributes) { + this.attributes = attributes; + } } diff --git a/core/src/main/java/org/keycloak/representations/idm/OAuthClientRepresentation.java b/core/src/main/java/org/keycloak/representations/idm/OAuthClientRepresentation.java index 4c2193d49db..e61cdfc5279 100755 --- a/core/src/main/java/org/keycloak/representations/idm/OAuthClientRepresentation.java +++ b/core/src/main/java/org/keycloak/representations/idm/OAuthClientRepresentation.java @@ -1,6 +1,7 @@ package org.keycloak.representations.idm; import java.util.List; +import java.util.Map; /** * @author Bill Burke @@ -16,6 +17,8 @@ public class OAuthClientRepresentation { protected ClaimRepresentation claims; protected Integer notBefore; protected Boolean publicClient; + protected String protocol; + protected Map attributes; protected Boolean directGrantsOnly; protected Boolean fullScopeAllowed; @@ -108,4 +111,19 @@ public class OAuthClientRepresentation { this.fullScopeAllowed = fullScopeAllowed; } + public String getProtocol() { + return protocol; + } + + public void setProtocol(String protocol) { + this.protocol = protocol; + } + + public Map getAttributes() { + return attributes; + } + + public void setAttributes(Map attributes) { + this.attributes = attributes; + } } diff --git a/model/api/src/main/java/org/keycloak/models/ClientModel.java b/model/api/src/main/java/org/keycloak/models/ClientModel.java index 9ca5a70fd74..61e1574bf8f 100755 --- a/model/api/src/main/java/org/keycloak/models/ClientModel.java +++ b/model/api/src/main/java/org/keycloak/models/ClientModel.java @@ -1,5 +1,6 @@ package org.keycloak.models; +import java.util.Map; import java.util.Set; /** @@ -53,6 +54,15 @@ public interface ClientModel { boolean isFullScopeAllowed(); void setFullScopeAllowed(boolean value); + String getProtocol(); + void setProtocol(String protocol); + + void setAttribute(String name, String value); + void removeAttribute(String name); + String getAttribute(String name); + Map getAttributes(); + + boolean isPublicClient(); void setPublicClient(boolean flag); diff --git a/model/api/src/main/java/org/keycloak/models/entities/ClientEntity.java b/model/api/src/main/java/org/keycloak/models/entities/ClientEntity.java index 0d23c35fb65..3ca5761481c 100755 --- a/model/api/src/main/java/org/keycloak/models/entities/ClientEntity.java +++ b/model/api/src/main/java/org/keycloak/models/entities/ClientEntity.java @@ -1,7 +1,9 @@ package org.keycloak.models.entities; import java.util.ArrayList; +import java.util.HashMap; import java.util.List; +import java.util.Map; /** * @author Marek Posolda @@ -11,12 +13,15 @@ public class ClientEntity extends AbstractIdentifiableEntity { private String name; private boolean enabled; private String secret; + private String protocol; private long allowedClaimsMask; private int notBefore; private boolean publicClient; private boolean fullScopeAllowed; private String realmId; + private Map attributes = new HashMap(); + private List webOrigins = new ArrayList(); private List redirectUris = new ArrayList(); @@ -109,4 +114,20 @@ public class ClientEntity extends AbstractIdentifiableEntity { public void setFullScopeAllowed(boolean fullScopeAllowed) { this.fullScopeAllowed = fullScopeAllowed; } + + public String getProtocol() { + return protocol; + } + + public void setProtocol(String protocol) { + this.protocol = protocol; + } + + public Map getAttributes() { + return attributes; + } + + public void setAttributes(Map attributes) { + this.attributes = attributes; + } } diff --git a/model/api/src/main/java/org/keycloak/models/utils/ModelToRepresentation.java b/model/api/src/main/java/org/keycloak/models/utils/ModelToRepresentation.java index 069768058e3..c610e2bc5a5 100755 --- a/model/api/src/main/java/org/keycloak/models/utils/ModelToRepresentation.java +++ b/model/api/src/main/java/org/keycloak/models/utils/ModelToRepresentation.java @@ -212,6 +212,8 @@ public class ModelToRepresentation { rep.setEnabled(applicationModel.isEnabled()); rep.setAdminUrl(applicationModel.getManagementUrl()); rep.setPublicClient(applicationModel.isPublicClient()); + rep.setProtocol(applicationModel.getProtocol()); + rep.setAttributes(applicationModel.getAttributes()); rep.setFullScopeAllowed(applicationModel.isFullScopeAllowed()); rep.setBearerOnly(applicationModel.isBearerOnly()); rep.setSurrogateAuthRequired(applicationModel.isSurrogateAuthRequired()); @@ -241,6 +243,8 @@ public class ModelToRepresentation { rep.setName(model.getClientId()); rep.setEnabled(model.isEnabled()); rep.setPublicClient(model.isPublicClient()); + rep.setProtocol(model.getProtocol()); + rep.setAttributes(model.getAttributes()); rep.setFullScopeAllowed(model.isFullScopeAllowed()); rep.setDirectGrantsOnly(model.isDirectGrantsOnly()); Set redirectUris = model.getRedirectUris(); diff --git a/model/api/src/main/java/org/keycloak/models/utils/RepresentationToModel.java b/model/api/src/main/java/org/keycloak/models/utils/RepresentationToModel.java index f3f3970da79..9d30bcef0dc 100755 --- a/model/api/src/main/java/org/keycloak/models/utils/RepresentationToModel.java +++ b/model/api/src/main/java/org/keycloak/models/utils/RepresentationToModel.java @@ -368,6 +368,7 @@ public class RepresentationToModel { applicationModel.setBaseUrl(resourceRep.getBaseUrl()); if (resourceRep.isBearerOnly() != null) applicationModel.setBearerOnly(resourceRep.isBearerOnly()); if (resourceRep.isPublicClient() != null) applicationModel.setPublicClient(resourceRep.isPublicClient()); + if (resourceRep.getProtocol() != null) applicationModel.setProtocol(resourceRep.getProtocol()); if (resourceRep.isFullScopeAllowed() != null) applicationModel.setFullScopeAllowed(resourceRep.isFullScopeAllowed()); else applicationModel.setFullScopeAllowed(true); applicationModel.updateApplication(); @@ -381,6 +382,12 @@ public class RepresentationToModel { KeycloakModelUtils.generateSecret(applicationModel); } + if (resourceRep.getAttributes() != null) { + for (Map.Entry entry : resourceRep.getAttributes().entrySet()) { + applicationModel.setAttribute(entry.getKey(), entry.getValue()); + } + } + if (resourceRep.getRedirectUris() != null) { for (String redirectUri : resourceRep.getRedirectUris()) { @@ -438,6 +445,14 @@ public class RepresentationToModel { if (rep.isSurrogateAuthRequired() != null) resource.setSurrogateAuthRequired(rep.isSurrogateAuthRequired()); resource.updateApplication(); + if (rep.getProtocol() != null) resource.setProtocol(rep.getProtocol()); + if (rep.getAttributes() != null) { + for (Map.Entry entry : rep.getAttributes().entrySet()) { + resource.setAttribute(entry.getKey(), entry.getValue()); + } + } + + if (rep.getNotBefore() != null) { resource.setNotBefore(rep.getNotBefore()); } @@ -565,6 +580,12 @@ public class RepresentationToModel { if (rep.getNotBefore() != null) { model.setNotBefore(rep.getNotBefore()); } + if (rep.getProtocol() != null) model.setProtocol(rep.getProtocol()); + if (rep.getAttributes() != null) { + for (Map.Entry entry : rep.getAttributes().entrySet()) { + model.setAttribute(entry.getKey(), entry.getValue()); + } + } } diff --git a/model/invalidation-cache/model-adapters/src/main/java/org/keycloak/models/cache/ClientAdapter.java b/model/invalidation-cache/model-adapters/src/main/java/org/keycloak/models/cache/ClientAdapter.java index 1565e4358b1..854fa62a97e 100755 --- a/model/invalidation-cache/model-adapters/src/main/java/org/keycloak/models/cache/ClientAdapter.java +++ b/model/invalidation-cache/model-adapters/src/main/java/org/keycloak/models/cache/ClientAdapter.java @@ -6,7 +6,9 @@ import org.keycloak.models.RoleContainerModel; import org.keycloak.models.RoleModel; import org.keycloak.models.cache.entities.CachedClient; +import java.util.HashMap; import java.util.HashSet; +import java.util.Map; import java.util.Set; /** @@ -208,4 +210,43 @@ public abstract class ClientAdapter implements ClientModel { updatedClient.setNotBefore(notBefore); } + @Override + public String getProtocol() { + if (updatedClient != null) return updatedClient.getProtocol(); + return cachedClient.getProtocol(); + } + + @Override + public void setProtocol(String protocol) { + getDelegateForUpdate(); + updatedClient.setProtocol(protocol); + } + + @Override + public void setAttribute(String name, String value) { + getDelegateForUpdate(); + updatedClient.setAttribute(name, value); + + } + + @Override + public void removeAttribute(String name) { + getDelegateForUpdate(); + updatedClient.removeAttribute(name); + + } + + @Override + public String getAttribute(String name) { + if (updatedClient != null) return updatedClient.getAttribute(name); + return cachedClient.getAttributes().get(name); + } + + @Override + public Map getAttributes() { + if (updatedClient != null) return updatedClient.getAttributes(); + Map copy = new HashMap(); + copy.putAll(cachedClient.getAttributes()); + return copy; + } } diff --git a/model/invalidation-cache/model-adapters/src/main/java/org/keycloak/models/cache/entities/CachedClient.java b/model/invalidation-cache/model-adapters/src/main/java/org/keycloak/models/cache/entities/CachedClient.java index 5ee1e8d2891..484619fbdcc 100755 --- a/model/invalidation-cache/model-adapters/src/main/java/org/keycloak/models/cache/entities/CachedClient.java +++ b/model/invalidation-cache/model-adapters/src/main/java/org/keycloak/models/cache/entities/CachedClient.java @@ -6,7 +6,9 @@ import org.keycloak.models.RealmProvider; import org.keycloak.models.RoleModel; import org.keycloak.models.cache.RealmCache; +import java.util.HashMap; import java.util.HashSet; +import java.util.Map; import java.util.Set; /** @@ -21,6 +23,8 @@ public class CachedClient { protected Set redirectUris = new HashSet(); protected boolean enabled; protected String secret; + protected String protocol; + protected Map attributes = new HashMap(); protected boolean publicClient; protected boolean fullScopeAllowed; protected boolean directGrantsOnly; @@ -34,6 +38,8 @@ public class CachedClient { name = model.getClientId(); this.realm = realm.getId(); enabled = model.isEnabled(); + protocol = model.getProtocol(); + attributes.putAll(model.getAttributes()); notBefore = model.getNotBefore(); directGrantsOnly = model.isDirectGrantsOnly(); publicClient = model.isPublicClient(); @@ -98,4 +104,12 @@ public class CachedClient { public boolean isFullScopeAllowed() { return fullScopeAllowed; } + + public String getProtocol() { + return protocol; + } + + public Map getAttributes() { + return attributes; + } } diff --git a/model/jpa/src/main/java/org/keycloak/models/jpa/ClientAdapter.java b/model/jpa/src/main/java/org/keycloak/models/jpa/ClientAdapter.java index 16a370e4d25..51257da7c0d 100755 --- a/model/jpa/src/main/java/org/keycloak/models/jpa/ClientAdapter.java +++ b/model/jpa/src/main/java/org/keycloak/models/jpa/ClientAdapter.java @@ -10,8 +10,10 @@ import org.keycloak.models.jpa.entities.ScopeMappingEntity; import javax.persistence.EntityManager; import javax.persistence.TypedQuery; +import java.util.HashMap; import java.util.HashSet; import java.util.List; +import java.util.Map; import java.util.Set; /** @@ -247,4 +249,38 @@ public abstract class ClientAdapter implements ClientModel { public int hashCode() { return entity.getId().hashCode(); } + + @Override + public String getProtocol() { + return entity.getProtocol(); + } + + @Override + public void setProtocol(String protocol) { + entity.setProtocol(protocol); + + } + + @Override + public void setAttribute(String name, String value) { + entity.getAttributes().put(name, value); + + } + + @Override + public void removeAttribute(String name) { + entity.getAttributes().remove(name); + } + + @Override + public String getAttribute(String name) { + return entity.getAttributes().get(name); + } + + @Override + public Map getAttributes() { + Map copy = new HashMap(); + copy.putAll(entity.getAttributes()); + return copy; + } } diff --git a/model/jpa/src/main/java/org/keycloak/models/jpa/entities/AttributeMap.java b/model/jpa/src/main/java/org/keycloak/models/jpa/entities/AttributeMap.java deleted file mode 100755 index 625b051bba7..00000000000 --- a/model/jpa/src/main/java/org/keycloak/models/jpa/entities/AttributeMap.java +++ /dev/null @@ -1,72 +0,0 @@ -package org.keycloak.models.jpa.entities; - -import java.util.HashMap; -import java.util.Map; - -/** - * @author Bill Burke - * @version $Revision: 1 $ - */ -public class AttributeMap { - Map attributes = new HashMap(); - - public void set(String key, String value) { - attributes.put(key, value); - } - - public void set(String key, Boolean value) { - attributes.put(key, value.toString()); - } - - public void set(String key, Integer value) { - attributes.put(key, value.toString()); - } - - public String get(String key) { - return attributes.get(key); - } - - public String get(String key, String defaultValue) { - String value = attributes.get(key); - return value == null ? defaultValue : value; - } - - public String[] getArray(String key) { - String value = get(key); - if (value != null) { - String[] a = value.split(","); - for (int i = 0; i < a.length; i++) { - a[i] = a[i].trim(); - } - return a; - } else { - return null; - } - } - - public Integer getInt(String key) { - return getInt(key, null); - } - - public Integer getInt(String key, Integer defaultValue) { - String v = get(key, null); - return v != null ? Integer.parseInt(v) : defaultValue; - } - - public Long getLong(String key) { - return getLong(key, null); - } - - public Long getLong(String key, Long defaultValue) { - String v = get(key, null); - return v != null ? Long.parseLong(v) : defaultValue; - } - - public Boolean getBoolean(String key) { - return getBoolean(key, null); - } - - public Boolean getBoolean(String key, Boolean defaultValue) { - String v = get(key, null); - return v != null ? Boolean.parseBoolean(v) : defaultValue; - }} diff --git a/model/jpa/src/main/java/org/keycloak/models/jpa/entities/ClientEntity.java b/model/jpa/src/main/java/org/keycloak/models/jpa/entities/ClientEntity.java index 7bc66c39b4f..c5652a82f57 100755 --- a/model/jpa/src/main/java/org/keycloak/models/jpa/entities/ClientEntity.java +++ b/model/jpa/src/main/java/org/keycloak/models/jpa/entities/ClientEntity.java @@ -10,9 +10,12 @@ import javax.persistence.Inheritance; import javax.persistence.InheritanceType; import javax.persistence.JoinColumn; import javax.persistence.ManyToOne; +import javax.persistence.MapKeyColumn; import javax.persistence.Table; import javax.persistence.UniqueConstraint; +import java.util.HashMap; import java.util.HashSet; +import java.util.Map; import java.util.Set; /** @@ -38,6 +41,8 @@ public abstract class ClientEntity { private int notBefore; @Column(name="PUBLIC_CLIENT") private boolean publicClient; + @Column(name="PROTOCOL") + private String protocol; @Column(name="FULL_SCOPE_ALLOWED") private boolean fullScopeAllowed; @@ -55,6 +60,12 @@ public abstract class ClientEntity { @CollectionTable(name = "REDIRECT_URIS", joinColumns={ @JoinColumn(name="CLIENT_ID") }) protected Set redirectUris = new HashSet(); + @ElementCollection + @MapKeyColumn(name="NAME") + @Column(name="VALUE", length = 2048) + @CollectionTable(name="CLIENT_ATTRIBUTES", joinColumns={ @JoinColumn(name="CLIENT_ID") }) + protected Map attributes = new HashMap(); + public RealmEntity getRealm() { return realm; } @@ -142,4 +153,20 @@ public abstract class ClientEntity { public void setFullScopeAllowed(boolean fullScopeAllowed) { this.fullScopeAllowed = fullScopeAllowed; } + + public Map getAttributes() { + return attributes; + } + + public void setAttributes(Map attributes) { + this.attributes = attributes; + } + + public String getProtocol() { + return protocol; + } + + public void setProtocol(String protocol) { + this.protocol = protocol; + } } diff --git a/model/mongo/src/main/java/org/keycloak/models/mongo/keycloak/adapters/ClientAdapter.java b/model/mongo/src/main/java/org/keycloak/models/mongo/keycloak/adapters/ClientAdapter.java index dae9f4fcb78..b549f36db64 100755 --- a/model/mongo/src/main/java/org/keycloak/models/mongo/keycloak/adapters/ClientAdapter.java +++ b/model/mongo/src/main/java/org/keycloak/models/mongo/keycloak/adapters/ClientAdapter.java @@ -12,8 +12,10 @@ import org.keycloak.models.mongo.keycloak.entities.MongoRoleEntity; import org.keycloak.models.mongo.utils.MongoModelUtils; import java.util.ArrayList; +import java.util.HashMap; import java.util.HashSet; import java.util.List; +import java.util.Map; import java.util.Set; /** @@ -240,4 +242,42 @@ public abstract class ClientAdapter extends A getMongoStore().pullItemFromList(this.getMongoEntity(), "scopeIds", role.getId(), invocationContext); } + @Override + public String getProtocol() { + return getMongoEntityAsClient().getProtocol(); + } + + @Override + public void setProtocol(String protocol) { + getMongoEntityAsClient().setProtocol(protocol); + updateMongoEntity(); + + } + + @Override + public void setAttribute(String name, String value) { + getMongoEntityAsClient().getAttributes().put(name, value); + updateMongoEntity(); + + } + + @Override + public void removeAttribute(String name) { + getMongoEntityAsClient().getAttributes().remove(name); + updateMongoEntity(); + } + + @Override + public String getAttribute(String name) { + return getMongoEntityAsClient().getAttributes().get(name); + } + + @Override + public Map getAttributes() { + Map copy = new HashMap(); + copy.putAll(getMongoEntityAsClient().getAttributes()); + return copy; + } + + } 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 240d5cb4980..e1402c9ad3c 100755 --- a/services/src/main/java/org/keycloak/services/managers/RealmManager.java +++ b/services/src/main/java/org/keycloak/services/managers/RealmManager.java @@ -18,6 +18,7 @@ import org.keycloak.models.UserModel; import org.keycloak.models.UserSessionProvider; import org.keycloak.models.utils.KeycloakModelUtils; import org.keycloak.models.utils.RepresentationToModel; +import org.keycloak.protocol.oidc.OpenIDConnect; import org.keycloak.representations.idm.ApplicationRepresentation; import org.keycloak.representations.idm.RealmEventsConfigRepresentation; import org.keycloak.representations.idm.RealmRepresentation;