keycloak-aplcache

claims backend

2/26/2014 5:29:17 PM

Changes

Details

diff --git a/core/src/main/java/org/keycloak/representations/AccessToken.java b/core/src/main/java/org/keycloak/representations/AccessToken.java
index c99a509..7f55dd9 100755
--- a/core/src/main/java/org/keycloak/representations/AccessToken.java
+++ b/core/src/main/java/org/keycloak/representations/AccessToken.java
@@ -12,7 +12,7 @@ import java.util.Set;
  * @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
  * @version $Revision: 1 $
  */
-public class AccessToken extends JsonWebToken {
+public class AccessToken extends IDToken {
     public static class Access {
         @JsonProperty("roles")
         protected Set<String> roles;
diff --git a/core/src/main/java/org/keycloak/representations/AccessTokenResponse.java b/core/src/main/java/org/keycloak/representations/AccessTokenResponse.java
index 985dae4..2ed5081 100755
--- a/core/src/main/java/org/keycloak/representations/AccessTokenResponse.java
+++ b/core/src/main/java/org/keycloak/representations/AccessTokenResponse.java
@@ -21,6 +21,9 @@ public class AccessTokenResponse {
     @JsonProperty("token_type")
     protected String tokenType;
 
+    @JsonProperty("id_token")
+    protected String idToken;
+
     public String getToken() {
         return token;
     }
@@ -52,4 +55,12 @@ public class AccessTokenResponse {
     public void setTokenType(String tokenType) {
         this.tokenType = tokenType;
     }
+
+    public String getIdToken() {
+        return idToken;
+    }
+
+    public void setIdToken(String idToken) {
+        this.idToken = idToken;
+    }
 }
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 5cb4a1d..601bce5 100755
--- a/core/src/main/java/org/keycloak/representations/idm/ApplicationRepresentation.java
+++ b/core/src/main/java/org/keycloak/representations/idm/ApplicationRepresentation.java
@@ -18,6 +18,7 @@ public class ApplicationRepresentation {
     protected String[] defaultRoles;
     protected List<String> redirectUris;
     protected List<String> webOrigins;
+    protected ClaimRepresentation claims;
 
     public String getId() {
         return id;
@@ -107,4 +108,12 @@ public class ApplicationRepresentation {
     public void setDefaultRoles(String[] defaultRoles) {
         this.defaultRoles = defaultRoles;
     }
+
+    public ClaimRepresentation getClaims() {
+        return claims;
+    }
+
+    public void setClaims(ClaimRepresentation claims) {
+        this.claims = claims;
+    }
 }
diff --git a/core/src/main/java/org/keycloak/representations/idm/ClaimRepresentation.java b/core/src/main/java/org/keycloak/representations/idm/ClaimRepresentation.java
new file mode 100755
index 0000000..1783d89
--- /dev/null
+++ b/core/src/main/java/org/keycloak/representations/idm/ClaimRepresentation.java
@@ -0,0 +1,98 @@
+package org.keycloak.representations.idm;
+
+/**
+ * @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
+ * @version $Revision: 1 $
+ */
+public class ClaimRepresentation {
+    protected boolean name;
+    protected boolean username;
+    protected boolean profile;
+    protected boolean picture;
+    protected boolean website;
+    protected boolean email;
+    protected boolean gender;
+    protected boolean locale;
+    protected boolean address;
+    protected boolean phone;
+
+    public boolean getName() {
+        return name;
+    }
+
+    public void setName(boolean name) {
+        this.name = name;
+    }
+
+    public boolean getUsername() {
+        return username;
+    }
+
+    public void setUsername(boolean username) {
+        this.username = username;
+    }
+
+    public boolean getProfile() {
+        return profile;
+    }
+
+    public void setProfile(boolean profile) {
+        this.profile = profile;
+    }
+
+    public boolean getPicture() {
+        return picture;
+    }
+
+    public void setPicture(boolean picture) {
+        this.picture = picture;
+    }
+
+    public boolean getWebsite() {
+        return website;
+    }
+
+    public void setWebsite(boolean website) {
+        this.website = website;
+    }
+
+    public boolean getEmail() {
+        return email;
+    }
+
+    public void setEmail(boolean email) {
+        this.email = email;
+    }
+
+    public boolean getGender() {
+        return gender;
+    }
+
+    public void setGender(boolean gender) {
+        this.gender = gender;
+    }
+
+    public boolean getLocale() {
+        return locale;
+    }
+
+    public void setLocale(boolean locale) {
+        this.locale = locale;
+    }
+
+    public boolean getAddress() {
+        return address;
+    }
+
+    public void setAddress(boolean address) {
+        this.address = address;
+    }
+
+    public boolean getPhone() {
+        return phone;
+    }
+
+    public void setPhone(boolean phone) {
+        this.phone = phone;
+    }
+}
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 be44c43..cfd33dd 100755
--- a/core/src/main/java/org/keycloak/representations/idm/OAuthClientRepresentation.java
+++ b/core/src/main/java/org/keycloak/representations/idm/OAuthClientRepresentation.java
@@ -14,6 +14,7 @@ public class OAuthClientRepresentation {
     protected List<String> webOrigins;
     protected boolean enabled;
     protected List<CredentialRepresentation> credentials;
+    protected ClaimRepresentation claims;
 
     public String getId() {
         return id;
@@ -70,4 +71,12 @@ public class OAuthClientRepresentation {
     public void setCredentials(List<CredentialRepresentation> credentials) {
         this.credentials = credentials;
     }
+
+    public ClaimRepresentation getClaims() {
+        return claims;
+    }
+
+    public void setClaims(ClaimRepresentation claims) {
+        this.claims = claims;
+    }
 }
diff --git a/core/src/main/java/org/keycloak/representations/IDToken.java b/core/src/main/java/org/keycloak/representations/IDToken.java
new file mode 100755
index 0000000..08514a9
--- /dev/null
+++ b/core/src/main/java/org/keycloak/representations/IDToken.java
@@ -0,0 +1,306 @@
+package org.keycloak.representations;
+
+import org.codehaus.jackson.annotate.JsonProperty;
+
+/**
+ * @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
+ * @version $Revision: 1 $
+ */
+public class IDToken extends JsonWebToken {
+    @JsonProperty("nonce")
+    protected String nonce;
+
+    @JsonProperty("name")
+    protected String name;
+
+    @JsonProperty("given_name")
+    protected String givenName;
+
+    @JsonProperty("family_name")
+    protected String familyName;
+
+    @JsonProperty("middle_name")
+    protected String middleName;
+
+    @JsonProperty("nickname")
+    protected String nickName;
+
+    @JsonProperty("preferred_username")
+    protected String preferredUsername;
+
+    @JsonProperty("profile")
+    protected String profile;
+
+    @JsonProperty("picture")
+    protected String picture;
+
+    @JsonProperty("website")
+    protected String website;
+
+    @JsonProperty("email")
+    protected String email;
+
+    @JsonProperty("email_verified")
+    protected Boolean emailVerified;
+
+    @JsonProperty("gender")
+    protected String gender;
+
+    @JsonProperty("birthdate")
+    protected String birthdate;
+
+    @JsonProperty("zoneinfo")
+    protected String zoneinfo;
+
+    @JsonProperty("locale")
+    protected String locale;
+
+    @JsonProperty("phone_number")
+    protected String phoneNumber;
+
+    @JsonProperty("phone_number_verified")
+    protected Boolean phoneNumberVerified;
+
+    @JsonProperty("address")
+    protected String address;
+
+    @JsonProperty("updated_at")
+    protected Long updatedAt;
+
+    @JsonProperty("formatted")
+    protected String formattedAddress;
+
+    @JsonProperty("street_address")
+    protected String streetAddress;
+
+    @JsonProperty("locality")
+    protected String locality;
+
+    @JsonProperty("region")
+    protected String region;
+
+    @JsonProperty("postal_code")
+    protected String postalCode;
+
+    @JsonProperty("country")
+    protected String country;
+
+    @JsonProperty("claims_locales")
+    protected String claimsLocales;
+
+    public String getNonce() {
+        return nonce;
+    }
+
+    public void setNonce(String nonce) {
+        this.nonce = nonce;
+    }
+
+    public String getName() {
+        return name;
+    }
+
+    public void setName(String name) {
+        this.name = name;
+    }
+
+    public String getGivenName() {
+        return givenName;
+    }
+
+    public void setGivenName(String givenName) {
+        this.givenName = givenName;
+    }
+
+    public String getFamilyName() {
+        return familyName;
+    }
+
+    public void setFamilyName(String familyName) {
+        this.familyName = familyName;
+    }
+
+    public String getMiddleName() {
+        return middleName;
+    }
+
+    public void setMiddleName(String middleName) {
+        this.middleName = middleName;
+    }
+
+    public String getNickName() {
+        return nickName;
+    }
+
+    public void setNickName(String nickName) {
+        this.nickName = nickName;
+    }
+
+    public String getPreferredUsername() {
+        return preferredUsername;
+    }
+
+    public void setPreferredUsername(String preferredUsername) {
+        this.preferredUsername = preferredUsername;
+    }
+
+    public String getProfile() {
+        return profile;
+    }
+
+    public void setProfile(String profile) {
+        this.profile = profile;
+    }
+
+    public String getPicture() {
+        return picture;
+    }
+
+    public void setPicture(String picture) {
+        this.picture = picture;
+    }
+
+    public String getWebsite() {
+        return website;
+    }
+
+    public void setWebsite(String website) {
+        this.website = website;
+    }
+
+    public String getEmail() {
+        return email;
+    }
+
+    public void setEmail(String email) {
+        this.email = email;
+    }
+
+    public Boolean getEmailVerified() {
+        return emailVerified;
+    }
+
+    public void setEmailVerified(Boolean emailVerified) {
+        this.emailVerified = emailVerified;
+    }
+
+    public String getGender() {
+        return gender;
+    }
+
+    public void setGender(String gender) {
+        this.gender = gender;
+    }
+
+    public String getBirthdate() {
+        return birthdate;
+    }
+
+    public void setBirthdate(String birthdate) {
+        this.birthdate = birthdate;
+    }
+
+    public String getZoneinfo() {
+        return zoneinfo;
+    }
+
+    public void setZoneinfo(String zoneinfo) {
+        this.zoneinfo = zoneinfo;
+    }
+
+    public String getLocale() {
+        return locale;
+    }
+
+    public void setLocale(String locale) {
+        this.locale = locale;
+    }
+
+    public String getPhoneNumber() {
+        return phoneNumber;
+    }
+
+    public void setPhoneNumber(String phoneNumber) {
+        this.phoneNumber = phoneNumber;
+    }
+
+    public Boolean getPhoneNumberVerified() {
+        return phoneNumberVerified;
+    }
+
+    public void setPhoneNumberVerified(Boolean phoneNumberVerified) {
+        this.phoneNumberVerified = phoneNumberVerified;
+    }
+
+    public String getAddress() {
+        return address;
+    }
+
+    public void setAddress(String address) {
+        this.address = address;
+    }
+
+    public Long getUpdatedAt() {
+        return updatedAt;
+    }
+
+    public void setUpdatedAt(Long updatedAt) {
+        this.updatedAt = updatedAt;
+    }
+
+    public String getFormattedAddress() {
+        return formattedAddress;
+    }
+
+    public void setFormattedAddress(String formattedAddress) {
+        this.formattedAddress = formattedAddress;
+    }
+
+    public String getStreetAddress() {
+        return streetAddress;
+    }
+
+    public void setStreetAddress(String streetAddress) {
+        this.streetAddress = streetAddress;
+    }
+
+    public String getLocality() {
+        return locality;
+    }
+
+    public void setLocality(String locality) {
+        this.locality = locality;
+    }
+
+    public String getRegion() {
+        return region;
+    }
+
+    public void setRegion(String region) {
+        this.region = region;
+    }
+
+    public String getPostalCode() {
+        return postalCode;
+    }
+
+    public void setPostalCode(String postalCode) {
+        this.postalCode = postalCode;
+    }
+
+    public String getCountry() {
+        return country;
+    }
+
+    public void setCountry(String country) {
+        this.country = country;
+    }
+
+    public String getClaimsLocales() {
+        return claimsLocales;
+    }
+
+    public void setClaimsLocales(String claimsLocales) {
+        this.claimsLocales = claimsLocales;
+    }
+}
diff --git a/docbook/reference/en/en-US/modules/Overview.xml b/docbook/reference/en/en-US/modules/Overview.xml
index bdd3b2b..3910cea 100755
--- a/docbook/reference/en/en-US/modules/Overview.xml
+++ b/docbook/reference/en/en-US/modules/Overview.xml
@@ -32,6 +32,10 @@
             </listitem>
 
             <listitem>
+                Pluggable theme and style support for user facing screens.
+            </listitem>
+
+            <listitem>
                 OAuth Bearer token auth for REST Services
             </listitem>
 
@@ -60,7 +64,7 @@
                 Deployable as a WAR, appliance, or on Openshift.
             </listitem>
             <listitem>
-                Supports JBoss AS7, EAP 6.x, and Wildfly applications.  Plans to support Node.js, RAILS, GRAILS, and other non-Java application
+                Supports JBoss AS7, EAP 6.x, and Wildfly applications.  Plans to support Node.js, RAILS, GRAILS, and other non-Java deployments
             </listitem>
         </itemizedlist>
     </para>
diff --git a/model/api/src/main/java/org/keycloak/models/ApplicationModel.java b/model/api/src/main/java/org/keycloak/models/ApplicationModel.java
index 4657644..79f1421 100755
--- a/model/api/src/main/java/org/keycloak/models/ApplicationModel.java
+++ b/model/api/src/main/java/org/keycloak/models/ApplicationModel.java
@@ -7,7 +7,7 @@ import java.util.Set;
  * @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
  * @version $Revision: 1 $
  */
-public interface ApplicationModel extends RoleContainerModel {
+public interface ApplicationModel extends RoleContainerModel, ClaimRequesterModel {
     void updateApplication();
 
     UserModel getApplicationUser();
@@ -45,4 +45,5 @@ public interface ApplicationModel extends RoleContainerModel {
     Set<RoleModel> getApplicationScopeMappings(UserModel user);
 
     void addScope(RoleModel role);
+
 }
diff --git a/model/api/src/main/java/org/keycloak/models/ClaimMask.java b/model/api/src/main/java/org/keycloak/models/ClaimMask.java
new file mode 100755
index 0000000..7d4334c
--- /dev/null
+++ b/model/api/src/main/java/org/keycloak/models/ClaimMask.java
@@ -0,0 +1,50 @@
+package org.keycloak.models;
+
+/**
+ * @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
+ * @version $Revision: 1 $
+ */
+public class ClaimMask {
+    public static final long NAME = 0x01l;
+    public static final long USERNAME = 0x02l;
+    public static final long PROFILE = 0x04l;
+    public static final long PICTURE = 0x08l;
+    public static final long WEBSITE = 0x10l;
+    public static final long EMAIL = 0x20l;
+    public static final long GENDER = 0x40l;
+    public static final long LOCALE = 0x80l;
+    public static final long ADDRESS = 0x100l;
+    public static final long PHONE = 0x200l;
+
+    public static boolean hasName(long mask) {
+        return (mask & NAME) > 0;
+    }
+    public static boolean hasUsername(long mask) {
+        return (mask & USERNAME) > 0;
+    }
+    public static boolean hasProfile(long mask) {
+        return (mask & PROFILE) > 0;
+    }
+    public static boolean hasPicture(long mask) {
+        return (mask & PICTURE) > 0;
+    }
+    public static boolean hasWebsite(long mask) {
+        return (mask & WEBSITE) > 0;
+    }
+    public static boolean hasEmail(long mask) {
+        return (mask & EMAIL) > 0;
+    }
+    public static boolean hasGender(long mask) {
+        return (mask & GENDER) > 0;
+    }
+    public static boolean hasLocale(long mask) {
+        return (mask & LOCALE) > 0;
+    }
+    public static boolean hasAddress(long mask) {
+        return (mask & ADDRESS) > 0;
+    }
+    public static boolean hasPhone(long mask) {
+        return (mask & PHONE) > 0;
+    }
+
+}
diff --git a/model/api/src/main/java/org/keycloak/models/ClaimRequesterModel.java b/model/api/src/main/java/org/keycloak/models/ClaimRequesterModel.java
new file mode 100755
index 0000000..3ef5cf7
--- /dev/null
+++ b/model/api/src/main/java/org/keycloak/models/ClaimRequesterModel.java
@@ -0,0 +1,11 @@
+package org.keycloak.models;
+
+/**
+ * @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
+ * @version $Revision: 1 $
+ */
+public interface ClaimRequesterModel {
+    long getAllowedClaimsMask();
+
+    void setAllowedClaimsMask(long mask);
+}
diff --git a/model/api/src/main/java/org/keycloak/models/OAuthClientModel.java b/model/api/src/main/java/org/keycloak/models/OAuthClientModel.java
index 622500c..5d59f24 100755
--- a/model/api/src/main/java/org/keycloak/models/OAuthClientModel.java
+++ b/model/api/src/main/java/org/keycloak/models/OAuthClientModel.java
@@ -4,8 +4,9 @@ package org.keycloak.models;
  * @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
  * @version $Revision: 1 $
  */
-public interface OAuthClientModel {
+public interface OAuthClientModel extends ClaimRequesterModel {
     String getId();
 
     UserModel getOAuthAgent();
+
 }
diff --git a/model/jpa/src/main/java/org/keycloak/models/jpa/ApplicationAdapter.java b/model/jpa/src/main/java/org/keycloak/models/jpa/ApplicationAdapter.java
index 9c25a38..575ba06 100755
--- a/model/jpa/src/main/java/org/keycloak/models/jpa/ApplicationAdapter.java
+++ b/model/jpa/src/main/java/org/keycloak/models/jpa/ApplicationAdapter.java
@@ -71,6 +71,16 @@ public class ApplicationAdapter implements ApplicationModel {
     }
 
     @Override
+    public long getAllowedClaimsMask() {
+        return application.getAllowedClaimsMask();
+    }
+
+    @Override
+    public void setAllowedClaimsMask(long mask) {
+        application.setAllowedClaimsMask(mask);
+    }
+
+    @Override
     public boolean isSurrogateAuthRequired() {
         return application.isSurrogateAuthRequired();
     }
diff --git a/model/jpa/src/main/java/org/keycloak/models/jpa/entities/ApplicationEntity.java b/model/jpa/src/main/java/org/keycloak/models/jpa/entities/ApplicationEntity.java
index 19a5981..b85f720 100755
--- a/model/jpa/src/main/java/org/keycloak/models/jpa/entities/ApplicationEntity.java
+++ b/model/jpa/src/main/java/org/keycloak/models/jpa/entities/ApplicationEntity.java
@@ -30,6 +30,7 @@ public class ApplicationEntity {
     private boolean surrogateAuthRequired;
     private String baseUrl;
     private String managementUrl;
+    private long allowedClaimsMask;
 
     @OneToOne(fetch = FetchType.EAGER)
     private UserEntity applicationUser;
@@ -119,4 +120,12 @@ public class ApplicationEntity {
     public void setRealm(RealmEntity realm) {
         this.realm = realm;
     }
+
+    public long getAllowedClaimsMask() {
+        return allowedClaimsMask;
+    }
+
+    public void setAllowedClaimsMask(long allowedClaimsMask) {
+        this.allowedClaimsMask = allowedClaimsMask;
+    }
 }
diff --git a/model/jpa/src/main/java/org/keycloak/models/jpa/entities/OAuthClientEntity.java b/model/jpa/src/main/java/org/keycloak/models/jpa/entities/OAuthClientEntity.java
index d266ed7..9a114a1 100755
--- a/model/jpa/src/main/java/org/keycloak/models/jpa/entities/OAuthClientEntity.java
+++ b/model/jpa/src/main/java/org/keycloak/models/jpa/entities/OAuthClientEntity.java
@@ -28,6 +28,7 @@ public class OAuthClientEntity {
     private String id;
 
     private String name;
+    private long allowedClaimsMask;
 
     @OneToOne(fetch = FetchType.EAGER)
     private UserEntity agent;
@@ -62,4 +63,13 @@ public class OAuthClientEntity {
     public void setRealm(RealmEntity realm) {
         this.realm = realm;
     }
+
+    public long getAllowedClaimsMask() {
+        return allowedClaimsMask;
+    }
+
+    public void setAllowedClaimsMask(long allowedClaimsMask) {
+        this.allowedClaimsMask = allowedClaimsMask;
+    }
+
 }
diff --git a/model/jpa/src/main/java/org/keycloak/models/jpa/OAuthClientAdapter.java b/model/jpa/src/main/java/org/keycloak/models/jpa/OAuthClientAdapter.java
index fd2afcc..aaea68e 100755
--- a/model/jpa/src/main/java/org/keycloak/models/jpa/OAuthClientAdapter.java
+++ b/model/jpa/src/main/java/org/keycloak/models/jpa/OAuthClientAdapter.java
@@ -28,5 +28,16 @@ public class OAuthClientAdapter implements OAuthClientModel {
     public UserModel getOAuthAgent() {
         return new UserAdapter(entity.getAgent());
     }
+    @Override
+    public long getAllowedClaimsMask() {
+        return entity.getAllowedClaimsMask();
+    }
+
+    @Override
+    public void setAllowedClaimsMask(long mask) {
+        entity.setAllowedClaimsMask(mask);
+    }
+
+
 
 }
diff --git a/model/mongo/src/main/java/org/keycloak/models/mongo/keycloak/adapters/ApplicationAdapter.java b/model/mongo/src/main/java/org/keycloak/models/mongo/keycloak/adapters/ApplicationAdapter.java
index 80835f2..40bbfe5 100755
--- a/model/mongo/src/main/java/org/keycloak/models/mongo/keycloak/adapters/ApplicationAdapter.java
+++ b/model/mongo/src/main/java/org/keycloak/models/mongo/keycloak/adapters/ApplicationAdapter.java
@@ -110,6 +110,17 @@ public class ApplicationAdapter extends AbstractAdapter implements ApplicationMo
     }
 
     @Override
+    public long getAllowedClaimsMask() {
+        return application.getAllowedClaimsMask();
+    }
+
+    @Override
+    public void setAllowedClaimsMask(long mask) {
+        application.setAllowedClaimsMask(mask);
+    }
+
+
+    @Override
     public RoleAdapter getRole(String name) {
         DBObject query = new QueryBuilder()
                 .and("name").is(name)
diff --git a/model/mongo/src/main/java/org/keycloak/models/mongo/keycloak/adapters/OAuthClientAdapter.java b/model/mongo/src/main/java/org/keycloak/models/mongo/keycloak/adapters/OAuthClientAdapter.java
index 2eacc45..e53eb44 100755
--- a/model/mongo/src/main/java/org/keycloak/models/mongo/keycloak/adapters/OAuthClientAdapter.java
+++ b/model/mongo/src/main/java/org/keycloak/models/mongo/keycloak/adapters/OAuthClientAdapter.java
@@ -31,6 +31,16 @@ public class OAuthClientAdapter extends AbstractAdapter implements OAuthClientMo
     }
 
     @Override
+    public long getAllowedClaimsMask() {
+        return delegate.getAllowedClaimsMask();
+    }
+
+    @Override
+    public void setAllowedClaimsMask(long mask) {
+        delegate.setAllowedClaimsMask(mask);
+    }
+
+    @Override
     public UserModel getOAuthAgent() {
         // This is not thread-safe. Assumption is that OAuthClientAdapter instance is per-client object
         if (oauthAgent == null) {
diff --git a/model/mongo/src/main/java/org/keycloak/models/mongo/keycloak/entities/ApplicationEntity.java b/model/mongo/src/main/java/org/keycloak/models/mongo/keycloak/entities/ApplicationEntity.java
old mode 100644
new mode 100755
index 39a6234..2a03171
--- a/model/mongo/src/main/java/org/keycloak/models/mongo/keycloak/entities/ApplicationEntity.java
+++ b/model/mongo/src/main/java/org/keycloak/models/mongo/keycloak/entities/ApplicationEntity.java
@@ -25,6 +25,7 @@ public class ApplicationEntity extends AbstractMongoIdentifiableEntity implement
 
     private String resourceUserId;
     private String realmId;
+    private long allowedClaimsMask;
 
     // We are using names of defaultRoles (not ids)
     private List<String> defaultRoles = new ArrayList<String>();
@@ -84,6 +85,15 @@ public class ApplicationEntity extends AbstractMongoIdentifiableEntity implement
     }
 
     @MongoField
+    public long getAllowedClaimsMask() {
+        return allowedClaimsMask;
+    }
+
+    public void setAllowedClaimsMask(long allowedClaimsMask) {
+        this.allowedClaimsMask = allowedClaimsMask;
+    }
+
+    @MongoField
     public String getRealmId() {
         return realmId;
     }
diff --git a/model/mongo/src/main/java/org/keycloak/models/mongo/keycloak/entities/OAuthClientEntity.java b/model/mongo/src/main/java/org/keycloak/models/mongo/keycloak/entities/OAuthClientEntity.java
old mode 100644
new mode 100755
index f2875b1..78c3687
--- a/model/mongo/src/main/java/org/keycloak/models/mongo/keycloak/entities/OAuthClientEntity.java
+++ b/model/mongo/src/main/java/org/keycloak/models/mongo/keycloak/entities/OAuthClientEntity.java
@@ -16,6 +16,7 @@ public class OAuthClientEntity extends AbstractMongoIdentifiableEntity implement
 
     private String oauthAgentId;
     private String realmId;
+    private long allowedClaimsMask;
 
     @MongoField
     public String getName() {
@@ -44,6 +45,15 @@ public class OAuthClientEntity extends AbstractMongoIdentifiableEntity implement
         this.realmId = realmId;
     }
 
+    @MongoField
+    public long getAllowedClaimsMask() {
+        return allowedClaimsMask;
+    }
+
+    public void setAllowedClaimsMask(long allowedClaimsMask) {
+        this.allowedClaimsMask = allowedClaimsMask;
+    }
+
     @Override
     public void afterRemove(MongoStoreInvocationContext context) {
         // Remove user of this oauthClient
diff --git a/services/src/main/java/org/keycloak/services/managers/ApplicationManager.java b/services/src/main/java/org/keycloak/services/managers/ApplicationManager.java
index 55642a2..7fab54d 100755
--- a/services/src/main/java/org/keycloak/services/managers/ApplicationManager.java
+++ b/services/src/main/java/org/keycloak/services/managers/ApplicationManager.java
@@ -4,6 +4,7 @@ import org.codehaus.jackson.annotate.JsonProperty;
 import org.codehaus.jackson.annotate.JsonPropertyOrder;
 import org.jboss.resteasy.logging.Logger;
 import org.keycloak.models.ApplicationModel;
+import org.keycloak.models.ClaimMask;
 import org.keycloak.models.Constants;
 import org.keycloak.models.RealmModel;
 import org.keycloak.models.RoleModel;
@@ -89,6 +90,12 @@ public class ApplicationManager {
             applicationModel.updateDefaultRoles(resourceRep.getDefaultRoles());
         }
 
+        if (resourceRep.getClaims() != null) {
+            ClaimManager.setClaims(applicationModel, resourceRep.getClaims());
+        } else {
+            applicationModel.setAllowedClaimsMask(ClaimMask.USERNAME);
+        }
+
         return applicationModel;
     }
 
@@ -162,6 +169,10 @@ public class ApplicationManager {
         if (webOrigins != null) {
             resource.getApplicationUser().setWebOrigins(new HashSet<String>(webOrigins));
         }
+
+        if (rep.getClaims() != null) {
+            ClaimManager.setClaims(resource, rep.getClaims());
+        }
     }
 
     public ApplicationRepresentation toRepresentation(ApplicationModel applicationModel) {
diff --git a/services/src/main/java/org/keycloak/services/managers/ClaimManager.java b/services/src/main/java/org/keycloak/services/managers/ClaimManager.java
new file mode 100755
index 0000000..02e7e76
--- /dev/null
+++ b/services/src/main/java/org/keycloak/services/managers/ClaimManager.java
@@ -0,0 +1,66 @@
+package org.keycloak.services.managers;
+
+import org.keycloak.models.ClaimMask;
+import org.keycloak.models.ClaimRequesterModel;
+import org.keycloak.representations.idm.ClaimRepresentation;
+
+/**
+ * @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
+ * @version $Revision: 1 $
+ */
+public class ClaimManager {
+    public static void setClaims(ClaimRequesterModel model, ClaimRepresentation rep) {
+        long mask = model.getAllowedClaimsMask();
+        if (rep.getAddress()) {
+            mask |= ClaimMask.ADDRESS;
+        } else {
+            mask &= ~ClaimMask.ADDRESS;
+        }
+        if (rep.getEmail()) {
+            mask |= ClaimMask.EMAIL;
+        } else {
+            mask &= ~ClaimMask.EMAIL;
+        }
+        if (rep.getGender()) {
+            mask |= ClaimMask.GENDER;
+        } else {
+            mask &= ~ClaimMask.GENDER;
+        }
+        if (rep.getLocale()) {
+            mask |= ClaimMask.LOCALE;
+        } else {
+            mask &= ~ClaimMask.LOCALE;
+        }
+        if (rep.getName()) {
+            mask |= ClaimMask.NAME;
+        } else {
+            mask &= ~ClaimMask.NAME;
+        }
+        if (rep.getPhone()) {
+            mask |= ClaimMask.PHONE;
+        } else {
+            mask &= ~ClaimMask.PHONE;
+        }
+        if (rep.getPicture()) {
+            mask |= ClaimMask.PICTURE;
+        } else {
+            mask &= ~ClaimMask.PICTURE;
+        }
+        if (rep.getProfile()) {
+            mask |= ClaimMask.PROFILE;
+        } else {
+            mask &= ~ClaimMask.PROFILE;
+        }
+        if (rep.getUsername()) {
+            mask |= ClaimMask.USERNAME;
+        } else {
+            mask &= ~ClaimMask.USERNAME;
+        }
+        if (rep.getWebsite()) {
+            mask |= ClaimMask.WEBSITE;
+        } else {
+            mask &= ~ClaimMask.WEBSITE;
+        }
+        model.setAllowedClaimsMask(mask);
+    }
+}
diff --git a/services/src/main/java/org/keycloak/services/managers/ModelToRepresentation.java b/services/src/main/java/org/keycloak/services/managers/ModelToRepresentation.java
index 303cd94..a40eb13 100755
--- a/services/src/main/java/org/keycloak/services/managers/ModelToRepresentation.java
+++ b/services/src/main/java/org/keycloak/services/managers/ModelToRepresentation.java
@@ -1,12 +1,15 @@
 package org.keycloak.services.managers;
 
 import org.keycloak.models.ApplicationModel;
+import org.keycloak.models.ClaimMask;
+import org.keycloak.models.ClaimRequesterModel;
 import org.keycloak.models.Constants;
 import org.keycloak.models.RealmModel;
 import org.keycloak.models.RequiredCredentialModel;
 import org.keycloak.models.RoleModel;
 import org.keycloak.models.UserCredentialModel;
 import org.keycloak.models.UserModel;
+import org.keycloak.representations.idm.ClaimRepresentation;
 import org.keycloak.representations.idm.CredentialRepresentation;
 import org.keycloak.representations.idm.RealmRepresentation;
 import org.keycloak.representations.idm.RoleRepresentation;
@@ -110,4 +113,19 @@ public class ModelToRepresentation {
         rep.setValue(cred.getValue());
         return rep;
     }
+
+    public static ClaimRepresentation toRepresentation(ClaimRequesterModel model) {
+        ClaimRepresentation rep = new ClaimRepresentation();
+        rep.setAddress(ClaimMask.hasAddress(model.getAllowedClaimsMask()));
+        rep.setEmail(ClaimMask.hasEmail(model.getAllowedClaimsMask()));
+        rep.setGender(ClaimMask.hasGender(model.getAllowedClaimsMask()));
+        rep.setLocale(ClaimMask.hasLocale(model.getAllowedClaimsMask()));
+        rep.setName(ClaimMask.hasName(model.getAllowedClaimsMask()));
+        rep.setPhone(ClaimMask.hasPhone(model.getAllowedClaimsMask()));
+        rep.setPicture(ClaimMask.hasPicture(model.getAllowedClaimsMask()));
+        rep.setProfile(ClaimMask.hasProfile(model.getAllowedClaimsMask()));
+        rep.setWebsite(ClaimMask.hasWebsite(model.getAllowedClaimsMask()));
+        rep.setUsername(ClaimMask.hasUsername(model.getAllowedClaimsMask()));
+        return rep;
+    }
 }
diff --git a/services/src/main/java/org/keycloak/services/managers/OAuthClientManager.java b/services/src/main/java/org/keycloak/services/managers/OAuthClientManager.java
index 5426755..300eab3 100755
--- a/services/src/main/java/org/keycloak/services/managers/OAuthClientManager.java
+++ b/services/src/main/java/org/keycloak/services/managers/OAuthClientManager.java
@@ -3,6 +3,7 @@ package org.keycloak.services.managers;
 import org.codehaus.jackson.annotate.JsonProperty;
 import org.codehaus.jackson.annotate.JsonPropertyOrder;
 import org.keycloak.models.ApplicationModel;
+import org.keycloak.models.ClaimMask;
 import org.keycloak.models.Constants;
 import org.keycloak.models.OAuthClientModel;
 import org.keycloak.models.RealmModel;
@@ -61,6 +62,12 @@ public class OAuthClientManager {
                 realm.updateCredential(resourceUser, credential);
             }
         }
+        if (rep.getClaims() != null) {
+            ClaimManager.setClaims(model, rep.getClaims());
+        } else {
+            model.setAllowedClaimsMask(ClaimMask.USERNAME);
+        }
+
         return model;
     }
 
@@ -75,6 +82,10 @@ public class OAuthClientManager {
         if (webOrigins != null) {
             model.getOAuthAgent().setWebOrigins(new HashSet<String>(webOrigins));
         }
+
+        if (rep.getClaims() != null) {
+            ClaimManager.setClaims(model, rep.getClaims());
+        }
     }
 
     public static OAuthClientRepresentation toRepresentation(OAuthClientModel model) {
diff --git a/services/src/main/java/org/keycloak/services/resources/admin/ApplicationResource.java b/services/src/main/java/org/keycloak/services/resources/admin/ApplicationResource.java
index 3fa6d1b..e6f677c 100755
--- a/services/src/main/java/org/keycloak/services/resources/admin/ApplicationResource.java
+++ b/services/src/main/java/org/keycloak/services/resources/admin/ApplicationResource.java
@@ -56,6 +56,11 @@ public class ApplicationResource extends RoleContainerResource {
         this.session = session;
     }
 
+    @Path("claims")
+    public ClaimResource getClaimResource() {
+        return new ClaimResource(application);
+    }
+
     @PUT
     @Consumes(MediaType.APPLICATION_JSON)
     public void update(final ApplicationRepresentation rep) {
diff --git a/services/src/main/java/org/keycloak/services/resources/admin/ClaimResource.java b/services/src/main/java/org/keycloak/services/resources/admin/ClaimResource.java
new file mode 100755
index 0000000..24760ac
--- /dev/null
+++ b/services/src/main/java/org/keycloak/services/resources/admin/ClaimResource.java
@@ -0,0 +1,36 @@
+package org.keycloak.services.resources.admin;
+
+import org.keycloak.models.ClaimRequesterModel;
+import org.keycloak.representations.idm.ClaimRepresentation;
+import org.keycloak.services.managers.ClaimManager;
+import org.keycloak.services.managers.ModelToRepresentation;
+
+import javax.ws.rs.Consumes;
+import javax.ws.rs.GET;
+import javax.ws.rs.PUT;
+import javax.ws.rs.Produces;
+import javax.ws.rs.core.MediaType;
+
+/**
+ * @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
+ * @version $Revision: 1 $
+ */
+public class ClaimResource {
+    protected ClaimRequesterModel model;
+
+    public ClaimResource(ClaimRequesterModel model) {
+        this.model = model;
+    }
+
+    @GET
+    @Produces(MediaType.APPLICATION_JSON)
+    public ClaimRepresentation getClaims() {
+        return ModelToRepresentation.toRepresentation(model);
+    }
+
+    @PUT
+    @Consumes(MediaType.APPLICATION_JSON)
+    public void updateClaims(ClaimRepresentation rep) {
+        ClaimManager.setClaims(model, rep);
+    }
+}
diff --git a/services/src/main/java/org/keycloak/services/resources/admin/OAuthClientResource.java b/services/src/main/java/org/keycloak/services/resources/admin/OAuthClientResource.java
index 9bdc837..ba1f0a1 100755
--- a/services/src/main/java/org/keycloak/services/resources/admin/OAuthClientResource.java
+++ b/services/src/main/java/org/keycloak/services/resources/admin/OAuthClientResource.java
@@ -56,6 +56,12 @@ public class OAuthClientResource  {
         this.session = session;
     }
 
+    @Path("claims")
+    public ClaimResource getClaimResource() {
+        return new ClaimResource(oauthClient);
+    }
+
+
     @PUT
     @Consumes(MediaType.APPLICATION_JSON)
     public void update(final OAuthClientRepresentation rep) {