keycloak-aplcache

cleanup and docs for mappers

3/11/2015 1:05:27 PM

Changes

Details

diff --git a/docbook/reference/en/en-US/master.xml b/docbook/reference/en/en-US/master.xml
index 6bbd301..31dcd82 100755
--- a/docbook/reference/en/en-US/master.xml
+++ b/docbook/reference/en/en-US/master.xml
@@ -40,6 +40,8 @@
                 <!ENTITY ApplicationClustering SYSTEM "modules/application-clustering.xml">
                 <!ENTITY MultiTenancy SYSTEM "modules/multi-tenancy.xml">
                 <!ENTITY Proxy SYSTEM "modules/proxy.xml">
+                <!ENTITY CustomAttributes SYSTEM "modules/custom-attributes.xml">
+                <!ENTITY ProtocolMappers SYSTEM "modules/protocol-mappers.xml">
                 ]>
 
 <book>
@@ -128,6 +130,8 @@ This one is short
     &Clustering;
     &ApplicationClustering;
     &Proxy;
+    &CustomAttributes;
+    &ProtocolMappers;
     &Migration;
 
 </book>
diff --git a/docbook/reference/en/en-US/modules/custom-attributes.xml b/docbook/reference/en/en-US/modules/custom-attributes.xml
new file mode 100755
index 0000000..338cdf2
--- /dev/null
+++ b/docbook/reference/en/en-US/modules/custom-attributes.xml
@@ -0,0 +1,150 @@
+<chapter id="custom-user-attributes">
+    <title>Custom User Attributes</title>
+    <para>If you have custom user data you want to store and manage in the admin console, registration page, and user account service, you can easily add
+    support for it by extending and modifying various Keycloak <link linkend="themes">themes</link>.</para>
+    <section>
+        <title>In admin console</title>
+    <para>To be able to enter custom attributes in the admin console, take the following steps</para>
+    <para>
+        <orderedlist>
+            <listitem>
+                Create a new theme within the <literal>themes/admin/mytheme</literal> directory in your distribution.
+                Where <literal>mytheme</literal> is whatever you want to name your theme.
+            </listitem>
+            <listitem>
+                Create a <literal>theme.properties</literal> file in this directory that extends the main admin console
+                theme.
+                <programlisting><![CDATA[parent=keycloak
+import=common/keycloak
+]]></programlisting>
+            </listitem>
+            <listitem>
+                Copy the file <literal>themes/admin/base/resources/partials/user-attribute-entry.html</literal> into the
+                a mirror directory in your theme: <literal>themes/admin/mytheme/resources/partials/user-attribute-entry.html</literal>.
+                What you are doing here is overriding the user attribute entry page in the admin console and putting in
+                what attributes you want.  This file already contains an example of entering address data.  You can remove
+                this if you want and replace it with something else.  Also, if you want to edit this file directly instead
+                of creating a new theme, you can.
+            </listitem>
+            <listitem>
+                In the <literal>user-attribute-entry.html</literal> file add your custom user attribute entry form item.  For example
+<programlisting><![CDATA[    <div class="form-group clearfix block">
+        <label class="col-sm-2 control-label" for="mobile">Mobile</label>
+        <div class="col-sm-6">
+            <input ng-model="user.attributes.mobile" class="form-control" type="text" name="mobile" id="mobile" />
+        </div>
+        <span tooltip-placement="right" tooltip="Mobile number." class="fa fa-info-circle"></span>
+    </div>
+]]></programlisting>
+                The <literal>ng-model</literal> names the user attribute you will store in the database and must have the
+                form of <literal>user.attributes.ATTR_NAME</literal>.
+            </listitem>
+            <listitem>
+                Change the theme for the admin console.  Save it, then refresh your browser, and you should
+                now see these fields in the User detail page for any user.
+            </listitem>
+        </orderedlist>
+    </para>
+    </section>
+    <section>
+        <title>In registration page</title>
+    <para>To be able to enter custom attributes in the registration page, take the following steps</para>
+    <para>
+        <orderedlist>
+            <listitem>
+                Create a new theme within the <literal>themes/login/mytheme</literal> directory in your distribution.
+                Where <literal>mytheme</literal> is whatever you want to name your theme.
+            </listitem>
+            <listitem>
+                Create a <literal>theme.properties</literal> file in this directory that extends the main admin console
+                theme.
+                <programlisting><![CDATA[parent=keycloak
+import=common/keycloak
+styles= ../patternfly/lib/patternfly/css/patternfly.css ../patternfly/css/login.css ../patternfly/lib/zocial/zocial.css css/login.css]]></programlisting>
+            </listitem>
+            <listitem>
+                Copy the file <literal>themes/login/base/register.ftl</literal> into the
+                a mirror directory in your theme: <literal>themes/login/mytheme/register.ftl</literal>.
+                What you are doing here is overriding the registration page and adding
+                what attributes you want.  This file already contains an example of entering address data.  You can remove
+                this if you want and replace it with something else.  Also, if you want to edit this file directly instead
+                of creating a new theme, you can.
+            </listitem>
+            <listitem>
+                In the <literal>register.ftl</literal> file add your custom user attribute entry form item.  For example
+<programlisting><![CDATA[
+<div class="form-group">
+   <div class="${properties.kcLabelWrapperClass!}">
+       <label for="user.attributes.mobile" class="${properties.kcLabelClass!}">Mobile number</label>
+   </div>
+
+   <div class="col-sm-10 col-md-10">
+       <input type="text" class="${properties.kcInputClass!}"  id="user.attributes.mobile" name="user.attributes.mobile"/>
+   </div>
+</div>
+]]></programlisting>
+                Make sure the input field id ane name match the user attribute you want to store in the database.
+                This must have the
+                form of <literal>user.attributes.ATTR_NAME</literal>.  You might also want to replace the label text
+                with a message property.  This will help later if you want to internationalize your pages.
+            </listitem>
+            <listitem>
+                Change the theme for the login to your new theme.  Save it, then refresh your browser, and you should
+                now see these fields in the registration.
+            </listitem>
+        </orderedlist>
+    </para>
+    </section>
+    <section>
+        <title>In user account profile page</title>
+    <para>To be able to manage custom attributes in the user account profile page, take the following steps</para>
+    <para>
+        <orderedlist>
+            <listitem>
+                Create a new theme within the <literal>themes/account/mytheme</literal> directory in your distribution.
+                Where <literal>mytheme</literal> is whatever you want to name your theme.
+            </listitem>
+            <listitem>
+                Create a <literal>theme.properties</literal> file in this directory that extends the main admin console
+                theme.
+                <programlisting><![CDATA[parent=patternfly
+import=common/keycloak
+
+styles= ../patternfly/lib/patternfly/css/patternfly.css ../patternfly/css/account.css css/account.css]]></programlisting>
+            </listitem>
+            <listitem>
+                Copy the file <literal>themes/account/base/account.ftl</literal> into the
+                a mirror directory in your theme: <literal>themes/account/mytheme/account.ftl</literal>.
+                What you are doing here is overriding the profile page and adding
+                what attributes you want to manage.  This file already contains an example of entering address data.  You can remove
+                this if you want and replace it with something else.  Also, if you want to edit this file directly instead
+                of creating a new theme, you can.
+            </listitem>
+            <listitem>
+                In the <literal>account.ftl</literal> file add your custom user attribute entry form item.  For example
+<programlisting><![CDATA[
+<div class="form-group">
+   <div class="col-sm-2 col-md-2">
+       <label for="user.attributes.mobile" class="control-label">Mobile number</label>
+   </div>
+
+   <div class="col-sm-10 col-md-10">
+       <input type="text" class="form-control" id="user.attributes.mobile" name="user.attributes.mobile" value="${(account.attributes.mobile!'')?html}"/>
+   </div>
+</div>]]></programlisting>
+                Make sure the input field id ane name match the user attribute you want to store in the database.
+                This must have the
+                form of <literal>user.attributes.ATTR_NAME</literal>.  You might also want to replace the label text
+                with a message property.  This will help later if you want to internationalize your pages.
+            </listitem>
+            <listitem>
+                Change the theme for the account to your new theme.  Save it, then refresh your browser, and you should
+                now see these fields in the account profile page.
+            </listitem>
+        </orderedlist>
+    </para>
+    </section>
+
+
+
+</chapter>
\ No newline at end of file
diff --git a/docbook/reference/en/en-US/modules/Overview.xml b/docbook/reference/en/en-US/modules/Overview.xml
index 53fcd8f..8a545d4 100755
--- a/docbook/reference/en/en-US/modules/Overview.xml
+++ b/docbook/reference/en/en-US/modules/Overview.xml
@@ -95,6 +95,14 @@
                 and even within the same deployed application.
             </listitem>
             <listitem>
