commit
770525a385
24 changed files with 422 additions and 24 deletions
|
@ -73,6 +73,11 @@ public abstract class AbstractIdentityProvider<C extends IdentityProviderModel>
|
|||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void preprocessFederatedIdentity(KeycloakSession session, RealmModel realm, BrokeredIdentityContext context) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void importNewUser(KeycloakSession session, RealmModel realm, UserModel user, BrokeredIdentityContext context) {
|
||||
|
||||
|
|
|
@ -18,8 +18,10 @@
|
|||
package org.keycloak.broker.provider;
|
||||
|
||||
import org.keycloak.Config;
|
||||
import org.keycloak.models.IdentityProviderModel;
|
||||
import org.keycloak.models.KeycloakSession;
|
||||
import org.keycloak.models.KeycloakSessionFactory;
|
||||
import org.keycloak.models.RealmModel;
|
||||
|
||||
import java.io.InputStream;
|
||||
import java.util.HashMap;
|
||||
|
|
|
@ -1,8 +1,10 @@
|
|||
package org.keycloak.broker.provider;
|
||||
|
||||
import org.keycloak.broker.provider.IdentityProviderMapper;
|
||||
import org.keycloak.models.IdentityProviderMapperModel;
|
||||
import org.keycloak.models.KeycloakSession;
|
||||
import org.keycloak.models.KeycloakSessionFactory;
|
||||
import org.keycloak.models.RealmModel;
|
||||
|
||||
/**
|
||||
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
|
||||
|
@ -28,4 +30,9 @@ public abstract class AbstractIdentityProviderMapper implements IdentityProvider
|
|||
public void postInit(KeycloakSessionFactory factory) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void preprocessFederatedIdentity(KeycloakSession session, RealmModel realm, IdentityProviderMapperModel mapperModel, BrokeredIdentityContext context) {
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
@ -32,6 +32,7 @@ public class BrokeredIdentityContext {
|
|||
|
||||
private String id;
|
||||
private String username;
|
||||
private String modelUsername;
|
||||
private String email;
|
||||
private String firstName;
|
||||
private String lastName;
|
||||
|
@ -59,6 +60,11 @@ public class BrokeredIdentityContext {
|
|||
this.id = id;
|
||||
}
|
||||
|
||||
/**
|
||||
* Username in remote idp
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public String getUsername() {
|
||||
return username;
|
||||
}
|
||||
|
@ -67,6 +73,19 @@ public class BrokeredIdentityContext {
|
|||
this.username = username;
|
||||
}
|
||||
|
||||
/**
|
||||
* username to store in UserModel
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public String getModelUsername() {
|
||||
return modelUsername;
|
||||
}
|
||||
|
||||
public void setModelUsername(String modelUsername) {
|
||||
this.modelUsername = modelUsername;
|
||||
}
|
||||
|
||||
public String getEmail() {
|
||||
return email;
|
||||
}
|
||||
|
|
|
@ -20,6 +20,7 @@ package org.keycloak.broker.provider;
|
|||
import org.keycloak.events.EventBuilder;
|
||||
import org.keycloak.models.ClientSessionModel;
|
||||
import org.keycloak.models.FederatedIdentityModel;
|
||||
import org.keycloak.models.IdentityProviderMapperModel;
|
||||
import org.keycloak.models.IdentityProviderModel;
|
||||
import org.keycloak.models.KeycloakSession;
|
||||
import org.keycloak.models.RealmModel;
|
||||
|
@ -46,6 +47,8 @@ public interface IdentityProvider<C extends IdentityProviderModel> extends Provi
|
|||
public Response authenticated(BrokeredIdentityContext context);
|
||||
}
|
||||
|
||||
|
||||
void preprocessFederatedIdentity(KeycloakSession session, RealmModel realm, BrokeredIdentityContext context);
|
||||
void attachUserSession(UserSessionModel userSession, ClientSessionModel clientSession, BrokeredIdentityContext context);
|
||||
void importNewUser(KeycloakSession session, RealmModel realm, UserModel user, BrokeredIdentityContext context);
|
||||
void updateBrokeredUser(KeycloakSession session, RealmModel realm, UserModel user, BrokeredIdentityContext context);
|
||||
|
|
2
broker/core/src/main/java/org/keycloak/broker/provider/IdentityProviderFactory.java
Normal file → Executable file
2
broker/core/src/main/java/org/keycloak/broker/provider/IdentityProviderFactory.java
Normal file → Executable file
|
@ -18,6 +18,8 @@
|
|||
package org.keycloak.broker.provider;
|
||||
|
||||
import org.keycloak.models.IdentityProviderModel;
|
||||
import org.keycloak.models.KeycloakSession;
|
||||
import org.keycloak.models.RealmModel;
|
||||
import org.keycloak.provider.ProviderFactory;
|
||||
|
||||
import java.io.InputStream;
|
||||
|
|
|
@ -19,7 +19,37 @@ public interface IdentityProviderMapper extends Provider, ProviderFactory<Identi
|
|||
String getDisplayCategory();
|
||||
String getDisplayType();
|
||||
|
||||
/**
|
||||
* Called to determine what keycloak username and email to use to process the login request from the external IDP
|
||||
* Usually used to map BrokeredIdentityContet.username or email.
|
||||
*
|
||||
* @param session
|
||||
* @param realm
|
||||
* @param mapperModel
|
||||
* @param context
|
||||
*/
|
||||
void preprocessFederatedIdentity(KeycloakSession session, RealmModel realm, IdentityProviderMapperModel mapperModel, BrokeredIdentityContext context);
|
||||
|
||||
/**
|
||||
* Called after UserModel is created for first time for this user.
|
||||
*
|
||||
* @param session
|
||||
* @param realm
|
||||
* @param user
|
||||
* @param mapperModel
|
||||
* @param context
|
||||
*/
|
||||
void importNewUser(KeycloakSession session, RealmModel realm, UserModel user, IdentityProviderMapperModel mapperModel, BrokeredIdentityContext context);
|
||||
|
||||
/**
|
||||
* Called when this user has logged in before and has already been imported.
|
||||
*
|
||||
* @param session
|
||||
* @param realm
|
||||
* @param user
|
||||
* @param mapperModel
|
||||
* @param context
|
||||
*/
|
||||
void updateBrokeredUser(KeycloakSession session, RealmModel realm, UserModel user, IdentityProviderMapperModel mapperModel, BrokeredIdentityContext context);
|
||||
|
||||
|
||||
|
|
|
@ -17,10 +17,15 @@
|
|||
*/
|
||||
package org.keycloak.broker.oidc;
|
||||
|
||||
import org.keycloak.broker.oidc.mappers.UsernameTemplateMapper;
|
||||
import org.keycloak.broker.provider.AbstractIdentityProviderFactory;
|
||||
import org.keycloak.models.IdentityProviderMapperModel;
|
||||
import org.keycloak.models.IdentityProviderModel;
|
||||
import org.keycloak.models.KeycloakSession;
|
||||
import org.keycloak.models.RealmModel;
|
||||
|
||||
import java.io.InputStream;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
|
@ -50,4 +55,5 @@ public class KeycloakOIDCIdentityProviderFactory extends AbstractIdentityProvide
|
|||
return OIDCIdentityProviderFactory.parseOIDCConfig(inputStream);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -17,11 +17,15 @@
|
|||
*/
|
||||
package org.keycloak.broker.oidc;
|
||||
|
||||
import org.keycloak.broker.oidc.mappers.UsernameTemplateMapper;
|
||||
import org.keycloak.broker.provider.util.SimpleHttp;
|
||||
import org.keycloak.broker.provider.AbstractIdentityProviderFactory;
|
||||
import org.keycloak.jose.jwk.JWK;
|
||||
import org.keycloak.jose.jwk.JWKParser;
|
||||
import org.keycloak.models.IdentityProviderMapperModel;
|
||||
import org.keycloak.models.IdentityProviderModel;
|
||||
import org.keycloak.models.KeycloakSession;
|
||||
import org.keycloak.models.RealmModel;
|
||||
import org.keycloak.models.utils.KeycloakModelUtils;
|
||||
import org.keycloak.protocol.oidc.representations.JSONWebKeySet;
|
||||
import org.keycloak.protocol.oidc.representations.OIDCConfigurationRepresentation;
|
||||
|
@ -30,6 +34,7 @@ import org.keycloak.util.JsonSerialization;
|
|||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.security.PublicKey;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
|
@ -89,7 +94,7 @@ public class OIDCIdentityProviderFactory extends AbstractIdentityProviderFactory
|
|||
|
||||
}
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException("F ailed to query JWKSet from: " + uri, e);
|
||||
throw new RuntimeException("Failed to query JWKSet from: " + uri, e);
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -99,4 +104,5 @@ public class OIDCIdentityProviderFactory extends AbstractIdentityProviderFactory
|
|||
protected static boolean keyTypeSupported(String type) {
|
||||
return type != null && type.equals("RSA");
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -33,8 +33,12 @@ public abstract class AbstractClaimMapper extends AbstractIdentityProviderMapper
|
|||
return null;
|
||||
}
|
||||
|
||||
protected Object getClaimValue(IdentityProviderMapperModel mapperModel, BrokeredIdentityContext context) {
|
||||
public static Object getClaimValue(IdentityProviderMapperModel mapperModel, BrokeredIdentityContext context) {
|
||||
String claim = mapperModel.getConfig().get(CLAIM);
|
||||
return getClaimValue(context, claim);
|
||||
}
|
||||
|
||||
public static Object getClaimValue(BrokeredIdentityContext context, String claim) {
|
||||
{ // search access token
|
||||
JsonWebToken token = (JsonWebToken)context.getContextData().get(KeycloakOIDCIdentityProvider.VALIDATED_ACCESS_TOKEN);
|
||||
if (token != null) {
|
||||
|
|
|
@ -0,0 +1,109 @@
|
|||
package org.keycloak.broker.oidc.mappers;
|
||||
|
||||
import org.keycloak.broker.oidc.KeycloakOIDCIdentityProviderFactory;
|
||||
import org.keycloak.broker.oidc.OIDCIdentityProviderFactory;
|
||||
import org.keycloak.broker.provider.BrokeredIdentityContext;
|
||||
import org.keycloak.models.IdentityProviderMapperModel;
|
||||
import org.keycloak.models.KeycloakSession;
|
||||
import org.keycloak.models.RealmModel;
|
||||
import org.keycloak.models.UserModel;
|
||||
import org.keycloak.models.utils.KeycloakModelUtils;
|
||||
import org.keycloak.provider.ProviderConfigProperty;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
/**
|
||||
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
|
||||
* @version $Revision: 1 $
|
||||
*/
|
||||
public class UsernameTemplateMapper extends AbstractClaimMapper {
|
||||
|
||||
public static final String[] COMPATIBLE_PROVIDERS = {KeycloakOIDCIdentityProviderFactory.PROVIDER_ID, OIDCIdentityProviderFactory.PROVIDER_ID};
|
||||
|
||||
private static final List<ProviderConfigProperty> configProperties = new ArrayList<ProviderConfigProperty>();
|
||||
|
||||
public static final String TEMPLATE = "template";
|
||||
|
||||
static {
|
||||
ProviderConfigProperty property;
|
||||
property = new ProviderConfigProperty();
|
||||
property.setName(TEMPLATE);
|
||||
property.setLabel("Template");
|
||||
property.setHelpText("Template to use to format the username to import. Substitutions are enclosed in ${}. For example: '${ALIAS}.${CLAIM.sub}'. ALIAS is the provider alias. CLAIM.<NAME> references an ID or Access token claim.");
|
||||
property.setType(ProviderConfigProperty.STRING_TYPE);
|
||||
property.setDefaultValue("${ALIAS}.${CLAIM.preferred_username}");
|
||||
configProperties.add(property);
|
||||
}
|
||||
|
||||
public static final String PROVIDER_ID = "oidc-username-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 "Preprocessor";
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getDisplayType() {
|
||||
return "Username Template Importer";
|
||||
}
|
||||
|
||||
@Override
|
||||
public void importNewUser(KeycloakSession session, RealmModel realm, UserModel user, IdentityProviderMapperModel mapperModel, BrokeredIdentityContext context) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateBrokeredUser(KeycloakSession session, RealmModel realm, UserModel user, IdentityProviderMapperModel mapperModel, BrokeredIdentityContext context) {
|
||||
}
|
||||
|
||||
static Pattern substitution = Pattern.compile("\\$\\{([^}]+)\\}");
|
||||
|
||||
@Override
|
||||
public void preprocessFederatedIdentity(KeycloakSession session, RealmModel realm, IdentityProviderMapperModel mapperModel, BrokeredIdentityContext context) {
|
||||
String template = mapperModel.getConfig().get(TEMPLATE);
|
||||
Matcher m = substitution.matcher(template);
|
||||
StringBuffer sb = new StringBuffer();
|
||||
while (m.find()) {
|
||||
String variable = m.group(1);
|
||||
if (variable.equals("ALIAS")) {
|
||||
m.appendReplacement(sb, context.getIdpConfig().getAlias());
|
||||
} else if (variable.equals("UUID")) {
|
||||
m.appendReplacement(sb, KeycloakModelUtils.generateId());
|
||||
} else if (variable.startsWith("CLAIM.")) {
|
||||
String name = variable.substring("CLAIM.".length());
|
||||
Object value = AbstractClaimMapper.getClaimValue(context, name);
|
||||
if (value == null) value = "";
|
||||
m.appendReplacement(sb, value.toString());
|
||||
} else {
|
||||
m.appendReplacement(sb, m.group(1));
|
||||
}
|
||||
|
||||
}
|
||||
m.appendTail(sb);
|
||||
String username = sb.toString();
|
||||
context.setModelUsername(username);
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getHelpText() {
|
||||
return "Format the username to import.";
|
||||
}
|
||||
}
|
|
@ -1,3 +1,4 @@
|
|||
org.keycloak.broker.oidc.mappers.ClaimToRoleMapper
|
||||
org.keycloak.broker.oidc.mappers.ExternalKeycloakRoleToRoleMapper
|
||||
org.keycloak.broker.oidc.mappers.UserAttributeMapper
|
||||
org.keycloak.broker.oidc.mappers.UserAttributeMapper
|
||||
org.keycloak.broker.oidc.mappers.UsernameTemplateMapper
|
|
@ -18,13 +18,17 @@
|
|||
package org.keycloak.broker.saml;
|
||||
|
||||
import org.keycloak.broker.provider.AbstractIdentityProviderFactory;
|
||||
import org.keycloak.broker.saml.mappers.UsernameTemplateMapper;
|
||||
import org.keycloak.dom.saml.v2.metadata.EndpointType;
|
||||
import org.keycloak.dom.saml.v2.metadata.EntitiesDescriptorType;
|
||||
import org.keycloak.dom.saml.v2.metadata.EntityDescriptorType;
|
||||
import org.keycloak.dom.saml.v2.metadata.IDPSSODescriptorType;
|
||||
import org.keycloak.dom.saml.v2.metadata.KeyDescriptorType;
|
||||
import org.keycloak.dom.saml.v2.metadata.KeyTypes;
|
||||
import org.keycloak.models.IdentityProviderMapperModel;
|
||||
import org.keycloak.models.IdentityProviderModel;
|
||||
import org.keycloak.models.KeycloakSession;
|
||||
import org.keycloak.models.RealmModel;
|
||||
import org.keycloak.saml.common.constants.JBossSAMLURIConstants;
|
||||
import org.keycloak.saml.common.exceptions.ParsingException;
|
||||
import org.keycloak.saml.common.util.DocumentUtil;
|
||||
|
@ -150,4 +154,5 @@ public class SAMLIdentityProviderFactory extends AbstractIdentityProviderFactory
|
|||
public String getId() {
|
||||
return PROVIDER_ID;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -0,0 +1,133 @@
|
|||
package org.keycloak.broker.saml.mappers;
|
||||
|
||||
import org.keycloak.broker.provider.AbstractIdentityProviderMapper;
|
||||
import org.keycloak.broker.provider.BrokeredIdentityContext;
|
||||
import org.keycloak.broker.saml.SAMLEndpoint;
|
||||
import org.keycloak.broker.saml.SAMLIdentityProviderFactory;
|
||||
import org.keycloak.dom.saml.v2.assertion.AssertionType;
|
||||
import org.keycloak.dom.saml.v2.assertion.AttributeStatementType;
|
||||
import org.keycloak.dom.saml.v2.assertion.AttributeType;
|
||||
import org.keycloak.dom.saml.v2.assertion.NameIDType;
|
||||
import org.keycloak.dom.saml.v2.assertion.SubjectType;
|
||||
import org.keycloak.models.IdentityProviderMapperModel;
|
||||
import org.keycloak.models.KeycloakSession;
|
||||
import org.keycloak.models.RealmModel;
|
||||
import org.keycloak.models.UserModel;
|
||||
import org.keycloak.models.utils.KeycloakModelUtils;
|
||||
import org.keycloak.provider.ProviderConfigProperty;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
/**
|
||||
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
|
||||
* @version $Revision: 1 $
|
||||
*/
|
||||
public class UsernameTemplateMapper extends AbstractIdentityProviderMapper {
|
||||
|
||||
public static final String[] COMPATIBLE_PROVIDERS = {SAMLIdentityProviderFactory.PROVIDER_ID};
|
||||
|
||||
private static final List<ProviderConfigProperty> configProperties = new ArrayList<ProviderConfigProperty>();
|
||||
|
||||
public static final String TEMPLATE = "template";
|
||||
|
||||
static {
|
||||
ProviderConfigProperty property;
|
||||
property = new ProviderConfigProperty();
|
||||
property.setName(TEMPLATE);
|
||||
property.setLabel("Template");
|
||||
property.setHelpText("Template to use to format the username to import. Substitutions are enclosed in ${}. For example: '${ALIAS}.${NAMEID}'. ALIAS is the provider alias. NAMEID is that SAML name id assertion. ATTRIBUTE.<NAME> references a SAML attribute where name is the attribute name or friendly name.");
|
||||
property.setType(ProviderConfigProperty.STRING_TYPE);
|
||||
property.setDefaultValue("${ALIAS}.${NAMEID}");
|
||||
configProperties.add(property);
|
||||
}
|
||||
|
||||
public static final String PROVIDER_ID = "saml-username-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 "Preprocessor";
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getDisplayType() {
|
||||
return "Username Template Importer";
|
||||
}
|
||||
|
||||
@Override
|
||||
public void importNewUser(KeycloakSession session, RealmModel realm, UserModel user, IdentityProviderMapperModel mapperModel, BrokeredIdentityContext context) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateBrokeredUser(KeycloakSession session, RealmModel realm, UserModel user, IdentityProviderMapperModel mapperModel, BrokeredIdentityContext context) {
|
||||
|
||||
}
|
||||
static Pattern substitution = Pattern.compile("\\$\\{([^}]+)\\}");
|
||||
|
||||
@Override
|
||||
public void preprocessFederatedIdentity(KeycloakSession session, RealmModel realm, IdentityProviderMapperModel mapperModel, BrokeredIdentityContext context) {
|
||||
AssertionType assertion = (AssertionType)context.getContextData().get(SAMLEndpoint.SAML_ASSERTION);
|
||||
String template = mapperModel.getConfig().get(TEMPLATE);
|
||||
Matcher m = substitution.matcher(template);
|
||||
StringBuffer sb = new StringBuffer();
|
||||
while (m.find()) {
|
||||
String variable = m.group(1);
|
||||
if (variable.equals("ALIAS")) {
|
||||
m.appendReplacement(sb, context.getIdpConfig().getAlias());
|
||||
} else if (variable.equals("UUID")) {
|
||||
m.appendReplacement(sb, KeycloakModelUtils.generateId());
|
||||
} else if (variable.equals("NAMEID")) {
|
||||
SubjectType subject = assertion.getSubject();
|
||||
SubjectType.STSubType subType = subject.getSubType();
|
||||
NameIDType subjectNameID = (NameIDType) subType.getBaseID();
|
||||
m.appendReplacement(sb, subjectNameID.getValue());
|
||||
} else if (variable.startsWith("ATTRIBUTE.")) {
|
||||
String name = variable.substring("ATTRIBUTE.".length());
|
||||
String value = "";
|
||||
for (AttributeStatementType statement : assertion.getAttributeStatements()) {
|
||||
for (AttributeStatementType.ASTChoiceType choice : statement.getAttributes()) {
|
||||
AttributeType attr = choice.getAttribute();
|
||||
if (name.equals(attr.getName()) || name.equals(attr.getFriendlyName())) {
|
||||
List<Object> attributeValue = attr.getAttributeValue();
|
||||
if (attributeValue != null && !attributeValue.isEmpty()) {
|
||||
value = attributeValue.get(0).toString();
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
m.appendReplacement(sb, value);
|
||||
} else {
|
||||
m.appendReplacement(sb, m.group(1));
|
||||
}
|
||||
|
||||
}
|
||||
m.appendTail(sb);
|
||||
context.setModelUsername(sb.toString());
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getHelpText() {
|
||||
return "Format the username to import.";
|
||||
}
|
||||
|
||||
}
|
|
@ -1,2 +1,3 @@
|
|||
org.keycloak.broker.saml.mappers.AttributeToRoleMapper
|
||||
org.keycloak.broker.saml.mappers.UserAttributeMapper
|
||||
org.keycloak.broker.saml.mappers.UserAttributeMapper
|
||||
org.keycloak.broker.saml.mappers.UsernameTemplateMapper
|
|
@ -4,6 +4,7 @@ import java.io.IOException;
|
|||
import java.io.InputStream;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
import org.codehaus.jackson.annotate.JsonAnyGetter;
|
||||
|
@ -90,4 +91,21 @@ public class JsonParserTest {
|
|||
Assert.assertEquals(100, config.getCorsMaxAge());
|
||||
Assert.assertEquals(200, config.getConnectionPoolSize());
|
||||
}
|
||||
|
||||
static Pattern substitution = Pattern.compile("\\$\\{([^}]+)\\}");
|
||||
|
||||
@Test
|
||||
public void testSub() {
|
||||
String pattern = "${ALIAS}.${CRAP}";
|
||||
Matcher m = substitution.matcher(pattern);
|
||||
StringBuffer sb = new StringBuffer();
|
||||
while (m.find()) {
|
||||
System.out.println("GROUP: " + m.group(1));
|
||||
m.appendReplacement(sb, m.group(1));
|
||||
|
||||
}
|
||||
m.appendTail(sb);
|
||||
System.out.println(sb.toString());
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -86,12 +86,21 @@ public class JpaUserProvider implements UserProvider {
|
|||
}
|
||||
|
||||
private void removeUser(UserEntity user) {
|
||||
String id = user.getId();
|
||||
em.createNamedQuery("deleteUserRoleMappingsByUser").setParameter("user", user).executeUpdate();
|
||||
em.createNamedQuery("deleteFederatedIdentityByUser").setParameter("user", user).executeUpdate();
|
||||
em.createNamedQuery("deleteUserConsentRolesByUser").setParameter("user", user).executeUpdate();
|
||||
em.createNamedQuery("deleteUserConsentProtMappersByUser").setParameter("user", user).executeUpdate();
|
||||
em.createNamedQuery("deleteUserConsentsByUser").setParameter("user", user).executeUpdate();
|
||||
em.remove(user);
|
||||
em.flush();
|
||||
// not sure why i have to do a clear() here. I was getting some messed up errors that Hibernate couldn't
|
||||
// un-delete the UserEntity.
|
||||
em.clear();
|
||||
user = em.find(UserEntity.class, id);
|
||||
if (user != null) {
|
||||
em.remove(user);
|
||||
}
|
||||
em.flush();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -186,4 +186,21 @@ public class UserEntity {
|
|||
public void setFederationLink(String federationLink) {
|
||||
this.federationLink = federationLink;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) return true;
|
||||
if (o == null || getClass() != o.getClass()) return false;
|
||||
|
||||
UserEntity that = (UserEntity) o;
|
||||
|
||||
if (!id.equals(that.id)) return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return id.hashCode();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -17,11 +17,11 @@ public class UserManager {
|
|||
}
|
||||
|
||||
public boolean removeUser(RealmModel realm, UserModel user) {
|
||||
UserSessionProvider sessions = session.sessions();
|
||||
if (sessions != null) {
|
||||
sessions.onUserRemoved(realm, user);
|
||||
}
|
||||
if (session.users().removeUser(realm, user)) {
|
||||
UserSessionProvider sessions = session.sessions();
|
||||
if (sessions != null) {
|
||||
sessions.onUserRemoved(realm, user);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
|
|
|
@ -44,6 +44,7 @@ import org.keycloak.models.RealmModel;
|
|||
import org.keycloak.models.RoleModel;
|
||||
import org.keycloak.models.UserModel;
|
||||
import org.keycloak.models.UserSessionModel;
|
||||
import org.keycloak.models.utils.KeycloakModelUtils;
|
||||
import org.keycloak.protocol.oidc.TokenManager;
|
||||
import org.keycloak.provider.ProviderFactory;
|
||||
import org.keycloak.representations.AccessToken;
|
||||
|
@ -249,6 +250,16 @@ public class IdentityBrokerService implements IdentityProvider.AuthenticationCal
|
|||
}
|
||||
|
||||
ClientSessionModel clientSession = clientCode.getClientSession();
|
||||
context.getIdp().preprocessFederatedIdentity(session, realmModel, 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.preprocessFederatedIdentity(session, realmModel, mapper, context);
|
||||
}
|
||||
}
|
||||
|
||||
FederatedIdentityModel federatedIdentityModel = new FederatedIdentityModel(providerId, context.getId(),
|
||||
context.getUsername(), context.getToken());
|
||||
|
||||
|
@ -492,18 +503,24 @@ public class IdentityBrokerService implements IdentityProvider.AuthenticationCal
|
|||
fireErrorEvent(Errors.FEDERATED_IDENTITY_EMAIL_EXISTS);
|
||||
throw new IdentityBrokerException(Messages.FEDERATED_IDENTITY_EMAIL_EXISTS);
|
||||
}
|
||||
String username = context.getModelUsername();
|
||||
if (username == null) {
|
||||
username = context.getUsername();
|
||||
if (this.realmModel.isRegistrationEmailAsUsername() && !Validation.isEmpty(context.getEmail())) {
|
||||
username = context.getEmail();
|
||||
} else if (username == null) {
|
||||
username = context.getIdpConfig().getAlias() + "." + context.getId();
|
||||
} else {
|
||||
username = context.getIdpConfig().getAlias() + "." + context.getUsername();
|
||||
}
|
||||
}
|
||||
if (username == null) {
|
||||
LOGGER.warn("Unknown username");
|
||||
fireErrorEvent(Errors.FEDERATED_IDENTITY_USERNAME_EXISTS);
|
||||
throw new IdentityBrokerException(Messages.FEDERATED_IDENTITY_USERNAME_EXISTS);
|
||||
|
||||
String username = context.getUsername();
|
||||
if (this.realmModel.isRegistrationEmailAsUsername() && !Validation.isEmpty(context.getEmail())) {
|
||||
username = context.getEmail();
|
||||
} else if (username == null) {
|
||||
username = context.getIdpConfig().getAlias() + "." + context.getId();
|
||||
} else {
|
||||
username = context.getIdpConfig().getAlias() + "." + context.getUsername();
|
||||
}
|
||||
if (username != null) {
|
||||
username = username.trim();
|
||||
}
|
||||
username = username.trim();
|
||||
|
||||
existingUser = this.session.users().getUserByUsername(username, this.realmModel);
|
||||
|
||||
|
|
|
@ -129,7 +129,8 @@ public class IdentityProvidersResource {
|
|||
this.auth.requireManage();
|
||||
|
||||
try {
|
||||
this.realm.addIdentityProvider(RepresentationToModel.toModel(representation));
|
||||
IdentityProviderModel identityProvider = RepresentationToModel.toModel(representation);
|
||||
this.realm.addIdentityProvider(identityProvider);
|
||||
|
||||
return Response.created(uriInfo.getAbsolutePathBuilder().path(representation.getProviderId()).build()).build();
|
||||
} catch (ModelDuplicateException e) {
|
||||
|
|
|
@ -33,7 +33,8 @@ public class GitHubIdentityProvider extends AbstractOAuth2IdentityProvider imple
|
|||
|
||||
BrokeredIdentityContext user = new BrokeredIdentityContext(getJsonProperty(profile, "id"));
|
||||
|
||||
user.setUsername(getJsonProperty(profile, "login"));
|
||||
String username = getJsonProperty(profile, "login");
|
||||
user.setUsername(username);
|
||||
user.setName(getJsonProperty(profile, "name"));
|
||||
user.setEmail(getJsonProperty(profile, "email"));
|
||||
user.setIdpConfig(getConfig());
|
||||
|
|
|
@ -60,7 +60,8 @@ public class LinkedInIdentityProvider extends AbstractOAuth2IdentityProvider imp
|
|||
|
||||
BrokeredIdentityContext user = new BrokeredIdentityContext(getJsonProperty(profile, "id"));
|
||||
|
||||
user.setUsername(extractUsernameFromProfileURL(getJsonProperty(profile, "publicProfileUrl")));
|
||||
String username = extractUsernameFromProfileURL(getJsonProperty(profile, "publicProfileUrl"));
|
||||
user.setUsername(username);
|
||||
user.setName(getJsonProperty(profile, "formattedName"));
|
||||
user.setEmail(getJsonProperty(profile, "emailAddress"));
|
||||
user.setIdpConfig(getConfig());
|
||||
|
|
|
@ -69,7 +69,8 @@ public class StackoverflowIdentityProvider extends AbstractOAuth2IdentityProvide
|
|||
|
||||
BrokeredIdentityContext user = new BrokeredIdentityContext(getJsonProperty(profile, "user_id"));
|
||||
|
||||
user.setUsername(extractUsernameFromProfileURL(getJsonProperty(profile, "link")));
|
||||
String username = extractUsernameFromProfileURL(getJsonProperty(profile, "link"));
|
||||
user.setUsername(username);
|
||||
user.setName(unescapeHtml3(getJsonProperty(profile, "display_name")));
|
||||
// email is not provided
|
||||
// user.setEmail(getJsonProperty(profile, "email"));
|
||||
|
|
Loading…
Reference in a new issue