From 451ce64907438c8d963c4573efa8f613bb712110 Mon Sep 17 00:00:00 2001 From: Bill Burke Date: Wed, 11 Mar 2015 09:59:56 -0400 Subject: [PATCH 1/2] role name mapper --- .../protocol/ProtocolMapperUtils.java | 15 ++++++++ .../protocol/oidc/mappers/HardcodedRole.java | 12 +++---- .../protocol/oidc/mappers/RoleNameMapper.java | 36 +++++++++++-------- .../testsuite/oauth/AccessTokenTest.java | 4 +++ 4 files changed, 46 insertions(+), 21 deletions(-) diff --git a/services/src/main/java/org/keycloak/protocol/ProtocolMapperUtils.java b/services/src/main/java/org/keycloak/protocol/ProtocolMapperUtils.java index 727d74df21..b91b7542a0 100755 --- a/services/src/main/java/org/keycloak/protocol/ProtocolMapperUtils.java +++ b/services/src/main/java/org/keycloak/protocol/ProtocolMapperUtils.java @@ -3,6 +3,7 @@ package org.keycloak.protocol; import org.keycloak.models.KeycloakSessionFactory; import org.keycloak.models.ProtocolMapperModel; import org.keycloak.models.UserModel; +import org.keycloak.representations.AccessToken; import java.lang.reflect.Method; import java.util.List; @@ -41,4 +42,18 @@ public class ProtocolMapperUtils { } return null; } + + public static String[] parseRole(String role) { + int scopeIndex = role.indexOf('.'); + if (scopeIndex > -1) { + String appName = role.substring(0, scopeIndex); + role = role.substring(scopeIndex + 1); + String[] rtn = {appName, role}; + return rtn; + } else { + String[] rtn = {null, role}; + return rtn; + + } + } } 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 ec0f720c03..26075e46bb 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 @@ -4,6 +4,7 @@ import org.keycloak.models.ClientSessionModel; import org.keycloak.models.KeycloakSession; import org.keycloak.models.ProtocolMapperModel; import org.keycloak.models.UserSessionModel; +import org.keycloak.protocol.ProtocolMapperUtils; import org.keycloak.protocol.oidc.OIDCLoginProtocol; import org.keycloak.representations.AccessToken; @@ -65,12 +66,11 @@ public class HardcodedRole extends AbstractOIDCProtocolMapper implements OIDCAcc public AccessToken transformAccessToken(AccessToken token, ProtocolMapperModel mappingModel, KeycloakSession session, UserSessionModel userSession, ClientSessionModel clientSession) { String role = mappingModel.getConfig().get(ROLE_CONFIG); - String appName = null; - int scopeIndex = role.indexOf('.'); - if (scopeIndex > -1) { - appName = role.substring(0, scopeIndex); - role = role.substring(scopeIndex + 1); - token.addAccess(appName).addRole(role); + String[] scopedRole = ProtocolMapperUtils.parseRole(role); + String appName = scopedRole[0]; + String roleName = scopedRole[1]; + if (appName != null) { + token.addAccess(appName).addRole(roleName); } else { AccessToken.Access access = token.getRealmAccess(); if (access == null) { 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 f60246caa1..eaee955b6d 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 @@ -76,29 +76,35 @@ public class RoleNameMapper extends AbstractOIDCProtocolMapper implements OIDCAc UserSessionModel userSession, ClientSessionModel clientSession) { String role = mappingModel.getConfig().get(ROLE_CONFIG); String newName = mappingModel.getConfig().get(NEW_ROLE_NAME); - String appName = null; - int scopeIndex = role.indexOf('.'); - if (scopeIndex > -1) { - appName = role.substring(0, scopeIndex); + + String[] scopedRole = ProtocolMapperUtils.parseRole(role); + String[] newScopedRole = ProtocolMapperUtils.parseRole(newName); + String appName = scopedRole[0]; + String roleName = scopedRole[1]; + if (appName != null) { AccessToken.Access access = token.getResourceAccess(appName); if (access == null) return token; - - role = role.substring(scopeIndex + 1); - if (!access.getRoles().contains(role)) return token; - access.getRoles().remove(role); + if (!access.getRoles().contains(roleName)) return token; + access.getRoles().remove(roleName); } else { AccessToken.Access access = token.getRealmAccess(); if (access == null) return token; - access.getRoles().remove(role); + access.getRoles().remove(roleName); } - String newAppName = null; - scopeIndex = newName.indexOf('.'); - if (scopeIndex > -1) { - newAppName = role.substring(0, scopeIndex); - newName = role.substring(scopeIndex + 1); - token.addAccess(newAppName).addRole(newName); + String newAppName = newScopedRole[0]; + String newRoleName = newScopedRole[1]; + AccessToken.Access access = null; + if (newAppName == null) { + access = token.getRealmAccess(); + if (access == null) { + access = new AccessToken.Access(); + token.setRealmAccess(access); + } + } else { + access = token.addAccess(newAppName); } + access.addRole(newRoleName); return token; } diff --git a/testsuite/integration/src/test/java/org/keycloak/testsuite/oauth/AccessTokenTest.java b/testsuite/integration/src/test/java/org/keycloak/testsuite/oauth/AccessTokenTest.java index 0091e337c6..b6f45bd294 100755 --- a/testsuite/integration/src/test/java/org/keycloak/testsuite/oauth/AccessTokenTest.java +++ b/testsuite/integration/src/test/java/org/keycloak/testsuite/oauth/AccessTokenTest.java @@ -607,6 +607,7 @@ public class AccessTokenTest { app.addProtocolMapper(UserAttributeMapper.createClaimMapper("nested phone", "phone", "home.phone", "String", true, "", true, true)); app.addProtocolMapper(HardcodedRole.create("hard-realm", "hardcoded")); app.addProtocolMapper(HardcodedRole.create("hard-app", "app.hardcoded")); + app.addProtocolMapper(RoleNameMapper.create("rename-app-role", "test-app.customer-user", "realm-user")); session.getTransaction().commit(); session.close(); } @@ -647,6 +648,8 @@ public class AccessTokenTest { nested = (Map)accessToken.getOtherClaims().get("home"); Assert.assertEquals("617-777-6666", nested.get("phone")); Assert.assertTrue(accessToken.getRealmAccess().getRoles().contains("hardcoded")); + Assert.assertTrue(accessToken.getRealmAccess().getRoles().contains("realm-user")); + Assert.assertFalse(accessToken.getResourceAccess("test-app").getRoles().contains("customer-user")); Assert.assertTrue(accessToken.getResourceAccess("app").getRoles().contains("hardcoded")); @@ -665,6 +668,7 @@ public class AccessTokenTest { || model.getName().equals("hard-nested") || model.getName().equals("custom phone") || model.getName().equals("nested phone") + || model.getName().equals("rename-app-role") || model.getName().equals("hard-realm") || model.getName().equals("hard-app") ) { From 6450c4c5f3cf9aa44e1025f6a420c8859b1b16b7 Mon Sep 17 00:00:00 2001 From: Bill Burke Date: Wed, 11 Mar 2015 12:05:27 -0400 Subject: [PATCH 2/2] cleanup and docs for mappers --- docbook/reference/en/en-US/master.xml | 4 + .../reference/en/en-US/modules/Overview.xml | 8 + .../en/en-US/modules/custom-attributes.xml | 150 ++++++++++++++++++ .../en/en-US/modules/protocol-mappers.xml | 17 ++ .../partials/application-detail.html | 7 - .../keycloak/login/LoginFormsProvider.java | 3 +- .../FreeMarkerLoginFormsProvider.java | 7 +- .../freemarker/model/OAuthGrantBean.java | 41 ++--- .../mappers/HardcodedAttributeMapper.java | 5 - .../protocol/oidc/mappers/HardcodedClaim.java | 10 +- .../protocol/oidc/mappers/HardcodedRole.java | 4 +- .../mappers/OIDCAttributeMapperHelper.java | 39 +++++ .../protocol/oidc/mappers/RoleNameMapper.java | 2 +- .../oidc/mappers/UserAttributeMapper.java | 28 +--- .../oidc/mappers/UserPropertyMapper.java | 29 +--- .../oidc/mappers/UserSessionNoteMapper.java | 2 +- .../managers/AuthenticationManager.java | 2 +- .../resources/IdentityBrokerService.java | 2 +- 18 files changed, 250 insertions(+), 110 deletions(-) create mode 100755 docbook/reference/en/en-US/modules/custom-attributes.xml create mode 100755 docbook/reference/en/en-US/modules/protocol-mappers.xml mode change 100644 => 100755 services/src/main/java/org/keycloak/services/resources/IdentityBrokerService.java diff --git a/docbook/reference/en/en-US/master.xml b/docbook/reference/en/en-US/master.xml index 6bbd3010c9..31dcd821b7 100755 --- a/docbook/reference/en/en-US/master.xml +++ b/docbook/reference/en/en-US/master.xml @@ -40,6 +40,8 @@ + + ]> @@ -128,6 +130,8 @@ This one is short &Clustering; &ApplicationClustering; &Proxy; + &CustomAttributes; + &ProtocolMappers; &Migration; diff --git a/docbook/reference/en/en-US/modules/Overview.xml b/docbook/reference/en/en-US/modules/Overview.xml index 53fcd8ffd7..8a545d412a 100755 --- a/docbook/reference/en/en-US/modules/Overview.xml +++ b/docbook/reference/en/en-US/modules/Overview.xml @@ -94,6 +94,14 @@ Multitenancy support. You can host and manage multiple realms for multiple organizations. In the same auth server and even within the same deployed application. + + Identity brokering/chaining. You can make the Keycloak server a child IDP to another SAML 2.0 or OpenID Connect IDP. + + + 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. + 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 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 0000000000..338cdf20fb --- /dev/null +++ b/docbook/reference/en/en-US/modules/custom-attributes.xml @@ -0,0 +1,150 @@ + + Custom User Attributes + 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 themes. +
+ In admin console + To be able to enter custom attributes in the admin console, take the following steps + + + + Create a new theme within the themes/admin/mytheme directory in your distribution. + Where mytheme is whatever you want to name your theme. + + + Create a theme.properties file in this directory that extends the main admin console + theme. + + + + Copy the file themes/admin/base/resources/partials/user-attribute-entry.html into the + a mirror directory in your theme: themes/admin/mytheme/resources/partials/user-attribute-entry.html. + 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. + + + In the user-attribute-entry.html file add your custom user attribute entry form item. For example + + +
+ +
+ + +]]>
+ The ng-model names the user attribute you will store in the database and must have the + form of user.attributes.ATTR_NAME. +
+ + 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. + +
+
+
+
+ In registration page + To be able to enter custom attributes in the registration page, take the following steps + + + + Create a new theme within the themes/login/mytheme directory in your distribution. + Where mytheme is whatever you want to name your theme. + + + Create a theme.properties file in this directory that extends the main admin console + theme. + + + + Copy the file themes/login/base/register.ftl into the + a mirror directory in your theme: themes/login/mytheme/register.ftl. + 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. + + + In the register.ftl file add your custom user attribute entry form item. For example + +
+ +
+ +
+ +
+ +]]>
+ 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 user.attributes.ATTR_NAME. You might also want to replace the label text + with a message property. This will help later if you want to internationalize your pages. +
+ + 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. + +
+
+
+
+ In user account profile page + To be able to manage custom attributes in the user account profile page, take the following steps + + + + Create a new theme within the themes/account/mytheme directory in your distribution. + Where mytheme is whatever you want to name your theme. + + + Create a theme.properties file in this directory that extends the main admin console + theme. + + + + Copy the file themes/account/base/account.ftl into the + a mirror directory in your theme: themes/account/mytheme/account.ftl. + 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. + + + In the account.ftl file add your custom user attribute entry form item. For example + +
+ +
+ +
+ +
+]]>
+ 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 user.attributes.ATTR_NAME. You might also want to replace the label text + with a message property. This will help later if you want to internationalize your pages. +
+ + 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. + +
+
+
+ + + +
\ No newline at end of file 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 0000000000..0c85d6203a --- /dev/null +++ b/docbook/reference/en/en-US/modules/protocol-mappers.xml @@ -0,0 +1,17 @@ + + OIDC Token and SAML Assertion Mappings + + 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. + + + 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. + + \ 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 35e12021aa..c3b1f9dbdb 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 @@ -64,13 +64,6 @@ -
- -
- -
- -
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 f9a9c481e5..11c26fe767 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 f8b85c689f..be59af04a3 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 6d515a1d41..431a606826 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 claimsRequested; - public OAuthGrantBean(String code, ClientModel client, List realmRolesRequested, MultivaluedMap resourceRolesRequested, String accessRequestMessage) { + public OAuthGrantBean(String code, ClientSessionModel clientSession, ClientModel client, List realmRolesRequested, MultivaluedMap resourceRolesRequested, String accessRequestMessage) { this.code = code; this.client = client; this.realmRolesRequested = realmRolesRequested; @@ -50,36 +51,12 @@ public class OAuthGrantBean { // todo support locale List claims = new LinkedList(); - 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 221bcfd273..455375e3f0 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 b54c919c76..ecea9e8a91 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 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 26075e46bb..088389fbec 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 b91c233172..7635a4bc3e 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 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 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 eaee955b6d..1e5784cce7 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 906eef4f15..b38283c262 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 a47f824789..15573ac499 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 4e83120d24..45b22bf3b4 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 25fce1fa35..aa27f17a94 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 7fb4209ca4..d26f695dd8 --- 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);