+                Identity brokering/chaining.  You can make the Keycloak server a child IDP to another SAML 2.0 or OpenID Connect IDP.
+            </listitem>
+            <listitem>
+                Token claim, assertion, and attribute mappings.  You can map user attributes, roles, and role names however you want
+                into a OIDC ID Token, Access Token, SAML attribute statements, etc.  This feature allows you to basically
+                tailor however you want auth responses to look.
+            </listitem>
+            <listitem>
                 Supports JBoss AS7, EAP 6.x, Wildfly, Tomcat 7, Tomcat 8, Jetty 9.1.x, Jetty 9.2.x, Jetty 8.1.x, and Pure JavaScript applications.  Plans to support Node.js, RAILS, GRAILS, and other non-Java deployments
             </listitem>
         </itemizedlist>
diff --git a/docbook/reference/en/en-US/modules/protocol-mappers.xml b/docbook/reference/en/en-US/modules/protocol-mappers.xml
new file mode 100755
index 0000000..0c85d62
--- /dev/null
+++ b/docbook/reference/en/en-US/modules/protocol-mappers.xml
@@ -0,0 +1,17 @@
+<chapter id="mappers">
+    <title>OIDC Token and SAML Assertion Mappings</title>
+    <para>
+        Applications that receive ID Tokens, Access Tokens, or SAML assertions may need or want different user metadata
+        and roles.  Keycloak allows you to define what exactly is transferred.  You can hardcode roles, claims and custom
+        attributes.  You can pull user metadata into a token or assertion.  You can rename roles.  Basicall you have
+        a lot of control of what exactly goes back to the client.
+    </para>
+    <para>
+        Within the admin console, if you go to an application you've registered, you'll see a "Mappers" sub-menu item.
+        This is the place where you can control how a OIDC ID Token, Access Token, and SAML login response assertions look
+        like.  When you click on this you'll see some default mappers that have been set up for you.  Clicking the
+        "Add Builtin" button gives you the option to add other preconfigured mappers.  Clicking on "Create" allows
+        you to define your own protocol mappers.  The tooltips are very helpful to learn exactly what you can do
+        to tailor your tokens and assertions.  They should be enough to guide you through the process.
+    </para>
+</chapter>
\ No newline at end of file
diff --git a/forms/common-themes/src/main/resources/theme/admin/base/resources/partials/application-detail.html b/forms/common-themes/src/main/resources/theme/admin/base/resources/partials/application-detail.html
index 35e1202..c3b1f9d 100755
--- a/forms/common-themes/src/main/resources/theme/admin/base/resources/partials/application-detail.html
+++ b/forms/common-themes/src/main/resources/theme/admin/base/resources/partials/application-detail.html
@@ -65,13 +65,6 @@
                     <span tooltip-placement="right" tooltip="Should a statement specifying the method and timestamp be included in login responses?" class="fa fa-info-circle"></span>
                 </div>
                 <div class="form-group clearfix block" data-ng-show="protocol == 'saml'">
