Details
diff --git a/forms/common-themes/src/main/resources/theme/login/base/login.ftl b/forms/common-themes/src/main/resources/theme/login/base/login.ftl
index a1a3b23..e46cf95 100755
--- a/forms/common-themes/src/main/resources/theme/login/base/login.ftl
+++ b/forms/common-themes/src/main/resources/theme/login/base/login.ftl
@@ -17,7 +17,7 @@
<form id="kc-form-login" class="${properties.kcFormClass!}" action="${url.loginAction}" method="post">
<div class="${properties.kcFormGroupClass!}">
<div class="${properties.kcLabelWrapperClass!}">
- <label for="username" class="${properties.kcLabelClass!}">${rb.usernameOrEmail}</label>
+ <label for="username" class="${properties.kcLabelClass!}"><#if !realm.registrationEmailAsUsername>${rb.usernameOrEmail}<#else>${rb.email}</#if></label>
</div>
<div class="${properties.kcInputWrapperClass!}">
diff --git a/services/src/main/java/org/keycloak/services/resources/IdentityBrokerService.java b/services/src/main/java/org/keycloak/services/resources/IdentityBrokerService.java
index 1b10621..c95b618 100755
--- a/services/src/main/java/org/keycloak/services/resources/IdentityBrokerService.java
+++ b/services/src/main/java/org/keycloak/services/resources/IdentityBrokerService.java
@@ -540,12 +540,15 @@ public class IdentityBrokerService {
String username = updatedIdentity.getUsername();
if (this.realmModel.isRegistrationEmailAsUsername()) {
- username = updatedIdentity.getEmail();
- if (username == null) {
- fireErrorEvent(Errors.FEDERATED_IDENTITY_REGISTRATION_EMAIL_MISSING);
- throw new IdentityBrokerException("federatedIdentityRegistrationEmailMissing");
- // TODO KEYCLOAK-1053 (ask user to enter email address) should be implemented instead of plain exception as better solution for this case
- }
+ username = updatedIdentity.getEmail();
+ if (username == null || username.trim().length() == 0) {
+ fireErrorEvent(Errors.FEDERATED_IDENTITY_REGISTRATION_EMAIL_MISSING);
+ throw new IdentityBrokerException("federatedIdentityRegistrationEmailMissing");
+ // TODO KEYCLOAK-1053 (ask user to enter email address) should be implemented instead of plain exception as better solution for this case
+ }
+ username = username.trim();
+ } else if (username != null) {
+ username = username.trim();
}
existingUser = this.session.users().getUserByUsername(username, this.realmModel);
diff --git a/testsuite/integration/src/test/java/org/keycloak/testsuite/admin/RealmTest.java b/testsuite/integration/src/test/java/org/keycloak/testsuite/admin/RealmTest.java
index 5dd37bc..564cb85 100644
--- a/testsuite/integration/src/test/java/org/keycloak/testsuite/admin/RealmTest.java
+++ b/testsuite/integration/src/test/java/org/keycloak/testsuite/admin/RealmTest.java
@@ -60,10 +60,13 @@ public class RealmTest extends AbstractClientTest {
@Test
public void updateRealm() {
+ // first change
RealmRepresentation rep = realm.toRepresentation();
rep.setSsoSessionIdleTimeout(123);
rep.setSsoSessionMaxLifespan(12);
rep.setAccessCodeLifespanLogin(1234);
+ rep.setRegistrationAllowed(true);
+ rep.setRegistrationEmailAsUsername(true);
realm.update(rep);
@@ -72,6 +75,18 @@ public class RealmTest extends AbstractClientTest {
assertEquals(123, rep.getSsoSessionIdleTimeout().intValue());
assertEquals(12, rep.getSsoSessionMaxLifespan().intValue());
assertEquals(1234, rep.getAccessCodeLifespanLogin().intValue());
+ assertEquals(Boolean.TRUE, rep.isRegistrationAllowed());
+ assertEquals(Boolean.TRUE, rep.isRegistrationEmailAsUsername());
+
+ // second change
+ rep.setRegistrationAllowed(false);
+ rep.setRegistrationEmailAsUsername(false);
+
+ realm.update(rep);
+
+ rep = realm.toRepresentation();
+ assertEquals(Boolean.FALSE, rep.isRegistrationAllowed());
+ assertEquals(Boolean.FALSE, rep.isRegistrationEmailAsUsername());
}
@Test
diff --git a/testsuite/integration/src/test/java/org/keycloak/testsuite/broker/AbstractIdentityProviderTest.java b/testsuite/integration/src/test/java/org/keycloak/testsuite/broker/AbstractIdentityProviderTest.java
index dd034c1..b1ae4cb 100644
--- a/testsuite/integration/src/test/java/org/keycloak/testsuite/broker/AbstractIdentityProviderTest.java
+++ b/testsuite/integration/src/test/java/org/keycloak/testsuite/broker/AbstractIdentityProviderTest.java
@@ -59,6 +59,7 @@ import javax.ws.rs.core.HttpHeaders;
import javax.ws.rs.core.Response;
import javax.ws.rs.core.Response.Status;
import javax.ws.rs.core.UriBuilder;
+
import java.io.IOException;
import java.net.URI;
import java.util.List;
@@ -68,6 +69,7 @@ import static com.thoughtworks.selenium.SeleneseTestBase.fail;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
/**
@@ -124,7 +126,7 @@ public abstract class AbstractIdentityProviderTest {
public void testSuccessfulAuthentication() {
IdentityProviderModel identityProviderModel = getIdentityProviderModel();
- assertSuccessfulAuthentication(identityProviderModel);
+ assertSuccessfulAuthentication(identityProviderModel, "test-user");
}
@Test
@@ -132,7 +134,77 @@ public abstract class AbstractIdentityProviderTest {
IdentityProviderModel identityProviderModel = getIdentityProviderModel();
identityProviderModel.setUpdateProfileFirstLogin(false);
- assertSuccessfulAuthentication(identityProviderModel);
+ assertSuccessfulAuthentication(identityProviderModel, "test-user");
+ }
+
+ @Test
+ public void testSuccessfulAuthenticationWithoutUpdateProfile_newUser_emailAsUsername() {
+
+ getRealm().setRegistrationEmailAsUsername(true);
+ brokerServerRule.stopSession(this.session, true);
+ this.session = brokerServerRule.startSession();
+
+ try {
+ IdentityProviderModel identityProviderModel = getIdentityProviderModel();
+ identityProviderModel.setUpdateProfileFirstLogin(false);
+
+ authenticateWithIdentityProvider(identityProviderModel, "test-user");
+
+ // authenticated and redirected to app
+ assertTrue(this.driver.getCurrentUrl().startsWith("http://localhost:8081/test-app"));
+
+ // check correct user is created with email as username and bound to correct federated identity
+ RealmModel realm = getRealm();
+
+ UserModel federatedUser = session.users().getUserByUsername("test-user@localhost", realm);
+
+ assertNotNull(federatedUser);
+
+ assertEquals("test-user@localhost", federatedUser.getUsername());
+
+ doAssertFederatedUser(federatedUser, identityProviderModel);
+
+ Set<FederatedIdentityModel> federatedIdentities = this.session.users().getFederatedIdentities(federatedUser, realm);
+
+ assertEquals(1, federatedIdentities.size());
+
+ FederatedIdentityModel federatedIdentityModel = federatedIdentities.iterator().next();
+
+ assertEquals(getProviderId(), federatedIdentityModel.getIdentityProvider());
+
+ driver.navigate().to("http://localhost:8081/test-app/logout");
+ driver.navigate().to("http://localhost:8081/test-app");
+
+ assertTrue(this.driver.getCurrentUrl().startsWith("http://localhost:8081/auth/realms/realm-with-broker/protocol/openid-connect/login"));
+
+ } finally {
+ getRealm().setRegistrationEmailAsUsername(false);
+ }
+ }
+
+ @Test
+ public void testSuccessfulAuthenticationWithoutUpdateProfile_newUser_emailAsUsername_emailNotProvided() {
+
+ getRealm().setRegistrationEmailAsUsername(true);
+ brokerServerRule.stopSession(this.session, true);
+ this.session = brokerServerRule.startSession();
+
+ try {
+ IdentityProviderModel identityProviderModel = getIdentityProviderModel();
+ identityProviderModel.setUpdateProfileFirstLogin(false);
+
+ authenticateWithIdentityProvider(identityProviderModel, "test-user-noemail");
+
+ RealmModel realm = getRealm();
+ UserModel federatedUser = session.users().getUserByUsername("test-user-noemail", realm);
+ assertNull(federatedUser);
+
+ // assert page is shown with correct error message
+ assertEquals("Email is not provided. Use another provider to create account please.", this.driver.findElement(By.className("kc-feedback-text")).getText());
+
+ } finally {
+ getRealm().setRegistrationEmailAsUsername(false);
+ }
}
@Test
@@ -313,7 +385,7 @@ public abstract class AbstractIdentityProviderTest {
identityProviderModel.setStoreToken(true);
- authenticateWithIdentityProvider(identityProviderModel);
+ authenticateWithIdentityProvider(identityProviderModel, "test-user");
UserModel federatedUser = getFederatedUser();
RealmModel realm = getRealm();
@@ -435,8 +507,8 @@ public abstract class AbstractIdentityProviderTest {
protected abstract void doAssertTokenRetrieval(String pageSource);
- private void assertSuccessfulAuthentication(IdentityProviderModel identityProviderModel) {
- authenticateWithIdentityProvider(identityProviderModel);
+ private void assertSuccessfulAuthentication(IdentityProviderModel identityProviderModel, String username) {
+ authenticateWithIdentityProvider(identityProviderModel, username);
// authenticated and redirected to app
assertTrue(this.driver.getCurrentUrl().startsWith("http://localhost:8081/test-app"));
@@ -464,7 +536,7 @@ public abstract class AbstractIdentityProviderTest {
assertTrue(this.driver.getCurrentUrl().startsWith("http://localhost:8081/auth/realms/realm-with-broker/protocol/openid-connect/login"));
}
- private void authenticateWithIdentityProvider(IdentityProviderModel identityProviderModel) {
+ private void authenticateWithIdentityProvider(IdentityProviderModel identityProviderModel, String username) {
driver.navigate().to("http://localhost:8081/test-app");
assertTrue(this.driver.getCurrentUrl().startsWith("http://localhost:8081/auth/realms/realm-with-broker/protocol/openid-connect/login"));
@@ -475,7 +547,7 @@ public abstract class AbstractIdentityProviderTest {
assertTrue(this.driver.getCurrentUrl().startsWith("http://localhost:8082/auth/"));
// log in to identity provider
- this.loginPage.login("test-user", "password");
+ this.loginPage.login(username, "password");
doAfterProviderAuthentication();
diff --git a/testsuite/integration/src/test/java/org/keycloak/testsuite/forms/RegisterTest.java b/testsuite/integration/src/test/java/org/keycloak/testsuite/forms/RegisterTest.java
index 2c2b802..2d0657a 100644
--- a/testsuite/integration/src/test/java/org/keycloak/testsuite/forms/RegisterTest.java
+++ b/testsuite/integration/src/test/java/org/keycloak/testsuite/forms/RegisterTest.java
@@ -193,4 +193,76 @@ public class RegisterTest {
events.expectLogin().detail("username", "registerUserSuccess").user(userId).assertEvent();
}
+ @Test
+ public void registerExistingUser_emailAsUsername() {
+ configureRelamRegistrationEmailAsUsername(true);
+
+ try {
+ loginPage.open();
+ loginPage.clickRegister();
+ registerPage.assertCurrent();
+
+ registerPage.registerWithEmailAsUsername("firstName", "lastName", "test-user@localhost", "password", "password");
+
+ registerPage.assertCurrent();
+ Assert.assertEquals("Username already exists", registerPage.getError());
+
+ events.expectRegister("test-user@localhost", "test-user@localhost").user((String) null).error("username_in_use").assertEvent();
+ } finally {
+ configureRelamRegistrationEmailAsUsername(false);
+ }
+ }
+
+ @Test
+ public void registerUserMissingOrInvalidEmail_emailAsUsername() {
+ configureRelamRegistrationEmailAsUsername(true);
+
+ try {
+ loginPage.open();
+ loginPage.clickRegister();
+ registerPage.assertCurrent();
+
+ registerPage.registerWithEmailAsUsername("firstName", "lastName", null, "password", "password");
+ registerPage.assertCurrent();
+ Assert.assertEquals("Please specify email", registerPage.getError());
+ events.expectRegister(null, null).removeDetail("username").removeDetail("email").error("invalid_registration").assertEvent();
+
+ registerPage.registerWithEmailAsUsername("firstName", "lastName", "registerUserInvalidEmailemail", "password", "password");
+ registerPage.assertCurrent();
+ Assert.assertEquals("Invalid email address", registerPage.getError());
+ events.expectRegister("registerUserInvalidEmailemail", "registerUserInvalidEmailemail").error("invalid_registration").assertEvent();
+ } finally {
+ configureRelamRegistrationEmailAsUsername(false);
+ }
+ }
+
+ @Test
+ public void registerUserSuccess_emailAsUsername() {
+ configureRelamRegistrationEmailAsUsername(true);
+
+ try {
+ loginPage.open();
+ loginPage.clickRegister();
+ registerPage.assertCurrent();
+
+ registerPage.registerWithEmailAsUsername("firstName", "lastName", "registerUserSuccessE@email", "password", "password");
+
+ Assert.assertEquals(RequestType.AUTH_RESPONSE, appPage.getRequestType());
+
+ String userId = events.expectRegister("registerUserSuccessE@email", "registerUserSuccessE@email").assertEvent().getUserId();
+ events.expectLogin().detail("username", "registerUserSuccessE@email").user(userId).assertEvent();
+ } finally {
+ configureRelamRegistrationEmailAsUsername(false);
+ }
+ }
+
+ protected void configureRelamRegistrationEmailAsUsername(final boolean value) {
+ keycloakRule.configure(new KeycloakRule.KeycloakSetup() {
+ @Override
+ public void config(RealmManager manager, RealmModel adminstrationRealm, RealmModel appRealm) {
+ appRealm.setRegistrationEmailAsUsername(value);
+ }
+ });
+ }
+
}
diff --git a/testsuite/integration/src/test/java/org/keycloak/testsuite/pages/RegisterPage.java b/testsuite/integration/src/test/java/org/keycloak/testsuite/pages/RegisterPage.java
index d3b95ed..217cf19 100644
--- a/testsuite/integration/src/test/java/org/keycloak/testsuite/pages/RegisterPage.java
+++ b/testsuite/integration/src/test/java/org/keycloak/testsuite/pages/RegisterPage.java
@@ -21,6 +21,9 @@
*/
package org.keycloak.testsuite.pages;
+import org.junit.Assert;
+
+import org.openqa.selenium.NoSuchElementException;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.support.FindBy;
@@ -87,6 +90,42 @@ public class RegisterPage extends AbstractPage {
submitButton.click();
}
+ public void registerWithEmailAsUsername(String firstName, String lastName, String email, String password, String passwordConfirm) {
+ firstNameInput.clear();
+ if (firstName != null) {
+ firstNameInput.sendKeys(firstName);
+ }
+
+ lastNameInput.clear();
+ if (lastName != null) {
+ lastNameInput.sendKeys(lastName);
+ }
+
+ emailInput.clear();
+ if (email != null) {
+ emailInput.sendKeys(email);
+ }
+
+ try {
+ usernameInput.clear();
+ Assert.fail("Form must be without username field");
+ } catch (NoSuchElementException e) {
+ // OK
+ }
+
+ passwordInput.clear();
+ if (password != null) {
+ passwordInput.sendKeys(password);
+ }
+
+ passwordConfirmInput.clear();
+ if (passwordConfirm != null) {
+ passwordConfirmInput.sendKeys(passwordConfirm);
+ }
+
+ submitButton.click();
+ }
+
public String getError() {
return loginErrorMessage != null ? loginErrorMessage.getText() : null;
}
diff --git a/testsuite/integration/src/test/resources/broker-test/test-broker-realm-with-kc-oidc.json b/testsuite/integration/src/test/resources/broker-test/test-broker-realm-with-kc-oidc.json
index dbed987..1fd510f 100755
--- a/testsuite/integration/src/test/resources/broker-test/test-broker-realm-with-kc-oidc.json
+++ b/testsuite/integration/src/test/resources/broker-test/test-broker-realm-with-kc-oidc.json
@@ -35,6 +35,17 @@
"realmRoles": ["manager"]
},
{
+ "username" : "test-user-noemail",
+ "enabled": true,
+ "firstName" : "Test",
+ "lastName" : "User",
+ "credentials" : [
+ { "type" : "password",
+ "value" : "password" }
+ ],
+ "realmRoles": ["manager"]
+ },
+ {
"username" : "pedroigor",
"enabled": true,
"email" : "psilva@redhat.com",
diff --git a/testsuite/integration/src/test/resources/broker-test/test-broker-realm-with-saml.json b/testsuite/integration/src/test/resources/broker-test/test-broker-realm-with-saml.json
index 1972224..60c0396 100755
--- a/testsuite/integration/src/test/resources/broker-test/test-broker-realm-with-saml.json
+++ b/testsuite/integration/src/test/resources/broker-test/test-broker-realm-with-saml.json
@@ -32,6 +32,17 @@
"realmRoles": ["manager"]
},
{
+ "username" : "test-user-noemail",
+ "enabled": true,
+ "firstName" : "Test",
+ "lastName" : "User",
+ "credentials" : [
+ { "type" : "password",
+ "value" : "password" }
+ ],
+ "realmRoles": ["manager"]
+ },
+ {
"username" : "pedroigor",
"enabled": true,
"email" : "psilva@redhat.com",
diff --git a/testsuite/integration/src/test/resources/broker-test/test-broker-realm-with-saml-with-signature.json b/testsuite/integration/src/test/resources/broker-test/test-broker-realm-with-saml-with-signature.json
index 3d22c42..4b3c505 100755
--- a/testsuite/integration/src/test/resources/broker-test/test-broker-realm-with-saml-with-signature.json
+++ b/testsuite/integration/src/test/resources/broker-test/test-broker-realm-with-saml-with-signature.json
@@ -38,6 +38,17 @@
"realmRoles": ["manager"]
},
{
+ "username" : "test-user-noemail",
+ "enabled": true,
+ "firstName" : "Test",
+ "lastName" : "User",
+ "credentials" : [
+ { "type" : "password",
+ "value" : "password" }
+ ],
+ "realmRoles": ["manager"]
+ },
+ {
"username" : "pedroigor",
"enabled": true,
"email" : "psilva@redhat.com",