diff --git a/events/api/src/main/java/org/keycloak/events/Errors.java b/events/api/src/main/java/org/keycloak/events/Errors.java index fa5d49b6e3..a0f536c324 100755 --- a/events/api/src/main/java/org/keycloak/events/Errors.java +++ b/events/api/src/main/java/org/keycloak/events/Errors.java @@ -35,7 +35,9 @@ public interface Errors { String NOT_ALLOWED = "not_allowed"; String IDENTITY_PROVIDER_NOT_FOUND = "identity_provider_not_found"; - String SOCIAL_ID_IN_USE = "social_id_in_use"; + String FEDERATED_IDENTITY_EMAIL_EXISTS = "federated_identity_email_exists"; + String FEDERATED_IDENTITY_USERNAME_EXISTS = "federated_identity_username_exists"; + String FEDERATED_IDENTITY_DISABLED_REGISTRATION = "federated_identity_disabled_registration"; String SSL_REQUIRED = "ssl_required"; String USER_SESSION_NOT_FOUND = "user_session_not_found"; diff --git a/forms/common-themes/src/main/resources/theme/login/base/messages/messages.properties b/forms/common-themes/src/main/resources/theme/login/base/messages/messages.properties index bd8f0b2d6c..577d9b506a 100755 --- a/forms/common-themes/src/main/resources/theme/login/base/messages/messages.properties +++ b/forms/common-themes/src/main/resources/theme/login/base/messages/messages.properties @@ -55,6 +55,7 @@ emailExists=Email already exists federatedIdentityEmailExists=User with email already exists. Please login to account management to link the account. federatedIdentityUsernameExists=User with username already exists. Please login to account management to link the account. +federatedIdentityDisabledRegistration=Registration of new users is not allowed. Please ask admin to register you and login to account management to link the account. loginTitle=Log in to loginOauthTitle=Temporary access. diff --git a/services/src/main/java/org/keycloak/services/resources/AuthenticationBrokerResource.java b/services/src/main/java/org/keycloak/services/resources/AuthenticationBrokerResource.java index 01af03cbce..fd27d8c5bb 100644 --- a/services/src/main/java/org/keycloak/services/resources/AuthenticationBrokerResource.java +++ b/services/src/main/java/org/keycloak/services/resources/AuthenticationBrokerResource.java @@ -340,15 +340,28 @@ public class AuthenticationBrokerResource { if (federatedUser == null) { - UserModel existingUser = session.users().getUserByEmail(updatedIdentity.getEmail(), realm); - String errorMessage = "federatedIdentityEmailExists"; + String errorMessage = null; - if (existingUser == null) { + // Check if no user already exists with this username or email + UserModel existingUser = session.users().getUserByEmail(updatedIdentity.getEmail(), realm); + if (existingUser != null) { + event.error(Errors.FEDERATED_IDENTITY_EMAIL_EXISTS); + errorMessage = "federatedIdentityEmailExists"; + } else { existingUser = session.users().getUserByUsername(updatedIdentity.getUsername(), realm); - errorMessage = "federatedIdentityUsernameExists"; + if (existingUser != null) { + event.error(Errors.FEDERATED_IDENTITY_USERNAME_EXISTS); + errorMessage = "federatedIdentityUsernameExists"; + } } - if (existingUser == null) { + // Check if realm registration is allowed + if (!realm.isRegistrationAllowed()) { + event.error(Errors.FEDERATED_IDENTITY_DISABLED_REGISTRATION); + errorMessage = "federatedIdentityDisabledRegistration"; + } + + if (errorMessage == null) { logger.debug("Creating user " + updatedIdentity.getUsername() + " and linking to federation provider " + providerId); federatedUser = session.users().addUser(realm, updatedIdentity.getUsername()); federatedUser.setEnabled(true); 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 15eacda854..1c912d3402 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 @@ -232,11 +232,50 @@ public abstract class AbstractIdentityProviderTest { accountFederatedIdentityPage.logout(); assertTrue(driver.getTitle().equals("Log in to realm-with-broker")); - // Assert I am logged immediately to account management + // Assert I am logged immediately to account management due to previously linked "test-user" identity loginPage.clickSocial(identityProviderModel.getId()); doAfterProviderAuthentication(); assertTrue(accountFederatedIdentityPage.isCurrent()); assertTrue(driver.getPageSource().contains("id=\"remove-" + identityProviderModel.getId() + "\"")); + + // Unlink my "test-user" + accountFederatedIdentityPage.clickRemoveProvider(identityProviderModel.getId()); + assertTrue(driver.getPageSource().contains("id=\"add-" + identityProviderModel.getId() + "\"")); + + // Logout from account management + accountFederatedIdentityPage.logout(); + assertTrue(driver.getTitle().equals("Log in to realm-with-broker")); + + // Try to login. Previous link is not valid anymore, so now it should try to register new user + this.loginPage.clickSocial(identityProviderModel.getId()); + doAfterProviderAuthentication(); + this.updateProfilePage.assertCurrent(); + } + + @Test + public void testDisabledRegistration() { + // Disable registration in realm + getRealm().setRegistrationAllowed(false); + brokerServerRule.stopSession(this.session, true); + this.session = brokerServerRule.startSession(); + + // Login with identity provider + this.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")); + this.loginPage.clickSocial(getProviderId()); + + assertTrue(this.driver.getCurrentUrl().startsWith("http://localhost:8082/auth/")); + this.loginPage.login("test-user", "password"); + doAfterProviderAuthentication(); + + WebElement element = this.driver.findElement(By.className("kc-feedback-text")); + assertNotNull(element); + assertEquals("Registration of new users is not allowed. Please ask admin to register you and login to account management to link the account.", element.getText()); + + // Re-enable registration in realm + getRealm().setRegistrationAllowed(true); + brokerServerRule.stopSession(this.session, true); + this.session = brokerServerRule.startSession(); } @Test(expected = NoSuchElementException.class) diff --git a/testsuite/integration/src/test/resources/broker-test/test-realm-with-broker.json b/testsuite/integration/src/test/resources/broker-test/test-realm-with-broker.json index 8b372aeb7d..182b131277 100755 --- a/testsuite/integration/src/test/resources/broker-test/test-realm-with-broker.json +++ b/testsuite/integration/src/test/resources/broker-test/test-realm-with-broker.json @@ -4,6 +4,7 @@ "enabled": true, "requiredCredentials": [ "password" ], "resetPasswordAllowed": true, + "registrationAllowed": true, "defaultRoles": [ "manager" ], "privateKey": "MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQCCPyvTTb14vSMkpe/pds2P5Cqxk7bkeFnQiNMS1vyZ+HS2O79fxzp1eAguHnBTs4XTRT7SZJhIT/6utgqZjmDigKV5N7X5ptq8BM/W1qa1cYBRip261pc+tWf3IywJYQ9yFI9mUQarmIEl0D7GH16NSZklheaWfbodRVarvX+ML0amNtGYVDft/RftYmgbKKrK218qQp9R4GZFtf/Q/RmboNXN7weMINU8GWVkTRrccKBIXSunT6zXGfuj3Wp1YpVq20BWwY2OMM/P+yDAc7LKEO1LJqPBdT4r9BRn2lXiaga3AL24gTKZPKU/tu7uqfFciF+i4Rr58SMDNOzQcnklAgMBAAECggEAc0eibJYEO5d8QXW1kPgcHV2gBChv2mxDYnWYDLbIQSdNdfYP/qABt/MTmm5KkWr16fcCEYoD1w0mqFBrtVn1msSusUmEAYGTXJMNumOmjjX1kzaTQMmqeFBrwqwYz/xehWR5P+A7fSmwNV3KEeW19GvN5w5K96w0TLAQdFV3TQVPSytusDunwuR1yltMe1voaEDZ9z0Pi08YiEk2f6xhj5CMkoiw3mNImzfruphHullxU4FD05fH6tDeJ381527ILpAzDsgYZh4aFLKjUHem96bX4EL7FIzBJ6okgN78AZnUC/EaVfgFTw0qfhoWvZV4ruVXXiMhCg4CMMRDq/k9iQKBgQDBNWsJMT84OnnWmQoJmZogkFV+tsGrSK6Re+aJxLWpishh7dwAnT2OcagZvVdUb0FwNWu1D0B9/SKDDMRnnHBhOGDpH57m/eQdRU0oX1BD27xvffk0lLcfD4BTxnR5e9jss8K4twc9jf0P1rxC/loGJ2NtCH0BrPHgz54Ea+96ewKBgQCsk3JDaaPnFwzVYm2BXlhxOxLPsF4wvD2rIRAswZV4C5xebjand8nwiMmVpNd0PRLkEnkI+waURGv2EY/P3JsssoiY8Xqe8f/1G+SQKre7lbqOas8rFoALepC0BYDiZDFy0Z9ZnRAFzRI5sgIt7jpoMRD4xDNlmiV8X+yBxc3Y3wKBgQChDQsU1YUyNKQ8+sLAL9anEEkD4Ald4q8JPHN2IY+gLLxNzT0XEfsu0pTiJ8805axxgUYv3e/PVYNAJBNPnrqaf6lgiegl+jr9Hzhqz9CTUAYqFaL2boSakoxQyNtsLI0s+cb1vDN/3uy0GDZDzcty18BsMagqDmRtFgNNAj/UIwKBgQCahbeFBv0cOPZjxisY8Bou4N8aGehsqNBq/0LVYExuXa8YmoTTdJ3bgw9Er4G/ccQNdUDsuqAMeCtW/CiRzQ0ge4d1sprB4Rv3I4+HSsiS7SFKzfZLtWzXWlpg5qCdlWr1TR7qhYjIOPO9t1beO3YOvwhcRoliyyAPenBxTmTfbwKBgDtm2WJ5VlQgNpIdOs1CCiqd0DFmWOmvBPspPC1kySiy+Ndr9jNohRZkR7pEjgqA5E8rdzc88LirUN7bY5HFHRWN9KXrs5/o3O1K3GFCp64N6nvnPEYZ2zSJalcMC2fjSsJg26z8Dg1H+gfTIDUMoGiEAAnJXuqk+WayPU+fZMLn", "publicKey": "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAgj8r0029eL0jJKXv6XbNj+QqsZO25HhZ0IjTEtb8mfh0tju/X8c6dXgILh5wU7OF00U+0mSYSE/+rrYKmY5g4oCleTe1+abavATP1tamtXGAUYqdutaXPrVn9yMsCWEPchSPZlEGq5iBJdA+xh9ejUmZJYXmln26HUVWq71/jC9GpjbRmFQ37f0X7WJoGyiqyttfKkKfUeBmRbX/0P0Zm6DVze8HjCDVPBllZE0a3HCgSF0rp0+s1xn7o91qdWKVattAVsGNjjDPz/sgwHOyyhDtSyajwXU+K/QUZ9pV4moGtwC9uIEymTylP7bu7qnxXIhfouEa+fEjAzTs0HJ5JQIDAQAB",