keycloak-aplcache
Changes
broker/core/src/main/resources/META-INF/services/org.keycloak.broker.provider.IdentityProviderMapper 1(+1 -0)
broker/oidc/src/main/java/org/keycloak/broker/oidc/mappers/ExternalKeycloakRoleToRoleMapper.java 118(+118 -0)
broker/oidc/src/main/resources/META-INF/services/org.keycloak.broker.provider.IdentityProviderMapper 3(+2 -1)
broker/saml/src/main/resources/META-INF/services/org.keycloak.broker.provider.IdentityProviderMapper 2(+1 -1)
testsuite/tomcat7/pom.xml 32(+16 -16)
Details
diff --git a/broker/core/src/main/java/org/keycloak/broker/provider/HardcodedRoleMapper.java b/broker/core/src/main/java/org/keycloak/broker/provider/HardcodedRoleMapper.java
new file mode 100755
index 0000000..31684a0
--- /dev/null
+++ b/broker/core/src/main/java/org/keycloak/broker/provider/HardcodedRoleMapper.java
@@ -0,0 +1,110 @@
+package org.keycloak.broker.provider;
+
+import org.keycloak.broker.provider.AbstractIdentityProviderMapper;
+import org.keycloak.broker.provider.BrokeredIdentityContext;
+import org.keycloak.broker.provider.IdentityBrokerException;
+import org.keycloak.models.ClientModel;
+import org.keycloak.models.IdentityProviderMapperModel;
+import org.keycloak.models.KeycloakSession;
+import org.keycloak.models.RealmModel;
+import org.keycloak.models.RoleModel;
+import org.keycloak.models.UserModel;
+import org.keycloak.provider.ProviderConfigProperty;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
+ * @version $Revision: 1 $
+ */
+public class HardcodedRoleMapper extends AbstractIdentityProviderMapper {
+ public static final String ROLE = "role";
+ protected static final List<ProviderConfigProperty> configProperties = new ArrayList<ProviderConfigProperty>();
+
+ static {
+ ProviderConfigProperty property;
+ property = new ProviderConfigProperty();
+ property.setName(ROLE);
+ property.setLabel("Role");
+ property.setHelpText("Role to grant to user. To reference an application role the syntax is appname.approle, i.e. myapp.myrole");
+ property.setType(ProviderConfigProperty.STRING_TYPE);
+ configProperties.add(property);
+ }
+
+
+
+ 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;
+
+ }
+ }
+
+ public static RoleModel getRoleFromString(RealmModel realm, String roleName) {
+ String[] parsedRole = parseRole(roleName);
+ RoleModel role = null;
+ if (parsedRole[0] == null) {
+ role = realm.getRole(parsedRole[1]);
+ } else {
+ ClientModel client = realm.getClientByClientId(parsedRole[0]);
+ role = client.getRole(parsedRole[1]);
+ }
+ return role;
+ }
+
+ @Override
+ public List<ProviderConfigProperty> getConfigProperties() {
+ return configProperties;
+ }
+
+ @Override
+ public String getDisplayCategory() {
+ return "Role Importer";
+ }
+
+ @Override
+ public String getDisplayType() {
+ return "Hardcoded Role";
+ }
+
+ public static final String[] COMPATIBLE_PROVIDERS = {ANY_PROVIDER};
+
+
+ public static final String PROVIDER_ID = "oidc-hardcoded-role-idp-mapper";
+
+ @Override
+ public String getId() {
+ return PROVIDER_ID;
+ }
+
+ @Override
+ public String[] getCompatibleProviders() {
+ return COMPATIBLE_PROVIDERS;
+ }
+
+ @Override
+ public void importNewUser(KeycloakSession session, RealmModel realm, UserModel user, IdentityProviderMapperModel mapperModel, BrokeredIdentityContext context) {
+ String roleName = mapperModel.getConfig().get(ROLE);
+ RoleModel role = getRoleFromString(realm, roleName);
+ if (role == null) throw new IdentityBrokerException("Unable to find role: " + roleName);
+ user.grantRole(role);
+ }
+
+ @Override
+ public void updateBrokeredUser(KeycloakSession session, RealmModel realm, UserModel user, IdentityProviderMapperModel mapperModel, BrokeredIdentityContext context) {
+
+ }
+
+ @Override
+ public String getHelpText() {
+ return "When user is imported from provider, hardcode a role mapping for it.";
+ }
+}
diff --git a/broker/core/src/main/java/org/keycloak/broker/provider/IdentityProviderMapper.java b/broker/core/src/main/java/org/keycloak/broker/provider/IdentityProviderMapper.java
index 990c6de..4017499 100755
--- a/broker/core/src/main/java/org/keycloak/broker/provider/IdentityProviderMapper.java
+++ b/broker/core/src/main/java/org/keycloak/broker/provider/IdentityProviderMapper.java
@@ -13,6 +13,8 @@ import org.keycloak.provider.ProviderFactory;
* @version $Revision: 1 $
*/
public interface IdentityProviderMapper extends Provider, ProviderFactory<IdentityProviderMapper>,ConfiguredProvider {
+ public static final String ANY_PROVIDER = "*";
+
String[] getCompatibleProviders();
String getDisplayCategory();
String getDisplayType();
diff --git a/broker/core/src/main/resources/META-INF/services/org.keycloak.broker.provider.IdentityProviderMapper b/broker/core/src/main/resources/META-INF/services/org.keycloak.broker.provider.IdentityProviderMapper
new file mode 100755
index 0000000..a3bf053
--- /dev/null
+++ b/broker/core/src/main/resources/META-INF/services/org.keycloak.broker.provider.IdentityProviderMapper
@@ -0,0 +1 @@
+org.keycloak.broker.provider.HardcodedRoleMapper
\ No newline at end of file
diff --git a/broker/oidc/src/main/java/org/keycloak/broker/oidc/mappers/ExternalKeycloakRoleToRoleMapper.java b/broker/oidc/src/main/java/org/keycloak/broker/oidc/mappers/ExternalKeycloakRoleToRoleMapper.java
new file mode 100755
index 0000000..f5bf539
--- /dev/null
+++ b/broker/oidc/src/main/java/org/keycloak/broker/oidc/mappers/ExternalKeycloakRoleToRoleMapper.java
@@ -0,0 +1,118 @@
+package org.keycloak.broker.oidc.mappers;
+
+import org.keycloak.broker.oidc.KeycloakOIDCIdentityProvider;
+import org.keycloak.broker.oidc.KeycloakOIDCIdentityProviderFactory;
+import org.keycloak.broker.oidc.OIDCIdentityProviderFactory;
+import org.keycloak.broker.provider.BrokeredIdentityContext;
+import org.keycloak.broker.provider.HardcodedRoleMapper;
+import org.keycloak.broker.provider.IdentityBrokerException;
+import org.keycloak.models.IdentityProviderMapperModel;
+import org.keycloak.models.KeycloakSession;
+import org.keycloak.models.RealmModel;
+import org.keycloak.models.RoleModel;
+import org.keycloak.models.UserModel;
+import org.keycloak.provider.ProviderConfigProperty;
+import org.keycloak.representations.JsonWebToken;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
+ * @version $Revision: 1 $
+ */
+public class ExternalKeycloakRoleToRoleMapper extends AbstractClaimMapper {
+
+ public static final String[] COMPATIBLE_PROVIDERS = {KeycloakOIDCIdentityProviderFactory.PROVIDER_ID};
+
+ private static final List<ProviderConfigProperty> configProperties = new ArrayList<ProviderConfigProperty>();
+ private static final String EXTERNAL_ROLE = "external.role";
+
+ static {
+ ProviderConfigProperty property;
+ ProviderConfigProperty property1;
+ property1 = new ProviderConfigProperty();
+ property1.setName(EXTERNAL_ROLE);
+ property1.setLabel("External role");
+ property1.setHelpText("External role to check for. To reference an application role the syntax is appname.approle, i.e. myapp.myrole.");
+ property1.setType(ProviderConfigProperty.STRING_TYPE);
+ configProperties.add(property1);
+ property = new ProviderConfigProperty();
+ property.setName(HardcodedRoleMapper.ROLE);
+ property.setLabel("Role");
+ property.setHelpText("Role to grant to user if external role is present. To reference an application role the syntax is appname.approle, i.e. myapp.myrole");
+ property.setType(ProviderConfigProperty.STRING_TYPE);
+ configProperties.add(property);
+ }
+
+ public static final String PROVIDER_ID = "keycloak-oidc-role-to-role-idp-mapper";
+
+
+ @Override
+ public List<ProviderConfigProperty> getConfigProperties() {
+ return configProperties;
+ }
+
+ @Override
+ public String getId() {
+ return PROVIDER_ID;
+ }
+
+ @Override
+ public String[] getCompatibleProviders() {
+ return COMPATIBLE_PROVIDERS;
+ }
+
+ @Override
+ public String getDisplayCategory() {
+ return "Role Importer";
+ }
+
+ @Override
+ public String getDisplayType() {
+ return "External Role to Role";
+ }
+
+ @Override
+ public void importNewUser(KeycloakSession session, RealmModel realm, UserModel user, IdentityProviderMapperModel mapperModel, BrokeredIdentityContext context) {
+ RoleModel role = hasRole(realm, mapperModel, context);
+ if (role != null) {
+ user.grantRole(role);
+ }
+ }
+
+ private RoleModel hasRole(RealmModel realm,IdentityProviderMapperModel mapperModel, BrokeredIdentityContext context) {
+ JsonWebToken token = (JsonWebToken)context.getContextData().get(KeycloakOIDCIdentityProvider.VALIDATED_ACCESS_TOKEN);
+ //if (token == null) return;
+ String roleName = mapperModel.getConfig().get(HardcodedRoleMapper.ROLE);
+ String[] parseRole = HardcodedRoleMapper.parseRole(mapperModel.getConfig().get(EXTERNAL_ROLE));
+ String externalRoleName = parseRole[1];
+ String claimName = null;
+ if (parseRole[0] == null) {
+ claimName = "realm_access.roles";
+ } else {
+ claimName = "resource_access." + parseRole[0] + ".roles";
+ }
+ Object claim = getClaimValue(token, claimName);
+ if (valueEquals(externalRoleName, claim)) {
+ RoleModel role = HardcodedRoleMapper.getRoleFromString(realm, roleName);
+ if (role == null) throw new IdentityBrokerException("Unable to find role: " + roleName);
+ return role;
+ }
+ return null;
+ }
+
+ @Override
+ public void updateBrokeredUser(KeycloakSession session, RealmModel realm, UserModel user, IdentityProviderMapperModel mapperModel, BrokeredIdentityContext context) {
+ RoleModel role = hasRole(realm, mapperModel, context);
+ if (role == null) {
+ user.deleteRoleMapping(role);
+ }
+ }
+
+ @Override
+ public String getHelpText() {
+ return "Looks for an external role in a keycloak access token. If external role exists, grant the user the specified realm or application role.";
+ }
+
+}
diff --git a/broker/oidc/src/main/resources/META-INF/services/org.keycloak.broker.provider.IdentityProviderMapper b/broker/oidc/src/main/resources/META-INF/services/org.keycloak.broker.provider.IdentityProviderMapper
index c2245b6..de86af2 100755
--- a/broker/oidc/src/main/resources/META-INF/services/org.keycloak.broker.provider.IdentityProviderMapper
+++ b/broker/oidc/src/main/resources/META-INF/services/org.keycloak.broker.provider.IdentityProviderMapper
@@ -1,2 +1,3 @@
-org.keycloak.broker.oidc.mappers.RoleMapper
+org.keycloak.broker.oidc.mappers.ClaimToRoleMapper
+org.keycloak.broker.oidc.mappers.ExternalKeycloakRoleToRoleMapper
org.keycloak.broker.oidc.mappers.UserAttributeMapper
\ No newline at end of file
diff --git a/broker/saml/src/main/resources/META-INF/services/org.keycloak.broker.provider.IdentityProviderMapper b/broker/saml/src/main/resources/META-INF/services/org.keycloak.broker.provider.IdentityProviderMapper
index 5051d1d..9de7273 100755
--- a/broker/saml/src/main/resources/META-INF/services/org.keycloak.broker.provider.IdentityProviderMapper
+++ b/broker/saml/src/main/resources/META-INF/services/org.keycloak.broker.provider.IdentityProviderMapper
@@ -1,2 +1,2 @@
-org.keycloak.broker.saml.mappers.RoleMapper
+org.keycloak.broker.saml.mappers.AttributeToRoleMapper
org.keycloak.broker.saml.mappers.UserAttributeMapper
\ No newline at end of file
diff --git a/docbook/reference/en/en-US/modules/identity-broker.xml b/docbook/reference/en/en-US/modules/identity-broker.xml
index 4c1a3c2..8d31ae4 100755
--- a/docbook/reference/en/en-US/modules/identity-broker.xml
+++ b/docbook/reference/en/en-US/modules/identity-broker.xml
@@ -72,7 +72,9 @@
<para>
When using Keycloak as an identity broker, users are not forced to provide their credentials in order to
authenticate in a specific realm. Instead of that, they are presented with a list of identity providers from
- where they can pick one and authenticate. The following diagram demonstrates the steps involved when using
+ where they can pick one and authenticate. You can also configure a hard-coded default broker. In this case
+ the user will not be given a choice, but instead be redirected directly the the parent broker.
+ The following diagram demonstrates the steps involved when using
Keycloak to broker an external identity provider:
</para>
@@ -272,6 +274,25 @@
be used by any other means.
</entry>
</row>
+ <row>
+ <entry>
+ <literal>Store Tokens</literal>
+ </entry>
+ <entry>
+ Any external tokens provided by the parent IDP will be stored.
+ This options is useful if you are using social authentication and need to access the token in order to invoke the
+ API of a social provider on behalf of the user.
+ </entry>
+ </row>
+ <row>
+ <entry>
+ <literal>Stored Tokens Readable</literal>
+ </entry>
+ <entry>
+ Automatically assigns a <literal>broker.READ_TOKEN</literal> role that allows the user
+ to access any stored external tokens via the broker service.
+ </entry>
+ </row>
<row>
<entry>
<literal>Update Profile on First Login</literal>
@@ -293,17 +314,6 @@
You can put number into this field, providers with lower numbers are shown first.
</entry>
</row>
- <!--<row>-->
- <!--<entry>-->
- <!--<literal>Store Tokens</literal>-->
- <!--</entry>-->
- <!--<entry>-->
- <!--Allows you to store tokens issued by an identity provider during the authentication of a specific user.-->
- <!--Tokens are stored and can be retrieved later.-->
- <!--This options is useful if you are using social authentication and need to access the token in order to invoke the-->
- <!--API of a social provider on behalf of the user.-->
- <!--</entry>-->
- <!--</row>-->
</tbody>
</tgroup>
</table>
@@ -1003,6 +1013,14 @@
</tbody>
</tgroup>
</table>
+ <para>
+ You can also import all this configuration data by providing a URL or XML file that points to the entity descriptor of the external
+ SAML IDP you want to connect to.
+ </para>
+ <para>
+ Once you create a SAML provider, there is an <literal>EXPORT</literal> button that appears when viewing that provider.
+ Clicking this button will export a SAML entity descriptor which you can use to
+ </para>
</section>
<section>
@@ -1104,63 +1122,45 @@
</tbody>
</tgroup>
</table>
+ <para>
+ You can also import all this configuration data by providing a URL or file that points to OpenID Provider Metadata (see OIDC Discovery specification)
+ </para>
</section>
- <!--<section>-->
- <!--<title>Retrieving Tokens from Identity Providers</title>-->
- <!--<para>-->
- <!--Keycloak allows you to store tokens and responses from identity providers during the authentication process.-->
- <!--For that, you can use the <literal>Store Token</literal> configuration option, as mentioned before.-->
- <!--</para>-->
- <!--<para>-->
- <!--It also allows you to retrieve these tokens and responses once the user is authenticated in order to use their-->
- <!--information or use them to invoke external resources protected by these tokens.-->
- <!--The latter case is usually related with social providers,-->
- <!--where you usually need to use their tokens to invoke methods on their APIs.-->
- <!--</para>-->
- <!--<para>-->
- <!--To retrieve a token for a particular identity provider you need to send a request as follows:-->
- <!--</para>-->
- <!--<programlisting language="JAVA"><![CDATA[GET /auth/realms/{realm}/broker/{provider_alias}/token HTTP/1.1-->
-<!--Host: localhost:8080-->
-<!--Authorization: Bearer {keycloak_access_token}]]></programlisting>-->
- <!--<para>-->
- <!--In this case, given that you are accessing an protected service in Keycloak, you need to send the access token-->
- <!--issued by Keycloak during the user authentication.-->
- <!--</para>-->
- <!--<para>-->
- <!--By default, the Keycloak access token issued for the application can't be automatically used for retrieve thirdparty token. You will-->
- <!--need to enable this in admin console first:-->
- <!--<orderedlist>-->
- <!--<listitem>-->
- <!--<para>-->
- <!--Click 'Applications' on the left side menu.-->
- <!--</para>-->
- <!--</listitem>-->
- <!--<listitem>-->
- <!--<para>-->
- <!--Select an application from the list.-->
- <!--</para>-->
- <!--</listitem>-->
- <!--<listitem>-->
- <!--<para>-->
- <!--Click the 'Identity Provider' tab.-->
- <!--</para>-->
- <!--</listitem>-->
- <!--<listitem>-->
- <!--<para>-->
- <!--From this page you can configure if an application is allowed to retrieve tokens from an specific identity provider. For that,-->
- <!--just click on the <emphasis>Can Retrieve Token</emphasis> button.-->
- <!--</para>-->
- <!--</listitem>-->
- <!--</orderedlist>-->
- <!--</para>-->
- <!--<note>-->
- <!--<para>-->
- <!--If your application is not at the same origin as the authentication server, make sure you have properly configured CORS.-->
- <!--</para>-->
- <!--</note>-->
- <!--</section>-->
+ <section>
+ <title>Retrieving Tokens from Identity Providers</title>
+ <para>
+ Keycloak allows you to store tokens and responses from identity providers during the authentication process.
+ For that, you can use the <literal>Store Token</literal> configuration option, as mentioned before.
+ </para>
+ <para>
+ It also allows you to retrieve these tokens and responses once the user is authenticated in order to use their
+ information or use them to invoke external resources protected by these tokens.
+ The latter case is usually related with social providers,
+ where you usually need to use their tokens to invoke methods on their APIs.
+ </para>
+ <para>
+ To retrieve a token for a particular identity provider you need to send a request as follows:
+ </para>
+ <programlisting language="JAVA"><![CDATA[GET /auth/realms/{realm}/broker/{provider_alias}/token HTTP/1.1
+Host: localhost:8080
+Authorization: Bearer {keycloak_access_token}]]></programlisting>
+ <para>
+ In this case, given that you are accessing an protected service in Keycloak, you need to send the access token
+ issued by Keycloak during the user authentication.
+ </para>
+ <para>
+ By default, the Keycloak access token issued for the application can't be automatically used for retrieve thirdparty token.
+ A user will have to have the <literal>broker.READ_TOKEN</literal> role. The client will also have to have that role
+ in its scope. In the broker configuration page you can automatically assign this role to newly imported users by
+ turning on the <literal>Stored Tokens Readable</literal> switch.
+ </para>
+ <note>
+ <para>
+ If your application is not at the same origin as the authentication server, make sure you have properly configured CORS.
+ </para>
+ </note>
+ </section>
<section>
<title>Automatically Select and Identity Provider</title>
@@ -1189,6 +1189,19 @@ keycloak.createLoginUrl({
</section>
<section>
+ <title>Mapping/Importing SAML and OIDC Metadata</title>
+ <para>
+ You can import SAML assertion data, OpenID Connect ID Token claims, and Keycloak access token claims
+ into new users that are imported from a brokered IDP. After you configure a broker, you'll see a <literal>Mappers</literal>
+ button appear. Click on that and you'll get to the list of mappers that are assigned to this broker. There is a
+ <literal>Create</literal> button on this page. Clicking on this create button allows you to create a broker mapper.
+ Broker mappers can import SAML attributes or OIDC ID/Access token claims into user attributes. You can assign
+ a role mapping to a user if a claim or external role exists. There's a bunch of options here so just mouse over
+ the tool tips to see what each mapper can do for you.
+ </para>
+ </section>
+
+ <section>
<title>Examples</title>
<para>
Keycloak provides some useful examples about how to use it as an identity broker.
diff --git a/services/src/main/java/org/keycloak/services/resources/admin/IdentityProviderResource.java b/services/src/main/java/org/keycloak/services/resources/admin/IdentityProviderResource.java
index 114aa06..539c410 100755
--- a/services/src/main/java/org/keycloak/services/resources/admin/IdentityProviderResource.java
+++ b/services/src/main/java/org/keycloak/services/resources/admin/IdentityProviderResource.java
@@ -181,7 +181,7 @@ public class IdentityProviderResource {
for (ProviderFactory factory : factories) {
IdentityProviderMapper mapper = (IdentityProviderMapper)factory;
for (String type : mapper.getCompatibleProviders()) {
- if (type.equals(identityProviderModel.getProviderId())) {
+ if (IdentityProviderMapper.ANY_PROVIDER.equals(type) || type.equals(identityProviderModel.getProviderId())) {
IdentityProviderMapperTypeRepresentation rep = new IdentityProviderMapperTypeRepresentation();
rep.setId(mapper.getId());
rep.setCategory(mapper.getDisplayCategory());
@@ -198,7 +198,7 @@ public class IdentityProviderResource {
rep.getProperties().add(propRep);
}
types.put(rep.getId(), rep);
-
+ break;
}
}
}
diff --git a/services/src/main/java/org/keycloak/services/resources/IdentityBrokerService.java b/services/src/main/java/org/keycloak/services/resources/IdentityBrokerService.java
index e51c209..c10ef1e 100755
--- a/services/src/main/java/org/keycloak/services/resources/IdentityBrokerService.java
+++ b/services/src/main/java/org/keycloak/services/resources/IdentityBrokerService.java
@@ -283,9 +283,10 @@ public class IdentityBrokerService implements IdentityProvider.AuthenticationCal
} catch (Exception e) {
return redirectToLoginPage(e, clientCode);
}
+ } else {
+ updateFederatedIdentity(context, federatedUser);
}
- updateFederatedIdentity(context, federatedUser);
UserSessionModel userSession = this.session.sessions()
.createUserSession(this.realmModel, federatedUser, federatedUser.getUsername(), this.clientConnection.getRemoteAddr(), "broker", false, context.getBrokerSessionId(), context.getBrokerUserId());
@@ -335,26 +336,26 @@ public class IdentityBrokerService implements IdentityProvider.AuthenticationCal
return Response.status(302).location(UriBuilder.fromUri(clientSession.getRedirectUri()).build()).build();
}
- private void updateFederatedIdentity(BrokeredIdentityContext updatedIdentity, UserModel federatedUser) {
- FederatedIdentityModel federatedIdentityModel = this.session.users().getFederatedIdentity(federatedUser, updatedIdentity.getIdpConfig().getAlias(), this.realmModel);
+ private void updateFederatedIdentity(BrokeredIdentityContext context, UserModel federatedUser) {
+ FederatedIdentityModel federatedIdentityModel = this.session.users().getFederatedIdentity(federatedUser, context.getIdpConfig().getAlias(), this.realmModel);
// Skip DB write if tokens are null or equal
- if (!ObjectUtil.isEqualOrNull(updatedIdentity.getToken(), federatedIdentityModel.getToken())) {
- federatedIdentityModel.setToken(updatedIdentity.getToken());
+ if (context.getIdpConfig().isStoreToken() && !ObjectUtil.isEqualOrNull(context.getToken(), federatedIdentityModel.getToken())) {
+ federatedIdentityModel.setToken(context.getToken());
this.session.users().updateFederatedIdentity(this.realmModel, federatedUser, federatedIdentityModel);
if (isDebugEnabled()) {
- LOGGER.debugf("Identity [%s] update with response from identity provider [%s].", federatedUser, updatedIdentity.getIdpConfig().getAlias());
+ LOGGER.debugf("Identity [%s] update with response from identity provider [%s].", federatedUser, context.getIdpConfig().getAlias());
}
}
- updatedIdentity.getIdp().updateBrokeredUser(session, realmModel, federatedUser, updatedIdentity);
- Set<IdentityProviderMapperModel> mappers = realmModel.getIdentityProviderMappersByAlias(updatedIdentity.getIdpConfig().getAlias());
+ context.getIdp().updateBrokeredUser(session, realmModel, federatedUser, context);
+ Set<IdentityProviderMapperModel> mappers = realmModel.getIdentityProviderMappersByAlias(context.getIdpConfig().getAlias());
if (mappers != null) {
KeycloakSessionFactory sessionFactory = session.getKeycloakSessionFactory();
for (IdentityProviderMapperModel mapper : mappers) {
IdentityProviderMapper target = (IdentityProviderMapper)sessionFactory.getProviderFactory(IdentityProviderMapper.class, mapper.getIdentityProviderMapper());
- target.updateBrokeredUser(session, realmModel, federatedUser, mapper, updatedIdentity);
+ target.updateBrokeredUser(session, realmModel, federatedUser, mapper, context);
}
}
@@ -484,14 +485,14 @@ public class IdentityBrokerService implements IdentityProvider.AuthenticationCal
throw new IdentityBrokerException("Configuration for identity provider [" + providerId + "] not found.");
}
- private UserModel createUser(BrokeredIdentityContext updatedIdentity) {
- FederatedIdentityModel federatedIdentityModel = new FederatedIdentityModel(updatedIdentity.getIdpConfig().getAlias(), updatedIdentity.getId(),
- updatedIdentity.getUsername(), updatedIdentity.getToken());
+ private UserModel createUser(BrokeredIdentityContext context) {
+ FederatedIdentityModel federatedIdentityModel = new FederatedIdentityModel(context.getIdpConfig().getAlias(), context.getId(),
+ context.getUsername(), context.getToken());
// Check if no user already exists with this username or email
UserModel existingUser = null;
- if (updatedIdentity.getEmail() != null) {
- existingUser = this.session.users().getUserByEmail(updatedIdentity.getEmail(), this.realmModel);
+ if (context.getEmail() != null) {
+ existingUser = this.session.users().getUserByEmail(context.getEmail(), this.realmModel);
}
if (existingUser != null) {
@@ -499,13 +500,13 @@ public class IdentityBrokerService implements IdentityProvider.AuthenticationCal
throw new IdentityBrokerException(Messages.FEDERATED_IDENTITY_EMAIL_EXISTS);
}
- String username = updatedIdentity.getUsername();
- if (this.realmModel.isRegistrationEmailAsUsername() && !Validation.isEmpty(updatedIdentity.getEmail())) {
- username = updatedIdentity.getEmail();
+ String username = context.getUsername();
+ if (this.realmModel.isRegistrationEmailAsUsername() && !Validation.isEmpty(context.getEmail())) {
+ username = context.getEmail();
} else if (username == null) {
- username = updatedIdentity.getIdpConfig().getAlias() + "." + updatedIdentity.getId();
+ username = context.getIdpConfig().getAlias() + "." + context.getId();
} else {
- username = updatedIdentity.getIdpConfig().getAlias() + "." + updatedIdentity.getUsername();
+ username = context.getIdpConfig().getAlias() + "." + context.getUsername();
}
if (username != null) {
username = username.trim();
@@ -529,33 +530,36 @@ public class IdentityBrokerService implements IdentityProvider.AuthenticationCal
}
federatedUser.setEnabled(true);
- federatedUser.setEmail(updatedIdentity.getEmail());
- federatedUser.setFirstName(updatedIdentity.getFirstName());
- federatedUser.setLastName(updatedIdentity.getLastName());
+ federatedUser.setEmail(context.getEmail());
+ federatedUser.setFirstName(context.getFirstName());
+ federatedUser.setLastName(context.getLastName());
- if (updatedIdentity.getIdpConfig().isAddReadTokenRoleOnCreate()) {
+ if (context.getIdpConfig().isAddReadTokenRoleOnCreate()) {
RoleModel readTokenRole = realmModel.getClientByClientId(Constants.BROKER_SERVICE_CLIENT_ID).getRole(READ_TOKEN_ROLE);
federatedUser.grantRole(readTokenRole);
}
+ if (context.getIdpConfig().isStoreToken()) {
+ federatedIdentityModel.setToken(context.getToken());
+ }
this.session.users().addFederatedIdentity(this.realmModel, federatedUser, federatedIdentityModel);
- updatedIdentity.getIdp().importNewUser(session, realmModel, federatedUser, updatedIdentity);
- Set<IdentityProviderMapperModel> mappers = realmModel.getIdentityProviderMappersByAlias(updatedIdentity.getIdpConfig().getAlias());
+ context.getIdp().importNewUser(session, realmModel, federatedUser, context);
+ Set<IdentityProviderMapperModel> mappers = realmModel.getIdentityProviderMappersByAlias(context.getIdpConfig().getAlias());
if (mappers != null) {
KeycloakSessionFactory sessionFactory = session.getKeycloakSessionFactory();
for (IdentityProviderMapperModel mapper : mappers) {
IdentityProviderMapper target = (IdentityProviderMapper)sessionFactory.getProviderFactory(IdentityProviderMapper.class, mapper.getIdentityProviderMapper());
- target.importNewUser(session, realmModel, federatedUser, mapper, updatedIdentity);
+ target.importNewUser(session, realmModel, federatedUser, mapper, context);
}
}
this.event.clone().user(federatedUser).event(EventType.REGISTER)
.detail(Details.IDENTITY_PROVIDER, federatedIdentityModel.getIdentityProvider())
- .detail(Details.IDENTITY_PROVIDER_USERNAME, updatedIdentity.getUsername())
+ .detail(Details.IDENTITY_PROVIDER_USERNAME, context.getUsername())
.removeDetail("auth_method")
.success();
testsuite/tomcat7/pom.xml 32(+16 -16)
diff --git a/testsuite/tomcat7/pom.xml b/testsuite/tomcat7/pom.xml
index 8f79b62..d6b0d53 100755
--- a/testsuite/tomcat7/pom.xml
+++ b/testsuite/tomcat7/pom.xml
@@ -13,11 +13,26 @@
<name>Keycloak Tomcat 7 Integration TestSuite</name>
<properties>
<!--<tomcat.version>8.0.14</tomcat.version>-->
- <tomcat.version>7.0.54</tomcat.version>
+ <tomcat.version>7.0.59</tomcat.version>
</properties>
<description />
<dependencies>
+ <dependency>
+ <groupId>org.apache.tomcat</groupId>
+ <artifactId>tomcat-catalina</artifactId>
+ <version>7.0.59</version>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.tomcat</groupId>
+ <artifactId>tomcat-util</artifactId>
+ <version>7.0.59</version>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.tomcat.embed</groupId>
+ <artifactId>tomcat-embed-core</artifactId>
+ <version>7.0.59</version>
+ </dependency>
<dependency>
<groupId>org.keycloak</groupId>
<artifactId>keycloak-dependencies-server-all</artifactId>
@@ -199,21 +214,6 @@
<scope>test</scope>
</dependency>
- <dependency>
- <groupId>org.apache.tomcat</groupId>
- <artifactId>tomcat-catalina</artifactId>
- <version>${tomcat.version}</version>
- </dependency>
- <dependency>
- <groupId>org.apache.tomcat</groupId>
- <artifactId>tomcat-util</artifactId>
- <version>${tomcat.version}</version>
- </dependency>
- <dependency>
- <groupId>org.apache.tomcat.embed</groupId>
- <artifactId>tomcat-embed-core</artifactId>
- <version>${tomcat.version}</version>
- </dependency>
</dependencies>
<build>
diff --git a/testsuite/tomcat7/src/test/java/org/keycloak/testsuite/Tomcat7Test.java b/testsuite/tomcat7/src/test/java/org/keycloak/testsuite/Tomcat7Test.java
index 7a38655..3f20d16 100755
--- a/testsuite/tomcat7/src/test/java/org/keycloak/testsuite/Tomcat7Test.java
+++ b/testsuite/tomcat7/src/test/java/org/keycloak/testsuite/Tomcat7Test.java
@@ -22,6 +22,7 @@
package org.keycloak.testsuite;
import org.apache.catalina.startup.Tomcat;
+import org.apache.tomcat.util.http.mapper.Mapper;
import org.junit.AfterClass;
import org.junit.BeforeClass;
import org.junit.ClassRule;