commit
f17863041a
13 changed files with 381 additions and 185 deletions
110
broker/core/src/main/java/org/keycloak/broker/provider/HardcodedRoleMapper.java
Executable file
110
broker/core/src/main/java/org/keycloak/broker/provider/HardcodedRoleMapper.java
Executable file
|
@ -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.";
|
||||||
|
}
|
||||||
|
}
|
|
@ -13,6 +13,8 @@ import org.keycloak.provider.ProviderFactory;
|
||||||
* @version $Revision: 1 $
|
* @version $Revision: 1 $
|
||||||
*/
|
*/
|
||||||
public interface IdentityProviderMapper extends Provider, ProviderFactory<IdentityProviderMapper>,ConfiguredProvider {
|
public interface IdentityProviderMapper extends Provider, ProviderFactory<IdentityProviderMapper>,ConfiguredProvider {
|
||||||
|
public static final String ANY_PROVIDER = "*";
|
||||||
|
|
||||||
String[] getCompatibleProviders();
|
String[] getCompatibleProviders();
|
||||||
String getDisplayCategory();
|
String getDisplayCategory();
|
||||||
String getDisplayType();
|
String getDisplayType();
|
||||||
|
|
|
@ -0,0 +1 @@
|
||||||
|
org.keycloak.broker.provider.HardcodedRoleMapper
|
|
@ -3,8 +3,8 @@ package org.keycloak.broker.oidc.mappers;
|
||||||
import org.keycloak.broker.oidc.KeycloakOIDCIdentityProviderFactory;
|
import org.keycloak.broker.oidc.KeycloakOIDCIdentityProviderFactory;
|
||||||
import org.keycloak.broker.oidc.OIDCIdentityProviderFactory;
|
import org.keycloak.broker.oidc.OIDCIdentityProviderFactory;
|
||||||
import org.keycloak.broker.provider.BrokeredIdentityContext;
|
import org.keycloak.broker.provider.BrokeredIdentityContext;
|
||||||
|
import org.keycloak.broker.provider.HardcodedRoleMapper;
|
||||||
import org.keycloak.broker.provider.IdentityBrokerException;
|
import org.keycloak.broker.provider.IdentityBrokerException;
|
||||||
import org.keycloak.models.ClientModel;
|
|
||||||
import org.keycloak.models.IdentityProviderMapperModel;
|
import org.keycloak.models.IdentityProviderMapperModel;
|
||||||
import org.keycloak.models.KeycloakSession;
|
import org.keycloak.models.KeycloakSession;
|
||||||
import org.keycloak.models.RealmModel;
|
import org.keycloak.models.RealmModel;
|
||||||
|
@ -19,14 +19,12 @@ import java.util.List;
|
||||||
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
|
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
|
||||||
* @version $Revision: 1 $
|
* @version $Revision: 1 $
|
||||||
*/
|
*/
|
||||||
public class RoleMapper extends AbstractClaimMapper {
|
public class ClaimToRoleMapper extends AbstractClaimMapper {
|
||||||
|
|
||||||
public static final String[] COMPATIBLE_PROVIDERS = {KeycloakOIDCIdentityProviderFactory.PROVIDER_ID, OIDCIdentityProviderFactory.PROVIDER_ID};
|
public static final String[] COMPATIBLE_PROVIDERS = {KeycloakOIDCIdentityProviderFactory.PROVIDER_ID, OIDCIdentityProviderFactory.PROVIDER_ID};
|
||||||
|
|
||||||
private static final List<ProviderConfigProperty> configProperties = new ArrayList<ProviderConfigProperty>();
|
private static final List<ProviderConfigProperty> configProperties = new ArrayList<ProviderConfigProperty>();
|
||||||
|
|
||||||
public static final String ROLE = "role";
|
|
||||||
|
|
||||||
static {
|
static {
|
||||||
ProviderConfigProperty property;
|
ProviderConfigProperty property;
|
||||||
ProviderConfigProperty property1;
|
ProviderConfigProperty property1;
|
||||||
|
@ -43,29 +41,15 @@ public class RoleMapper extends AbstractClaimMapper {
|
||||||
property1.setType(ProviderConfigProperty.STRING_TYPE);
|
property1.setType(ProviderConfigProperty.STRING_TYPE);
|
||||||
configProperties.add(property1);
|
configProperties.add(property1);
|
||||||
property = new ProviderConfigProperty();
|
property = new ProviderConfigProperty();
|
||||||
property.setName(ROLE);
|
property.setName(HardcodedRoleMapper.ROLE);
|
||||||
property.setLabel("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.setHelpText("Role to grant to user if claim is present. To reference an application role the syntax is appname.approle, i.e. myapp.myrole");
|
||||||
property.setType(ProviderConfigProperty.STRING_TYPE);
|
property.setType(ProviderConfigProperty.STRING_TYPE);
|
||||||
configProperties.add(property);
|
configProperties.add(property);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static final String PROVIDER_ID = "oidc-role-idp-mapper";
|
public static final String PROVIDER_ID = "oidc-role-idp-mapper";
|
||||||
|
|
||||||
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;
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public List<ProviderConfigProperty> getConfigProperties() {
|
public List<ProviderConfigProperty> getConfigProperties() {
|
||||||
|
@ -89,36 +73,24 @@ public class RoleMapper extends AbstractClaimMapper {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String getDisplayType() {
|
public String getDisplayType() {
|
||||||
return "Role Importer";
|
return "Claim to Role";
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void importNewUser(KeycloakSession session, RealmModel realm, UserModel user, IdentityProviderMapperModel mapperModel, BrokeredIdentityContext context) {
|
public void importNewUser(KeycloakSession session, RealmModel realm, UserModel user, IdentityProviderMapperModel mapperModel, BrokeredIdentityContext context) {
|
||||||
String roleName = mapperModel.getConfig().get(ROLE);
|
String roleName = mapperModel.getConfig().get(HardcodedRoleMapper.ROLE);
|
||||||
if (hasClaimValue(mapperModel, context)) {
|
if (hasClaimValue(mapperModel, context)) {
|
||||||
RoleModel role = getRoleFromString(realm, roleName);
|
RoleModel role = HardcodedRoleMapper.getRoleFromString(realm, roleName);
|
||||||
if (role == null) throw new IdentityBrokerException("Unable to find role: " + roleName);
|
if (role == null) throw new IdentityBrokerException("Unable to find role: " + roleName);
|
||||||
user.grantRole(role);
|
user.grantRole(role);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
protected 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
|
@Override
|
||||||
public void updateBrokeredUser(KeycloakSession session, RealmModel realm, UserModel user, IdentityProviderMapperModel mapperModel, BrokeredIdentityContext context) {
|
public void updateBrokeredUser(KeycloakSession session, RealmModel realm, UserModel user, IdentityProviderMapperModel mapperModel, BrokeredIdentityContext context) {
|
||||||
String roleName = mapperModel.getConfig().get(ROLE);
|
String roleName = mapperModel.getConfig().get(HardcodedRoleMapper.ROLE);
|
||||||
if (!hasClaimValue(mapperModel, context)) {
|
if (!hasClaimValue(mapperModel, context)) {
|
||||||
RoleModel role = getRoleFromString(realm, roleName);
|
RoleModel role = HardcodedRoleMapper.getRoleFromString(realm, roleName);
|
||||||
if (role == null) throw new IdentityBrokerException("Unable to find role: " + roleName);
|
if (role == null) throw new IdentityBrokerException("Unable to find role: " + roleName);
|
||||||
user.deleteRoleMapping(role);
|
user.deleteRoleMapping(role);
|
||||||
}
|
}
|
|
@ -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.";
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -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
|
org.keycloak.broker.oidc.mappers.UserAttributeMapper
|
|
@ -2,6 +2,7 @@ package org.keycloak.broker.saml.mappers;
|
||||||
|
|
||||||
import org.keycloak.broker.provider.AbstractIdentityProviderMapper;
|
import org.keycloak.broker.provider.AbstractIdentityProviderMapper;
|
||||||
import org.keycloak.broker.provider.BrokeredIdentityContext;
|
import org.keycloak.broker.provider.BrokeredIdentityContext;
|
||||||
|
import org.keycloak.broker.provider.HardcodedRoleMapper;
|
||||||
import org.keycloak.broker.provider.IdentityBrokerException;
|
import org.keycloak.broker.provider.IdentityBrokerException;
|
||||||
import org.keycloak.broker.saml.SAMLEndpoint;
|
import org.keycloak.broker.saml.SAMLEndpoint;
|
||||||
import org.keycloak.broker.saml.SAMLIdentityProviderFactory;
|
import org.keycloak.broker.saml.SAMLIdentityProviderFactory;
|
||||||
|
@ -25,13 +26,12 @@ import java.util.Map;
|
||||||
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
|
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
|
||||||
* @version $Revision: 1 $
|
* @version $Revision: 1 $
|
||||||
*/
|
*/
|
||||||
public class RoleMapper extends AbstractIdentityProviderMapper {
|
public class AttributeToRoleMapper extends AbstractIdentityProviderMapper {
|
||||||
|
|
||||||
public static final String[] COMPATIBLE_PROVIDERS = {SAMLIdentityProviderFactory.PROVIDER_ID};
|
public static final String[] COMPATIBLE_PROVIDERS = {SAMLIdentityProviderFactory.PROVIDER_ID};
|
||||||
|
|
||||||
private static final List<ProviderConfigProperty> configProperties = new ArrayList<ProviderConfigProperty>();
|
private static final List<ProviderConfigProperty> configProperties = new ArrayList<ProviderConfigProperty>();
|
||||||
|
|
||||||
public static final String ROLE = "role";
|
|
||||||
public static final String ATTRIBUTE_NAME = "attribute.name";
|
public static final String ATTRIBUTE_NAME = "attribute.name";
|
||||||
public static final String ATTRIBUTE_FRIENDLY_NAME = "attribute.friendly.name";
|
public static final String ATTRIBUTE_FRIENDLY_NAME = "attribute.friendly.name";
|
||||||
public static final String ATTRIBUTE_VALUE = "attribute.value";
|
public static final String ATTRIBUTE_VALUE = "attribute.value";
|
||||||
|
@ -57,7 +57,7 @@ public class RoleMapper extends AbstractIdentityProviderMapper {
|
||||||
property.setType(ProviderConfigProperty.STRING_TYPE);
|
property.setType(ProviderConfigProperty.STRING_TYPE);
|
||||||
configProperties.add(property);
|
configProperties.add(property);
|
||||||
property = new ProviderConfigProperty();
|
property = new ProviderConfigProperty();
|
||||||
property.setName(ROLE);
|
property.setName(HardcodedRoleMapper.ROLE);
|
||||||
property.setLabel("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.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);
|
property.setType(ProviderConfigProperty.STRING_TYPE);
|
||||||
|
@ -66,20 +66,6 @@ public class RoleMapper extends AbstractIdentityProviderMapper {
|
||||||
|
|
||||||
public static final String PROVIDER_ID = "saml-role-idp-mapper";
|
public static final String PROVIDER_ID = "saml-role-idp-mapper";
|
||||||
|
|
||||||
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;
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public List<ProviderConfigProperty> getConfigProperties() {
|
public List<ProviderConfigProperty> getConfigProperties() {
|
||||||
return configProperties;
|
return configProperties;
|
||||||
|
@ -102,31 +88,19 @@ public class RoleMapper extends AbstractIdentityProviderMapper {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String getDisplayType() {
|
public String getDisplayType() {
|
||||||
return "Role Mapper";
|
return "SAML Attribute to Role";
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void importNewUser(KeycloakSession session, RealmModel realm, UserModel user, IdentityProviderMapperModel mapperModel, BrokeredIdentityContext context) {
|
public void importNewUser(KeycloakSession session, RealmModel realm, UserModel user, IdentityProviderMapperModel mapperModel, BrokeredIdentityContext context) {
|
||||||
String roleName = mapperModel.getConfig().get(ROLE);
|
String roleName = mapperModel.getConfig().get(HardcodedRoleMapper.ROLE);
|
||||||
if (isAttributePresent(mapperModel, context)) {
|
if (isAttributePresent(mapperModel, context)) {
|
||||||
RoleModel role = getRoleFromString(realm, roleName);
|
RoleModel role = HardcodedRoleMapper.getRoleFromString(realm, roleName);
|
||||||
if (role == null) throw new IdentityBrokerException("Unable to find role: " + roleName);
|
if (role == null) throw new IdentityBrokerException("Unable to find role: " + roleName);
|
||||||
user.grantRole(role);
|
user.grantRole(role);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
protected 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;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected boolean isAttributePresent(IdentityProviderMapperModel mapperModel, BrokeredIdentityContext context) {
|
protected boolean isAttributePresent(IdentityProviderMapperModel mapperModel, BrokeredIdentityContext context) {
|
||||||
String name = mapperModel.getConfig().get(ATTRIBUTE_NAME);
|
String name = mapperModel.getConfig().get(ATTRIBUTE_NAME);
|
||||||
if (name != null && name.trim().equals("")) name = null;
|
if (name != null && name.trim().equals("")) name = null;
|
||||||
|
@ -149,9 +123,9 @@ public class RoleMapper extends AbstractIdentityProviderMapper {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void updateBrokeredUser(KeycloakSession session, RealmModel realm, UserModel user, IdentityProviderMapperModel mapperModel, BrokeredIdentityContext context) {
|
public void updateBrokeredUser(KeycloakSession session, RealmModel realm, UserModel user, IdentityProviderMapperModel mapperModel, BrokeredIdentityContext context) {
|
||||||
String roleName = mapperModel.getConfig().get(ROLE);
|
String roleName = mapperModel.getConfig().get(HardcodedRoleMapper.ROLE);
|
||||||
if (!isAttributePresent(mapperModel, context)) {
|
if (!isAttributePresent(mapperModel, context)) {
|
||||||
RoleModel role = getRoleFromString(realm, roleName);
|
RoleModel role = HardcodedRoleMapper.getRoleFromString(realm, roleName);
|
||||||
if (role == null) throw new IdentityBrokerException("Unable to find role: " + roleName);
|
if (role == null) throw new IdentityBrokerException("Unable to find role: " + roleName);
|
||||||
user.deleteRoleMapping(role);
|
user.deleteRoleMapping(role);
|
||||||
}
|
}
|
|
@ -1,2 +1,2 @@
|
||||||
org.keycloak.broker.saml.mappers.RoleMapper
|
org.keycloak.broker.saml.mappers.AttributeToRoleMapper
|
||||||
org.keycloak.broker.saml.mappers.UserAttributeMapper
|
org.keycloak.broker.saml.mappers.UserAttributeMapper
|
|
@ -72,7 +72,9 @@
|
||||||
<para>
|
<para>
|
||||||
When using Keycloak as an identity broker, users are not forced to provide their credentials in order to
|
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
|
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:
|
Keycloak to broker an external identity provider:
|
||||||
</para>
|
</para>
|
||||||
|
|
||||||
|
@ -272,6 +274,25 @@
|
||||||
be used by any other means.
|
be used by any other means.
|
||||||
</entry>
|
</entry>
|
||||||
</row>
|
</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>
|
<row>
|
||||||
<entry>
|
<entry>
|
||||||
<literal>Update Profile on First Login</literal>
|
<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.
|
You can put number into this field, providers with lower numbers are shown first.
|
||||||
</entry>
|
</entry>
|
||||||
</row>
|
</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>
|
</tbody>
|
||||||
</tgroup>
|
</tgroup>
|
||||||
</table>
|
</table>
|
||||||
|
@ -1003,6 +1013,14 @@
|
||||||
</tbody>
|
</tbody>
|
||||||
</tgroup>
|
</tgroup>
|
||||||
</table>
|
</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>
|
||||||
|
|
||||||
<section>
|
<section>
|
||||||
|
@ -1104,63 +1122,45 @@
|
||||||
</tbody>
|
</tbody>
|
||||||
</tgroup>
|
</tgroup>
|
||||||
</table>
|
</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>
|
||||||
|
|
||||||
<!--<section>-->
|
<section>
|
||||||
<!--<title>Retrieving Tokens from Identity Providers</title>-->
|
<title>Retrieving Tokens from Identity Providers</title>
|
||||||
<!--<para>-->
|
<para>
|
||||||
<!--Keycloak allows you to store tokens and responses from identity providers during the authentication process.-->
|
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.-->
|
For that, you can use the <literal>Store Token</literal> configuration option, as mentioned before.
|
||||||
<!--</para>-->
|
</para>
|
||||||
<!--<para>-->
|
<para>
|
||||||
<!--It also allows you to retrieve these tokens and responses once the user is authenticated in order to use their-->
|
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.-->
|
information or use them to invoke external resources protected by these tokens.
|
||||||
<!--The latter case is usually related with social providers,-->
|
The latter case is usually related with social providers,
|
||||||
<!--where you usually need to use their tokens to invoke methods on their APIs.-->
|
where you usually need to use their tokens to invoke methods on their APIs.
|
||||||
<!--</para>-->
|
</para>
|
||||||
<!--<para>-->
|
<para>
|
||||||
<!--To retrieve a token for a particular identity provider you need to send a request as follows:-->
|
To retrieve a token for a particular identity provider you need to send a request as follows:
|
||||||
<!--</para>-->
|
</para>
|
||||||
<!--<programlisting language="JAVA"><![CDATA[GET /auth/realms/{realm}/broker/{provider_alias}/token HTTP/1.1-->
|
<programlisting language="JAVA"><![CDATA[GET /auth/realms/{realm}/broker/{provider_alias}/token HTTP/1.1
|
||||||
<!--Host: localhost:8080-->
|
Host: localhost:8080
|
||||||
<!--Authorization: Bearer {keycloak_access_token}]]></programlisting>-->
|
Authorization: Bearer {keycloak_access_token}]]></programlisting>
|
||||||
<!--<para>-->
|
<para>
|
||||||
<!--In this case, given that you are accessing an protected service in Keycloak, you need to send the access token-->
|
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.-->
|
issued by Keycloak during the user authentication.
|
||||||
<!--</para>-->
|
</para>
|
||||||
<!--<para>-->
|
<para>
|
||||||
<!--By default, the Keycloak access token issued for the application can't be automatically used for retrieve thirdparty token. You will-->
|
By default, the Keycloak access token issued for the application can't be automatically used for retrieve thirdparty token.
|
||||||
<!--need to enable this in admin console first:-->
|
A user will have to have the <literal>broker.READ_TOKEN</literal> role. The client will also have to have that role
|
||||||
<!--<orderedlist>-->
|
in its scope. In the broker configuration page you can automatically assign this role to newly imported users by
|
||||||
<!--<listitem>-->
|
turning on the <literal>Stored Tokens Readable</literal> switch.
|
||||||
<!--<para>-->
|
</para>
|
||||||
<!--Click 'Applications' on the left side menu.-->
|
<note>
|
||||||
<!--</para>-->
|
<para>
|
||||||
<!--</listitem>-->
|
If your application is not at the same origin as the authentication server, make sure you have properly configured CORS.
|
||||||
<!--<listitem>-->
|
</para>
|
||||||
<!--<para>-->
|
</note>
|
||||||
<!--Select an application from the list.-->
|
</section>
|
||||||
<!--</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>
|
<section>
|
||||||
<title>Automatically Select and Identity Provider</title>
|
<title>Automatically Select and Identity Provider</title>
|
||||||
|
@ -1188,6 +1188,19 @@ keycloak.createLoginUrl({
|
||||||
});]]></programlisting>
|
});]]></programlisting>
|
||||||
</section>
|
</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>
|
<section>
|
||||||
<title>Examples</title>
|
<title>Examples</title>
|
||||||
<para>
|
<para>
|
||||||
|
|
|
@ -283,9 +283,10 @@ public class IdentityBrokerService implements IdentityProvider.AuthenticationCal
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
return redirectToLoginPage(e, clientCode);
|
return redirectToLoginPage(e, clientCode);
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
updateFederatedIdentity(context, federatedUser);
|
||||||
}
|
}
|
||||||
|
|
||||||
updateFederatedIdentity(context, federatedUser);
|
|
||||||
|
|
||||||
UserSessionModel userSession = this.session.sessions()
|
UserSessionModel userSession = this.session.sessions()
|
||||||
.createUserSession(this.realmModel, federatedUser, federatedUser.getUsername(), this.clientConnection.getRemoteAddr(), "broker", false, context.getBrokerSessionId(), context.getBrokerUserId());
|
.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();
|
return Response.status(302).location(UriBuilder.fromUri(clientSession.getRedirectUri()).build()).build();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void updateFederatedIdentity(BrokeredIdentityContext updatedIdentity, UserModel federatedUser) {
|
private void updateFederatedIdentity(BrokeredIdentityContext context, UserModel federatedUser) {
|
||||||
FederatedIdentityModel federatedIdentityModel = this.session.users().getFederatedIdentity(federatedUser, updatedIdentity.getIdpConfig().getAlias(), this.realmModel);
|
FederatedIdentityModel federatedIdentityModel = this.session.users().getFederatedIdentity(federatedUser, context.getIdpConfig().getAlias(), this.realmModel);
|
||||||
|
|
||||||
// Skip DB write if tokens are null or equal
|
// Skip DB write if tokens are null or equal
|
||||||
if (!ObjectUtil.isEqualOrNull(updatedIdentity.getToken(), federatedIdentityModel.getToken())) {
|
if (context.getIdpConfig().isStoreToken() && !ObjectUtil.isEqualOrNull(context.getToken(), federatedIdentityModel.getToken())) {
|
||||||
federatedIdentityModel.setToken(updatedIdentity.getToken());
|
federatedIdentityModel.setToken(context.getToken());
|
||||||
|
|
||||||
this.session.users().updateFederatedIdentity(this.realmModel, federatedUser, federatedIdentityModel);
|
this.session.users().updateFederatedIdentity(this.realmModel, federatedUser, federatedIdentityModel);
|
||||||
|
|
||||||
if (isDebugEnabled()) {
|
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);
|
context.getIdp().updateBrokeredUser(session, realmModel, federatedUser, context);
|
||||||
Set<IdentityProviderMapperModel> mappers = realmModel.getIdentityProviderMappersByAlias(updatedIdentity.getIdpConfig().getAlias());
|
Set<IdentityProviderMapperModel> mappers = realmModel.getIdentityProviderMappersByAlias(context.getIdpConfig().getAlias());
|
||||||
if (mappers != null) {
|
if (mappers != null) {
|
||||||
KeycloakSessionFactory sessionFactory = session.getKeycloakSessionFactory();
|
KeycloakSessionFactory sessionFactory = session.getKeycloakSessionFactory();
|
||||||
for (IdentityProviderMapperModel mapper : mappers) {
|
for (IdentityProviderMapperModel mapper : mappers) {
|
||||||
IdentityProviderMapper target = (IdentityProviderMapper)sessionFactory.getProviderFactory(IdentityProviderMapper.class, mapper.getIdentityProviderMapper());
|
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.");
|
throw new IdentityBrokerException("Configuration for identity provider [" + providerId + "] not found.");
|
||||||
}
|
}
|
||||||
|
|
||||||
private UserModel createUser(BrokeredIdentityContext updatedIdentity) {
|
private UserModel createUser(BrokeredIdentityContext context) {
|
||||||
FederatedIdentityModel federatedIdentityModel = new FederatedIdentityModel(updatedIdentity.getIdpConfig().getAlias(), updatedIdentity.getId(),
|
FederatedIdentityModel federatedIdentityModel = new FederatedIdentityModel(context.getIdpConfig().getAlias(), context.getId(),
|
||||||
updatedIdentity.getUsername(), updatedIdentity.getToken());
|
context.getUsername(), context.getToken());
|
||||||
// Check if no user already exists with this username or email
|
// Check if no user already exists with this username or email
|
||||||
UserModel existingUser = null;
|
UserModel existingUser = null;
|
||||||
|
|
||||||
if (updatedIdentity.getEmail() != null) {
|
if (context.getEmail() != null) {
|
||||||
existingUser = this.session.users().getUserByEmail(updatedIdentity.getEmail(), this.realmModel);
|
existingUser = this.session.users().getUserByEmail(context.getEmail(), this.realmModel);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (existingUser != null) {
|
if (existingUser != null) {
|
||||||
|
@ -499,13 +500,13 @@ public class IdentityBrokerService implements IdentityProvider.AuthenticationCal
|
||||||
throw new IdentityBrokerException(Messages.FEDERATED_IDENTITY_EMAIL_EXISTS);
|
throw new IdentityBrokerException(Messages.FEDERATED_IDENTITY_EMAIL_EXISTS);
|
||||||
}
|
}
|
||||||
|
|
||||||
String username = updatedIdentity.getUsername();
|
String username = context.getUsername();
|
||||||
if (this.realmModel.isRegistrationEmailAsUsername() && !Validation.isEmpty(updatedIdentity.getEmail())) {
|
if (this.realmModel.isRegistrationEmailAsUsername() && !Validation.isEmpty(context.getEmail())) {
|
||||||
username = updatedIdentity.getEmail();
|
username = context.getEmail();
|
||||||
} else if (username == null) {
|
} else if (username == null) {
|
||||||
username = updatedIdentity.getIdpConfig().getAlias() + "." + updatedIdentity.getId();
|
username = context.getIdpConfig().getAlias() + "." + context.getId();
|
||||||
} else {
|
} else {
|
||||||
username = updatedIdentity.getIdpConfig().getAlias() + "." + updatedIdentity.getUsername();
|
username = context.getIdpConfig().getAlias() + "." + context.getUsername();
|
||||||
}
|
}
|
||||||
if (username != null) {
|
if (username != null) {
|
||||||
username = username.trim();
|
username = username.trim();
|
||||||
|
@ -529,33 +530,36 @@ public class IdentityBrokerService implements IdentityProvider.AuthenticationCal
|
||||||
}
|
}
|
||||||
|
|
||||||
federatedUser.setEnabled(true);
|
federatedUser.setEnabled(true);
|
||||||
federatedUser.setEmail(updatedIdentity.getEmail());
|
federatedUser.setEmail(context.getEmail());
|
||||||
federatedUser.setFirstName(updatedIdentity.getFirstName());
|
federatedUser.setFirstName(context.getFirstName());
|
||||||
federatedUser.setLastName(updatedIdentity.getLastName());
|
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);
|
RoleModel readTokenRole = realmModel.getClientByClientId(Constants.BROKER_SERVICE_CLIENT_ID).getRole(READ_TOKEN_ROLE);
|
||||||
federatedUser.grantRole(readTokenRole);
|
federatedUser.grantRole(readTokenRole);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (context.getIdpConfig().isStoreToken()) {
|
||||||
|
federatedIdentityModel.setToken(context.getToken());
|
||||||
|
}
|
||||||
|
|
||||||
this.session.users().addFederatedIdentity(this.realmModel, federatedUser, federatedIdentityModel);
|
this.session.users().addFederatedIdentity(this.realmModel, federatedUser, federatedIdentityModel);
|
||||||
|
|
||||||
updatedIdentity.getIdp().importNewUser(session, realmModel, federatedUser, updatedIdentity);
|
context.getIdp().importNewUser(session, realmModel, federatedUser, context);
|
||||||
Set<IdentityProviderMapperModel> mappers = realmModel.getIdentityProviderMappersByAlias(updatedIdentity.getIdpConfig().getAlias());
|
Set<IdentityProviderMapperModel> mappers = realmModel.getIdentityProviderMappersByAlias(context.getIdpConfig().getAlias());
|
||||||
if (mappers != null) {
|
if (mappers != null) {
|
||||||
KeycloakSessionFactory sessionFactory = session.getKeycloakSessionFactory();
|
KeycloakSessionFactory sessionFactory = session.getKeycloakSessionFactory();
|
||||||
for (IdentityProviderMapperModel mapper : mappers) {
|
for (IdentityProviderMapperModel mapper : mappers) {
|
||||||
IdentityProviderMapper target = (IdentityProviderMapper)sessionFactory.getProviderFactory(IdentityProviderMapper.class, mapper.getIdentityProviderMapper());
|
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)
|
this.event.clone().user(federatedUser).event(EventType.REGISTER)
|
||||||
.detail(Details.IDENTITY_PROVIDER, federatedIdentityModel.getIdentityProvider())
|
.detail(Details.IDENTITY_PROVIDER, federatedIdentityModel.getIdentityProvider())
|
||||||
.detail(Details.IDENTITY_PROVIDER_USERNAME, updatedIdentity.getUsername())
|
.detail(Details.IDENTITY_PROVIDER_USERNAME, context.getUsername())
|
||||||
.removeDetail("auth_method")
|
.removeDetail("auth_method")
|
||||||
.success();
|
.success();
|
||||||
|
|
||||||
|
|
|
@ -181,7 +181,7 @@ public class IdentityProviderResource {
|
||||||
for (ProviderFactory factory : factories) {
|
for (ProviderFactory factory : factories) {
|
||||||
IdentityProviderMapper mapper = (IdentityProviderMapper)factory;
|
IdentityProviderMapper mapper = (IdentityProviderMapper)factory;
|
||||||
for (String type : mapper.getCompatibleProviders()) {
|
for (String type : mapper.getCompatibleProviders()) {
|
||||||
if (type.equals(identityProviderModel.getProviderId())) {
|
if (IdentityProviderMapper.ANY_PROVIDER.equals(type) || type.equals(identityProviderModel.getProviderId())) {
|
||||||
IdentityProviderMapperTypeRepresentation rep = new IdentityProviderMapperTypeRepresentation();
|
IdentityProviderMapperTypeRepresentation rep = new IdentityProviderMapperTypeRepresentation();
|
||||||
rep.setId(mapper.getId());
|
rep.setId(mapper.getId());
|
||||||
rep.setCategory(mapper.getDisplayCategory());
|
rep.setCategory(mapper.getDisplayCategory());
|
||||||
|
@ -198,7 +198,7 @@ public class IdentityProviderResource {
|
||||||
rep.getProperties().add(propRep);
|
rep.getProperties().add(propRep);
|
||||||
}
|
}
|
||||||
types.put(rep.getId(), rep);
|
types.put(rep.getId(), rep);
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -13,11 +13,26 @@
|
||||||
<name>Keycloak Tomcat 7 Integration TestSuite</name>
|
<name>Keycloak Tomcat 7 Integration TestSuite</name>
|
||||||
<properties>
|
<properties>
|
||||||
<!--<tomcat.version>8.0.14</tomcat.version>-->
|
<!--<tomcat.version>8.0.14</tomcat.version>-->
|
||||||
<tomcat.version>7.0.54</tomcat.version>
|
<tomcat.version>7.0.59</tomcat.version>
|
||||||
</properties>
|
</properties>
|
||||||
<description />
|
<description />
|
||||||
|
|
||||||
<dependencies>
|
<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>
|
<dependency>
|
||||||
<groupId>org.keycloak</groupId>
|
<groupId>org.keycloak</groupId>
|
||||||
<artifactId>keycloak-dependencies-server-all</artifactId>
|
<artifactId>keycloak-dependencies-server-all</artifactId>
|
||||||
|
@ -199,21 +214,6 @@
|
||||||
<scope>test</scope>
|
<scope>test</scope>
|
||||||
</dependency>
|
</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>
|
</dependencies>
|
||||||
<build>
|
<build>
|
||||||
|
|
|
@ -22,6 +22,7 @@
|
||||||
package org.keycloak.testsuite;
|
package org.keycloak.testsuite;
|
||||||
|
|
||||||
import org.apache.catalina.startup.Tomcat;
|
import org.apache.catalina.startup.Tomcat;
|
||||||
|
import org.apache.tomcat.util.http.mapper.Mapper;
|
||||||
import org.junit.AfterClass;
|
import org.junit.AfterClass;
|
||||||
import org.junit.BeforeClass;
|
import org.junit.BeforeClass;
|
||||||
import org.junit.ClassRule;
|
import org.junit.ClassRule;
|
||||||
|
|
Loading…
Reference in a new issue