KEYCLOAK-592 Display login form with error message if trying to login with social provider where email already exists

This commit is contained in:
Stian Thorgersen 2014-08-12 12:06:13 +01:00
parent 94be235a0f
commit f95418dfc9
5 changed files with 117 additions and 61 deletions

View file

@ -51,6 +51,8 @@ successTotpRemoved=Google authenticator removed.
usernameExists=Username already exists
socialEmailExists=User with email already exists. Please login to account management to link the account.
loginTitle=Log in to
loginOauthTitle=Temporary access.
loginOauthTitleHtml=Temporary access requested. Login to grant access.

View file

@ -64,7 +64,7 @@ public class DefaultKeycloakTransactionManager implements KeycloakTransactionMan
exception = exception == null ? e : exception;
}
}
active = false;
if (exception != null) {
throw exception;
}
@ -87,6 +87,7 @@ public class DefaultKeycloakTransactionManager implements KeycloakTransactionMan
exception = exception != null ? e : exception;
}
}
active = false;
if (exception != null) {
throw exception;
}

View file

@ -31,10 +31,12 @@ import org.keycloak.audit.Details;
import org.keycloak.audit.Errors;
import org.keycloak.audit.EventType;
import org.keycloak.jose.jws.JWSInput;
import org.keycloak.login.LoginFormsProvider;
import org.keycloak.models.AccountRoles;
import org.keycloak.models.ClientModel;
import org.keycloak.models.Constants;
import org.keycloak.models.KeycloakSession;
import org.keycloak.models.ModelDuplicateException;
import org.keycloak.models.RealmModel;
import org.keycloak.models.SocialLinkModel;
import org.keycloak.models.UserModel;
@ -46,6 +48,7 @@ import org.keycloak.services.managers.RealmManager;
import org.keycloak.services.managers.TokenManager;
import org.keycloak.services.resources.flows.Flows;
import org.keycloak.services.resources.flows.OAuthFlows;
import org.keycloak.services.resources.flows.OAuthRedirect;
import org.keycloak.services.resources.flows.Urls;
import org.keycloak.social.AuthCallback;
import org.keycloak.social.SocialAccessDeniedException;
@ -67,6 +70,7 @@ import javax.ws.rs.core.Response;
import javax.ws.rs.core.UriBuilder;
import javax.ws.rs.core.UriInfo;
import java.io.IOException;
import java.net.URI;
import java.net.URISyntaxException;
import java.util.HashMap;
import java.util.List;
@ -182,6 +186,7 @@ public class SocialResource {
audit.detail(Details.USERNAME, socialUser.getId() + "@" + provider.getId());
try {
SocialLinkModel socialLink = new SocialLinkModel(provider.getId(), socialUser.getId(), socialUser.getUsername());
UserModel user = session.users().getUserBySocialLink(socialLink, realm);
@ -251,7 +256,15 @@ public class SocialResource {
UserSessionModel userSession = session.sessions().createUserSession(realm, user, username, clientConnection.getRemoteAddr(), authMethod, false);
audit.session(userSession);
return oauth.processAccessCode(scope, state, redirectUri, client, user, userSession, audit);
Response response = oauth.processAccessCode(scope, state, redirectUri, client, user, userSession, audit);
if (session.getTransaction().isActive()) {
session.getTransaction().commit();
}
return response;
} catch (ModelDuplicateException e) {
// Assume email is the duplicate as there's nothing else atm
return returnToLogin(realm, client, initialRequest.getAttributes(), "socialEmailExists");
}
}
@GET
@ -307,6 +320,17 @@ public class SocialResource {
}
}
private Response returnToLogin(RealmModel realm, ClientModel client, Map<String, String> attributes, String error) {
MultivaluedMap<String, String> q = new MultivaluedMapImpl<String, String>();
for (Entry<String, String> e : attributes.entrySet()) {
q.add(e.getKey(), e.getValue());
}
return Flows.forms(session, realm, client, uriInfo)
.setQueryParams(q)
.setError(error)
.createLogin();
}
private Map<String, String[]> getQueryParams() {
Map<String, String[]> queryParams = new HashMap<String, String[]>();
for (Entry<String, List<String>> e : uriInfo.getQueryParameters().entrySet()) {

View file

@ -106,6 +106,10 @@ public class UsersResource {
}
updateUserFromRep(user, rep);
if (session.getTransaction().isActive()) {
session.getTransaction().commit();
}
return Response.noContent().build();
} catch (ModelDuplicateException e) {
return Flows.errors().exists("User exists with same username or email");
@ -128,6 +132,10 @@ public class UsersResource {
UserModel user = session.users().addUser(realm, rep.getUsername());
updateUserFromRep(user, rep);
if (session.getTransaction().isActive()) {
session.getTransaction().commit();
}
return Response.created(uriInfo.getAbsolutePathBuilder().path(user.getUsername()).build()).build();
} catch (ModelDuplicateException e) {
return Flows.errors().exists("User exists with same username or email");

View file

@ -156,6 +156,27 @@ public class SocialLoginTest {
events.expectLogin().user(userId).detail(Details.USERNAME, "1@dummy").detail(Details.AUTH_METHOD, "social@dummy").assertEvent();
}
@Test
public void loginEmailExists() throws Exception {
loginSuccess();
oauth.openLogout();
events.clear();
loginPage.open();
loginPage.clickSocial("dummy");
driver.findElement(By.id("id")).sendKeys("2");
driver.findElement(By.id("username")).sendKeys("dummy-user2");
driver.findElement(By.id("firstname")).sendKeys("Bob2");
driver.findElement(By.id("lastname")).sendKeys("Builder2");
driver.findElement(By.id("email")).sendKeys("bob@builder.com");
driver.findElement(By.id("login")).click();
Assert.assertTrue(loginPage.isCurrent());
Assert.assertEquals("User with email already exists. Please login to account management to link the account.", loginPage.getError());
}
@Test
public void loginCancelled() throws Exception {
loginPage.open();