Merge pull request #1237 from patriot1burke/master

username mapper
This commit is contained in:
Bill Burke 2015-05-08 20:53:05 -04:00
commit 770525a385
24 changed files with 422 additions and 24 deletions

View file

@ -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) {

View file

@ -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;

View file

@ -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) {
}
}

View file

@ -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;
}

View file

@ -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);

View 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;

View file

@ -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);

View file

@ -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);
}
}
}

View file

@ -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");
}
}

View file

@ -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) {

View file

@ -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.";
}
}

View file

@ -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

View file

@ -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;
}
}

View file

@ -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.";
}
}

View file

@ -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

View file

@ -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());
}
}

View file

@ -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

View file

@ -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();
}
}

View file

@ -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;

View file

@ -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);

View file

@ -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) {

View file

@ -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());

View file

@ -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());

View file

@ -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"));