KEYCLOAK-592 Display login form with error message if trying to login with social provider where email already exists
This commit is contained in:
parent
94be235a0f
commit
f95418dfc9
5 changed files with 117 additions and 61 deletions
|
@ -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.
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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()) {
|
||||
|
|
|
@ -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");
|
||||
|
|
|
@ -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();
|
||||
|
|
Loading…
Reference in a new issue