-                    <label class="col-sm-2 control-label" for="samlMultiValuedRoles">Multi-valued Roles</label>
-                    <div class="col-sm-6">
-                        <input ng-model="samlMultiValuedRoles" ng-click="switchChange()" name="samlMultiValuedRoles" id="samlMultiValuedRoles" onoffswitch />
-                    </div>
-                    <span tooltip-placement="right" tooltip="'On' means that there will be one role attribute with multiple values for each role in SAML response.  'Off' means that there will be an attribute defined for each role." class="fa fa-info-circle"></span>
-                </div>
-                <div class="form-group clearfix block" data-ng-show="protocol == 'saml'">
                     <label class="col-sm-2 control-label" for="samlServerSignature">Sign Documents</label>
                     <div class="col-sm-6">
                         <input ng-model="samlServerSignature" ng-click="switchChange()" name="samlServerSignature" id="samlServerSignature" onoffswitch />
diff --git a/forms/login-api/src/main/java/org/keycloak/login/LoginFormsProvider.java b/forms/login-api/src/main/java/org/keycloak/login/LoginFormsProvider.java
index f9a9c48..11c26fe 100755
--- a/forms/login-api/src/main/java/org/keycloak/login/LoginFormsProvider.java
+++ b/forms/login-api/src/main/java/org/keycloak/login/LoginFormsProvider.java
@@ -1,6 +1,7 @@
 package org.keycloak.login;
 
 import org.keycloak.models.ClientModel;
+import org.keycloak.models.ClientSessionModel;
 import org.keycloak.models.RealmModel;
 import org.keycloak.models.RoleModel;
 import org.keycloak.models.UserModel;
@@ -35,7 +36,7 @@ public interface LoginFormsProvider extends Provider {
 
     public Response createErrorPage();
 
-    public Response createOAuthGrant();
+    public Response createOAuthGrant(ClientSessionModel clientSessionModel);
 
     public Response createCode();
 
diff --git a/forms/login-freemarker/src/main/java/org/keycloak/login/freemarker/FreeMarkerLoginFormsProvider.java b/forms/login-freemarker/src/main/java/org/keycloak/login/freemarker/FreeMarkerLoginFormsProvider.java
index f8b85c6..be59af0 100755
--- a/forms/login-freemarker/src/main/java/org/keycloak/login/freemarker/FreeMarkerLoginFormsProvider.java
+++ b/forms/login-freemarker/src/main/java/org/keycloak/login/freemarker/FreeMarkerLoginFormsProvider.java
@@ -24,6 +24,7 @@ import org.keycloak.login.freemarker.model.IdentityProviderBean;
 import org.keycloak.login.freemarker.model.TotpBean;
 import org.keycloak.login.freemarker.model.UrlBean;
 import org.keycloak.models.ClientModel;
+import org.keycloak.models.ClientSessionModel;
 import org.keycloak.models.KeycloakSession;
 import org.keycloak.models.RealmModel;
 import org.keycloak.models.RoleModel;
@@ -75,6 +76,7 @@ public class FreeMarkerLoginFormsProvider implements LoginFormsProvider {
     private UserModel user;
 
     private ClientModel client;
+    private ClientSessionModel clientSession;
 
     private UriInfo uriInfo;
 
@@ -213,7 +215,7 @@ public class FreeMarkerLoginFormsProvider implements LoginFormsProvider {
                 attributes.put("register", new RegisterBean(formData));
                 break;
             case OAUTH_GRANT:
-                attributes.put("oauth", new OAuthGrantBean(accessCode, client, realmRolesRequested, resourceRolesRequested, this.accessRequestMessage));
+                attributes.put("oauth", new OAuthGrantBean(accessCode, clientSession, client, realmRolesRequested, resourceRolesRequested, this.accessRequestMessage));
                 break;
             case CODE:
                 attributes.put(OAuth2Constants.CODE, new CodeBean(accessCode, messageType == MessageType.ERROR ? message : null));
@@ -265,7 +267,8 @@ public class FreeMarkerLoginFormsProvider implements LoginFormsProvider {
         return createResponse(LoginFormsPages.ERROR);
     }
 
-    public Response createOAuthGrant() {
+    public Response createOAuthGrant(ClientSessionModel clientSession) {
+        this.clientSession = clientSession;
         return createResponse(LoginFormsPages.OAUTH_GRANT);
     }
 
diff --git a/forms/login-freemarker/src/main/java/org/keycloak/login/freemarker/model/OAuthGrantBean.java b/forms/login-freemarker/src/main/java/org/keycloak/login/freemarker/model/OAuthGrantBean.java
index 6d515a1..431a606 100755
--- a/forms/login-freemarker/src/main/java/org/keycloak/login/freemarker/model/OAuthGrantBean.java
+++ b/forms/login-freemarker/src/main/java/org/keycloak/login/freemarker/model/OAuthGrantBean.java
@@ -21,8 +21,9 @@
  */
 package org.keycloak.login.freemarker.model;
 
-import org.keycloak.models.ClaimMask;
 import org.keycloak.models.ClientModel;
+import org.keycloak.models.ClientSessionModel;
+import org.keycloak.models.ProtocolMapperModel;
 import org.keycloak.models.RoleModel;
 
 import javax.ws.rs.core.MultivaluedMap;
@@ -41,7 +42,7 @@ public class OAuthGrantBean {
     private ClientModel client;
     private List<String> claimsRequested;
 
-    public OAuthGrantBean(String code, ClientModel client, List<RoleModel> realmRolesRequested, MultivaluedMap<String, RoleModel> resourceRolesRequested, String accessRequestMessage) {
+    public OAuthGrantBean(String code, ClientSessionModel clientSession, ClientModel client, List<RoleModel> realmRolesRequested, MultivaluedMap<String, RoleModel> resourceRolesRequested, String accessRequestMessage) {
         this.code = code;
         this.client = client;
         this.realmRolesRequested = realmRolesRequested;
@@ -50,36 +51,12 @@ public class OAuthGrantBean {
 
         // todo support locale
         List<String> claims = new LinkedList<String>();
-        long mask = client.getAllowedClaimsMask();
-        if (ClaimMask.hasEmail(mask)) {
-            claims.add("email");
-        }
-        if (ClaimMask.hasUsername(mask)) {
-            claims.add("username");
-        }
-        if (ClaimMask.hasName(mask)) {
-            claims.add("name");
-        }
-        if (ClaimMask.hasGender(mask)) {
-            claims.add("gender");
-        }
-        if (ClaimMask.hasAddress(mask)) {
-            claims.add("address");
-        }
-        if (ClaimMask.hasPhone(mask)) {
-            claims.add("phone");
-        }
-        if (ClaimMask.hasPicture(mask)) {
-            claims.add("picture");
-        }
-        if (ClaimMask.hasProfile(mask)) {
-            claims.add("profile page");
-        }
-        if (ClaimMask.hasLocale(mask)) {
-            claims.add("locale");
-        }
-        if (ClaimMask.hasWebsite(mask)) {
-            claims.add("website");
+        if (clientSession != null) {
+            for (ProtocolMapperModel model : client.getProtocolMappers()) {
+                if (model.isConsentRequired() && model.getProtocol().equals(clientSession.getAuthMethod()) && model.getConsentText() != null) {
+                    claims.add(model.getConsentText());
+                }
+            }
         }
         if (claims.size() > 0) this.claimsRequested = claims;
     }
diff --git a/saml/saml-protocol/src/main/java/org/keycloak/protocol/saml/mappers/HardcodedAttributeMapper.java b/saml/saml-protocol/src/main/java/org/keycloak/protocol/saml/mappers/HardcodedAttributeMapper.java
index 221bcfd..455375e 100755
--- a/saml/saml-protocol/src/main/java/org/keycloak/protocol/saml/mappers/HardcodedAttributeMapper.java
+++ b/saml/saml-protocol/src/main/java/org/keycloak/protocol/saml/mappers/HardcodedAttributeMapper.java
@@ -24,11 +24,6 @@ public class HardcodedAttributeMapper extends AbstractSAMLProtocolMapper impleme
 
     static {
         ConfigProperty property;
-        property = new ConfigProperty();
-        property.setName(ProtocolMapperUtils.USER_ATTRIBUTE);
-        property.setLabel(ProtocolMapperUtils.USER_MODEL_ATTRIBUTE_LABEL);
-        property.setHelpText(ProtocolMapperUtils.USER_MODEL_ATTRIBUTE_HELP_TEXT);
-        configProperties.add(property);
         AttributeStatementHelper.setConfigProperties(configProperties);
         property = new ConfigProperty();
         property.setName(ATTRIBUTE_VALUE);
diff --git a/services/src/main/java/org/keycloak/protocol/oidc/mappers/HardcodedClaim.java b/services/src/main/java/org/keycloak/protocol/oidc/mappers/HardcodedClaim.java
index b54c919..ecea9e8 100755
--- a/services/src/main/java/org/keycloak/protocol/oidc/mappers/HardcodedClaim.java
+++ b/services/src/main/java/org/keycloak/protocol/oidc/mappers/HardcodedClaim.java
@@ -5,6 +5,7 @@ import org.keycloak.models.KeycloakSession;
 import org.keycloak.models.ProtocolMapperModel;
 import org.keycloak.models.UserModel;
 import org.keycloak.models.UserSessionModel;
+import org.keycloak.protocol.ProtocolMapper;
 import org.keycloak.protocol.ProtocolMapperUtils;
 import org.keycloak.protocol.oidc.OIDCLoginProtocol;
 import org.keycloak.representations.AccessToken;
@@ -44,8 +45,13 @@ public class HardcodedClaim extends AbstractOIDCProtocolMapper implements OIDCAc
         property = new ConfigProperty();
         property.setName(OIDCAttributeMapperHelper.JSON_TYPE);
         property.setLabel(OIDCAttributeMapperHelper.JSON_TYPE);
-        property.setType(ConfigProperty.STRING_TYPE);
-        property.setDefaultValue(ConfigProperty.STRING_TYPE);
+        List<String> types = new ArrayList(3);
+        types.add("String");
+        types.add("long");
+        types.add("int");
+        types.add("boolean");
+        property.setType(ProtocolMapper.ConfigProperty.LIST_TYPE);
+        property.setDefaultValue(types);
         property.setHelpText("JSON type that should be used for the value of the claim.  long, int, boolean, and String are valid values.");
         configProperties.add(property);
         property = new ConfigProperty();
diff --git a/services/src/main/java/org/keycloak/protocol/oidc/mappers/HardcodedRole.java b/services/src/main/java/org/keycloak/protocol/oidc/mappers/HardcodedRole.java
index 26075e4..088389f 100755
--- a/services/src/main/java/org/keycloak/protocol/oidc/mappers/HardcodedRole.java
+++ b/services/src/main/java/org/keycloak/protocol/oidc/mappers/HardcodedRole.java
@@ -49,7 +49,7 @@ public class HardcodedRole extends AbstractOIDCProtocolMapper implements OIDCAcc
 
     @Override
     public String getDisplayType() {
-        return "Add Role";
+        return "Hardcoded Role";
     }
 
     @Override
@@ -59,7 +59,7 @@ public class HardcodedRole extends AbstractOIDCProtocolMapper implements OIDCAcc
 
     @Override
     public String getHelpText() {
-        return "Hardcode any role specify into the token.";
+        return "Hardcode a role into the access token.";
     }
 
     @Override
diff --git a/services/src/main/java/org/keycloak/protocol/oidc/mappers/OIDCAttributeMapperHelper.java b/services/src/main/java/org/keycloak/protocol/oidc/mappers/OIDCAttributeMapperHelper.java
index b91c233..7635a4b 100755
--- a/services/src/main/java/org/keycloak/protocol/oidc/mappers/OIDCAttributeMapperHelper.java
+++ b/services/src/main/java/org/keycloak/protocol/oidc/mappers/OIDCAttributeMapperHelper.java
@@ -2,12 +2,15 @@ package org.keycloak.protocol.oidc.mappers;
 
 import org.keycloak.models.ProtocolMapperModel;
 import org.keycloak.models.RealmModel;
+import org.keycloak.protocol.ProtocolMapper;
 import org.keycloak.protocol.ProtocolMapperUtils;
 import org.keycloak.protocol.oidc.OIDCLoginProtocol;
 import org.keycloak.representations.AccessToken;
 import org.keycloak.representations.IDToken;
 
+import java.util.ArrayList;
 import java.util.HashMap;
+import java.util.List;
 import java.util.Map;
 
 /**
@@ -97,4 +100,40 @@ public class OIDCAttributeMapperHelper {
     public static boolean includeInAccessToken(ProtocolMapperModel mappingModel) {
         return "true".equals(mappingModel.getConfig().get(INCLUDE_IN_ACCESS_TOKEN));
     }
+
+    public static void addAttributeConfig(List<ProtocolMapper.ConfigProperty> configProperties) {
+        ProtocolMapper.ConfigProperty property;
+        property = new ProtocolMapper.ConfigProperty();
+        property.setName(TOKEN_CLAIM_NAME);
+        property.setLabel(TOKEN_CLAIM_NAME_LABEL);
+        property.setType(ProtocolMapper.ConfigProperty.STRING_TYPE);
+        property.setHelpText("Name of the claim to insert into the token.  This can be a fully qualified name like 'address.street'.  In this case, a nested json object will be created.");
+        configProperties.add(property);
+        property = new ProtocolMapper.ConfigProperty();
+        property.setName(JSON_TYPE);
+        property.setLabel(JSON_TYPE);
+        List<String> types = new ArrayList(3);
+        types.add("String");
+        types.add("long");
+        types.add("int");
+        types.add("boolean");
+        property.setType(ProtocolMapper.ConfigProperty.LIST_TYPE);
+        property.setDefaultValue(types);
+        property.setHelpText("JSON type that should be used to populate the json claim in the token.  long, int, boolean, and String are valid values.");
+        configProperties.add(property);
+        property = new ProtocolMapper.ConfigProperty();
+        property.setName(INCLUDE_IN_ID_TOKEN);
+        property.setLabel(INCLUDE_IN_ID_TOKEN_LABEL);
+        property.setType(ProtocolMapper.ConfigProperty.BOOLEAN_TYPE);
+        property.setDefaultValue("true");
+        property.setHelpText(INCLUDE_IN_ID_TOKEN_HELP_TEXT);
+        configProperties.add(property);
+        property = new ProtocolMapper.ConfigProperty();
+        property.setName(INCLUDE_IN_ACCESS_TOKEN);
+        property.setLabel(INCLUDE_IN_ACCESS_TOKEN_LABEL);
+        property.setType(ProtocolMapper.ConfigProperty.BOOLEAN_TYPE);
+        property.setDefaultValue("true");
+        property.setHelpText(INCLUDE_IN_ACCESS_TOKEN_HELP_TEXT);
+        configProperties.add(property);
+    }
 }
diff --git a/services/src/main/java/org/keycloak/protocol/oidc/mappers/RoleNameMapper.java b/services/src/main/java/org/keycloak/protocol/oidc/mappers/RoleNameMapper.java
index eaee955..1e5784c 100755
--- a/services/src/main/java/org/keycloak/protocol/oidc/mappers/RoleNameMapper.java
+++ b/services/src/main/java/org/keycloak/protocol/oidc/mappers/RoleNameMapper.java
@@ -58,7 +58,7 @@ public class RoleNameMapper extends AbstractOIDCProtocolMapper implements OIDCAc
 
     @Override
     public String getDisplayType() {
-        return "Role Mapper";
+        return "Role Name Mapper";
     }
 
     @Override
diff --git a/services/src/main/java/org/keycloak/protocol/oidc/mappers/UserAttributeMapper.java b/services/src/main/java/org/keycloak/protocol/oidc/mappers/UserAttributeMapper.java
index 906eef4..b38283c 100755
--- a/services/src/main/java/org/keycloak/protocol/oidc/mappers/UserAttributeMapper.java
+++ b/services/src/main/java/org/keycloak/protocol/oidc/mappers/UserAttributeMapper.java
@@ -33,33 +33,7 @@ public class UserAttributeMapper extends AbstractOIDCProtocolMapper implements O
         property.setHelpText(ProtocolMapperUtils.USER_MODEL_ATTRIBUTE_HELP_TEXT);
         property.setType(ConfigProperty.STRING_TYPE);
         configProperties.add(property);
-        property = new ConfigProperty();
-        property.setName(OIDCAttributeMapperHelper.TOKEN_CLAIM_NAME);
-        property.setLabel(OIDCAttributeMapperHelper.TOKEN_CLAIM_NAME_LABEL);
-        property.setType(ConfigProperty.STRING_TYPE);
-        property.setHelpText("Name of the claim to insert into the token.  This can be a fully qualified name like 'address.street'.  In this case, a nested json object will be created.");
-        configProperties.add(property);
-        property = new ConfigProperty();
-        property.setName(OIDCAttributeMapperHelper.JSON_TYPE);
-        property.setLabel(OIDCAttributeMapperHelper.JSON_TYPE);
-        property.setType(ConfigProperty.STRING_TYPE);
-        property.setDefaultValue(ConfigProperty.STRING_TYPE);
-        property.setHelpText("JSON type that should be used to populate the json claim in the token.  long, int, boolean, and String are valid values.");
-        configProperties.add(property);
-        property = new ConfigProperty();
-        property.setName(OIDCAttributeMapperHelper.INCLUDE_IN_ID_TOKEN);
-        property.setLabel(OIDCAttributeMapperHelper.INCLUDE_IN_ID_TOKEN_LABEL);
-        property.setType(ConfigProperty.BOOLEAN_TYPE);
-        property.setDefaultValue("true");
-        property.setHelpText(OIDCAttributeMapperHelper.INCLUDE_IN_ID_TOKEN_HELP_TEXT);
-        configProperties.add(property);
-        property = new ConfigProperty();
-        property.setName(OIDCAttributeMapperHelper.INCLUDE_IN_ACCESS_TOKEN);
-        property.setLabel(OIDCAttributeMapperHelper.INCLUDE_IN_ACCESS_TOKEN_LABEL);
-        property.setType(ConfigProperty.BOOLEAN_TYPE);
-        property.setDefaultValue("true");
-        property.setHelpText(OIDCAttributeMapperHelper.INCLUDE_IN_ACCESS_TOKEN_HELP_TEXT);
-        configProperties.add(property);
+        OIDCAttributeMapperHelper.addAttributeConfig(configProperties);
 
     }
 
diff --git a/services/src/main/java/org/keycloak/protocol/oidc/mappers/UserPropertyMapper.java b/services/src/main/java/org/keycloak/protocol/oidc/mappers/UserPropertyMapper.java
index a47f824..15573ac 100755
--- a/services/src/main/java/org/keycloak/protocol/oidc/mappers/UserPropertyMapper.java
+++ b/services/src/main/java/org/keycloak/protocol/oidc/mappers/UserPropertyMapper.java
@@ -3,7 +3,6 @@ package org.keycloak.protocol.oidc.mappers;
 import org.keycloak.models.ClientSessionModel;
 import org.keycloak.models.KeycloakSession;
 import org.keycloak.models.ProtocolMapperModel;
-import org.keycloak.models.RealmModel;
 import org.keycloak.models.UserModel;
 import org.keycloak.models.UserSessionModel;
 import org.keycloak.protocol.ProtocolMapperUtils;
@@ -32,33 +31,7 @@ public class UserPropertyMapper extends AbstractOIDCProtocolMapper implements OI
         property.setType(ConfigProperty.STRING_TYPE);
         property.setHelpText(ProtocolMapperUtils.USER_MODEL_PROPERTY_HELP_TEXT);
         configProperties.add(property);
-        property = new ConfigProperty();
-        property.setName(OIDCAttributeMapperHelper.TOKEN_CLAIM_NAME);
-        property.setLabel(OIDCAttributeMapperHelper.TOKEN_CLAIM_NAME_LABEL);
-        property.setType(ConfigProperty.STRING_TYPE);
-        property.setHelpText("Name of the claim to insert into the token.  This can be a fully qualified name like 'address.street'.  In this case, a nested json object will be created.");
-        configProperties.add(property);
-        property = new ConfigProperty();
-        property.setName(OIDCAttributeMapperHelper.JSON_TYPE);
-        property.setLabel(OIDCAttributeMapperHelper.JSON_TYPE);
-        property.setType(ConfigProperty.STRING_TYPE);
-        property.setDefaultValue(ConfigProperty.STRING_TYPE);
-        property.setHelpText("JSON type that should be used to populate the json claim in the token.  long, int, boolean, and String are valid values.");
-        configProperties.add(property);
-        property = new ConfigProperty();
-        property.setName(OIDCAttributeMapperHelper.INCLUDE_IN_ID_TOKEN);
-        property.setLabel(OIDCAttributeMapperHelper.INCLUDE_IN_ID_TOKEN_LABEL);
-        property.setType(ConfigProperty.BOOLEAN_TYPE);
-        property.setDefaultValue("true");
-        property.setHelpText(OIDCAttributeMapperHelper.INCLUDE_IN_ID_TOKEN_HELP_TEXT);
-        configProperties.add(property);
-        property = new ConfigProperty();
-        property.setName(OIDCAttributeMapperHelper.INCLUDE_IN_ACCESS_TOKEN);
-        property.setLabel(OIDCAttributeMapperHelper.INCLUDE_IN_ACCESS_TOKEN_LABEL);
-        property.setType(ConfigProperty.BOOLEAN_TYPE);
-        property.setDefaultValue("true");
-        property.setHelpText(OIDCAttributeMapperHelper.INCLUDE_IN_ACCESS_TOKEN_HELP_TEXT);
-        configProperties.add(property);
+        OIDCAttributeMapperHelper.addAttributeConfig(configProperties);
     }
 
     public static final String PROVIDER_ID = "oidc-usermodel-property-mapper";
diff --git a/services/src/main/java/org/keycloak/protocol/oidc/mappers/UserSessionNoteMapper.java b/services/src/main/java/org/keycloak/protocol/oidc/mappers/UserSessionNoteMapper.java
index 4e83120..45b22bf 100755
--- a/services/src/main/java/org/keycloak/protocol/oidc/mappers/UserSessionNoteMapper.java
+++ b/services/src/main/java/org/keycloak/protocol/oidc/mappers/UserSessionNoteMapper.java
@@ -33,7 +33,7 @@ public class UserSessionNoteMapper extends AbstractOIDCProtocolMapper implements
         configProperties.add(property);
         property = new ConfigProperty();
         property.setName(OIDCAttributeMapperHelper.TOKEN_CLAIM_NAME);
-        property.setLabel(OIDCAttributeMapperHelper.TOKEN_CLAIM_NAME);
+        property.setLabel(OIDCAttributeMapperHelper.TOKEN_CLAIM_NAME_LABEL);
         property.setType(ConfigProperty.STRING_TYPE);
         property.setHelpText("Name of the claim to insert into the token.  This can be a fully qualified name like 'address.street'.  In this case, a nested json object will be created.");
         configProperties.add(property);
diff --git a/services/src/main/java/org/keycloak/services/managers/AuthenticationManager.java b/services/src/main/java/org/keycloak/services/managers/AuthenticationManager.java
index 25fce1f..aa27f17 100755
--- a/services/src/main/java/org/keycloak/services/managers/AuthenticationManager.java
+++ b/services/src/main/java/org/keycloak/services/managers/AuthenticationManager.java
@@ -391,7 +391,7 @@ public class AuthenticationManager {
                     .setClientSessionCode(accessCode.getCode())
                     .setAccessRequest(realmRoles, resourceRoles)
                     .setClient(client)
-                    .createOAuthGrant();
+                    .createOAuthGrant(clientSession);
         }
 
         event.success();
diff --git a/services/src/main/java/org/keycloak/services/resources/IdentityBrokerService.java b/services/src/main/java/org/keycloak/services/resources/IdentityBrokerService.java
old mode 100644
new mode 100755
index 7fb4209..d26f695
--- a/services/src/main/java/org/keycloak/services/resources/IdentityBrokerService.java
+++ b/services/src/main/java/org/keycloak/services/resources/IdentityBrokerService.java
@@ -197,7 +197,7 @@ public class IdentityBrokerService {
                             .setClient(clientModel)
                             .setUriInfo(this.uriInfo)
                             .setActionUri(this.uriInfo.getRequestUri())
-                            .createOAuthGrant(), clientModel);
+                            .createOAuthGrant(null), clientModel);
                 }
 
                 IdentityProvider identityProvider = getIdentityProvider(providerId);