From b7976ff3de0187d28cbe371a858d51af32913853 Mon Sep 17 00:00:00 2001 From: Julien Lancelot Date: Thu, 24 May 2018 15:56:11 +0200 Subject: [PATCH] SONAR-10652 Correctly fail when authentication and several emails exists --- .../main/java/org/sonar/db/user/UserDao.java | 17 +- .../java/org/sonar/db/user/UserMapper.java | 3 +- .../java/org/sonar/db/user/UserDaoTest.java | 9 +- .../org/sonarqube/qa/util/GroupTester.java | 4 +- .../qa/util/pageobjects/LoginPage.java | 5 + .../authentication/AuthenticationModule.java | 2 +- .../authentication/AuthenticatorsImpl.java | 8 +- ...tor.java => HttpHeadersAuthenticator.java} | 10 +- .../UserIdentityAuthenticatorImpl.java | 31 +- .../AuthenticatorsImplTest.java | 14 +- ...java => HttpHeadersAuthenticatorTest.java} | 4 +- .../UserIdentityAuthenticatorImplTest.java | 27 +- .../org/sonarqube/tests/Category5Suite.java | 4 +- .../tests/user/BaseIdentityProviderTest.java | 60 +++- .../user/HttpHeadersAuthenticationTest.java | 191 ++++++++++++ .../user/OAuth2IdentityProviderTest.java | 50 +++- .../tests/user/RealmAuthenticationTest.java | 276 +++++++----------- .../tests/user/SsoAuthenticationTest.java | 166 ----------- ...ot_in_log_when_unauthorized_exception.html | 44 --- ...rized_page_when_authentication_failed.html | 39 --- ...henticate_when_not_allowed_to_sign_up.html | 39 --- .../fail_when_email_already_exists.html | 44 --- .../external-user-details.html | 64 ---- .../external-user-details2.html | 64 ---- ...ot_in_log_when_unauthorized_exception.html | 44 --- ...rized_page_when_authentication_failed.html | 39 --- ...henticate_when_not_allowed_to_sign_up.html | 39 --- 27 files changed, 464 insertions(+), 833 deletions(-) rename server/sonar-server/src/main/java/org/sonar/server/authentication/{SsoAuthenticator.java => HttpHeadersAuthenticator.java} (95%) rename server/sonar-server/src/test/java/org/sonar/server/authentication/{SsoAuthenticatorTest.java => HttpHeadersAuthenticatorTest.java} (98%) create mode 100644 tests/src/test/java/org/sonarqube/tests/user/HttpHeadersAuthenticationTest.java delete mode 100644 tests/src/test/java/org/sonarqube/tests/user/SsoAuthenticationTest.java delete mode 100644 tests/src/test/resources/user/BaseIdentityProviderTest/display_message_in_ui_but_not_in_log_when_unauthorized_exception.html delete mode 100644 tests/src/test/resources/user/BaseIdentityProviderTest/display_unauthorized_page_when_authentication_failed.html delete mode 100644 tests/src/test/resources/user/BaseIdentityProviderTest/fail_to_authenticate_when_not_allowed_to_sign_up.html delete mode 100644 tests/src/test/resources/user/BaseIdentityProviderTest/fail_when_email_already_exists.html delete mode 100644 tests/src/test/resources/user/ExternalAuthenticationTest/external-user-details.html delete mode 100644 tests/src/test/resources/user/ExternalAuthenticationTest/external-user-details2.html delete mode 100644 tests/src/test/resources/user/OAuth2IdentityProviderTest/display_message_in_ui_but_not_in_log_when_unauthorized_exception.html delete mode 100644 tests/src/test/resources/user/OAuth2IdentityProviderTest/display_unauthorized_page_when_authentication_failed.html delete mode 100644 tests/src/test/resources/user/OAuth2IdentityProviderTest/fail_to_authenticate_when_not_allowed_to_sign_up.html diff --git a/server/sonar-db-dao/src/main/java/org/sonar/db/user/UserDao.java b/server/sonar-db-dao/src/main/java/org/sonar/db/user/UserDao.java index 79318d4d02a..f78aebc4f71 100644 --- a/server/sonar-db-dao/src/main/java/org/sonar/db/user/UserDao.java +++ b/server/sonar-db-dao/src/main/java/org/sonar/db/user/UserDao.java @@ -22,7 +22,6 @@ package org.sonar.db.user; import java.util.Collection; import java.util.HashMap; import java.util.List; -import java.util.Locale; import java.util.Map; import java.util.Objects; import java.util.function.Consumer; @@ -38,15 +37,16 @@ import org.sonar.db.DbSession; import org.sonar.db.component.ComponentDto; import org.sonar.db.organization.OrganizationDto; +import static java.util.Locale.ENGLISH; import static org.sonar.db.DatabaseUtils.executeLargeInputs; import static org.sonar.db.DatabaseUtils.executeLargeInputsWithoutOutput; +import static org.sonar.db.user.UserDto.SCM_ACCOUNTS_SEPARATOR; public class UserDao implements Dao { private final System2 system2; private final UuidFactory uuidFactory; - public UserDao(System2 system2, UuidFactory uuidFactory) { this.system2 = system2; this.uuidFactory = uuidFactory; @@ -154,19 +154,18 @@ public class UserDao implements Dao { public List selectByScmAccountOrLoginOrEmail(DbSession session, String scmAccountOrLoginOrEmail) { String like = new StringBuilder().append("%") - .append(UserDto.SCM_ACCOUNTS_SEPARATOR).append(scmAccountOrLoginOrEmail) - .append(UserDto.SCM_ACCOUNTS_SEPARATOR).append("%").toString(); + .append(SCM_ACCOUNTS_SEPARATOR).append(scmAccountOrLoginOrEmail) + .append(SCM_ACCOUNTS_SEPARATOR).append("%").toString(); return mapper(session).selectNullableByScmAccountOrLoginOrEmail(scmAccountOrLoginOrEmail, like); } /** - * Search for an active user with the given email exits in database + * Search for an active user with the given emailCaseInsensitive exits in database * - * Please note that email is case insensitive, result for searching 'mail@email.com' or 'Mail@Email.com' will be the same + * Select is case insensitive. Result for searching 'mail@emailCaseInsensitive.com' or 'Mail@Email.com' is the same */ - @CheckForNull - public UserDto selectByEmail(DbSession dbSession, String email) { - return mapper(dbSession).selectByEmail(email.toLowerCase(Locale.ENGLISH)); + public List selectByEmail(DbSession dbSession, String emailCaseInsensitive) { + return mapper(dbSession).selectByEmail(emailCaseInsensitive.toLowerCase(ENGLISH)); } @CheckForNull diff --git a/server/sonar-db-dao/src/main/java/org/sonar/db/user/UserMapper.java b/server/sonar-db-dao/src/main/java/org/sonar/db/user/UserMapper.java index c83c98a739a..2ab7fe93dab 100644 --- a/server/sonar-db-dao/src/main/java/org/sonar/db/user/UserMapper.java +++ b/server/sonar-db-dao/src/main/java/org/sonar/db/user/UserMapper.java @@ -57,8 +57,7 @@ public interface UserMapper { List selectByIds(@Param("ids") List ids); - @CheckForNull - UserDto selectByEmail(String email); + List selectByEmail(String email); @CheckForNull UserDto selectByExternalIdAndIdentityProvider(@Param("externalId") String externalId, @Param("externalIdentityProvider") String externalExternalIdentityProvider); diff --git a/server/sonar-db-dao/src/test/java/org/sonar/db/user/UserDaoTest.java b/server/sonar-db-dao/src/test/java/org/sonar/db/user/UserDaoTest.java index 1ca0e6a9c01..f54f8923af8 100644 --- a/server/sonar-db-dao/src/test/java/org/sonar/db/user/UserDaoTest.java +++ b/server/sonar-db-dao/src/test/java/org/sonar/db/user/UserDaoTest.java @@ -585,12 +585,13 @@ public class UserDaoTest { @Test public void select_by_email() { - UserDto activeUser = db.users().insertUser(); + UserDto activeUser1 = db.users().insertUser(u -> u.setEmail("user1@email.com")); + UserDto activeUser2 = db.users().insertUser(u -> u.setEmail("user1@email.com")); UserDto disableUser = db.users().insertUser(u -> u.setActive(false)); - assertThat(underTest.selectByEmail(session, activeUser.getEmail())).isNotNull(); - assertThat(underTest.selectByEmail(session, disableUser.getEmail())).isNull(); - assertThat(underTest.selectByEmail(session, "unknown")).isNull(); + assertThat(underTest.selectByEmail(session, "user1@email.com")).hasSize(2); + assertThat(underTest.selectByEmail(session, disableUser.getEmail())).isEmpty(); + assertThat(underTest.selectByEmail(session, "unknown")).isEmpty(); } @Test diff --git a/server/sonar-qa-util/src/main/java/org/sonarqube/qa/util/GroupTester.java b/server/sonar-qa-util/src/main/java/org/sonarqube/qa/util/GroupTester.java index 4b369210c88..3e1c0cbee85 100644 --- a/server/sonar-qa-util/src/main/java/org/sonarqube/qa/util/GroupTester.java +++ b/server/sonar-qa-util/src/main/java/org/sonarqube/qa/util/GroupTester.java @@ -70,11 +70,11 @@ public class GroupTester { return response.getGroupsList(); } - public GroupTester addMemberToGroups(Organizations.Organization organization, String userLogin, String... groups) { + public GroupTester addMemberToGroups(@Nullable Organizations.Organization organization, String userLogin, String... groups) { for (String group : groups) { AddUserRequest request = new AddUserRequest() .setLogin(userLogin) - .setOrganization(organization.getKey()) + .setOrganization(organization != null ? organization.getKey() : null) .setName(group); session.wsClient().userGroups().addUser(request); } diff --git a/server/sonar-qa-util/src/main/java/org/sonarqube/qa/util/pageobjects/LoginPage.java b/server/sonar-qa-util/src/main/java/org/sonarqube/qa/util/pageobjects/LoginPage.java index 3f765429d47..154386aacb0 100644 --- a/server/sonar-qa-util/src/main/java/org/sonarqube/qa/util/pageobjects/LoginPage.java +++ b/server/sonar-qa-util/src/main/java/org/sonarqube/qa/util/pageobjects/LoginPage.java @@ -45,6 +45,11 @@ public class LoginPage { return Selenide.page(Navigation.class); } + public Navigation useBaseAuth() { + Selenide.$(".oauth-providers a").click(); + return Selenide.page(Navigation.class); + } + public LoginPage submitWrongCredentials(String login, String password) { Selenide.$("#login").val(login); Selenide.$("#password").val(password); diff --git a/server/sonar-server/src/main/java/org/sonar/server/authentication/AuthenticationModule.java b/server/sonar-server/src/main/java/org/sonar/server/authentication/AuthenticationModule.java index 7cc3041bdd3..dfc64b840e0 100644 --- a/server/sonar-server/src/main/java/org/sonar/server/authentication/AuthenticationModule.java +++ b/server/sonar-server/src/main/java/org/sonar/server/authentication/AuthenticationModule.java @@ -51,7 +51,7 @@ public class AuthenticationModule extends Module { RealmAuthenticator.class, BasicAuthenticator.class, ValidateAction.class, - SsoAuthenticator.class, + HttpHeadersAuthenticator.class, AuthenticatorsImpl.class); } } diff --git a/server/sonar-server/src/main/java/org/sonar/server/authentication/AuthenticatorsImpl.java b/server/sonar-server/src/main/java/org/sonar/server/authentication/AuthenticatorsImpl.java index 358b149f787..a1bd581afa5 100644 --- a/server/sonar-server/src/main/java/org/sonar/server/authentication/AuthenticatorsImpl.java +++ b/server/sonar-server/src/main/java/org/sonar/server/authentication/AuthenticatorsImpl.java @@ -28,19 +28,19 @@ public class AuthenticatorsImpl implements Authenticators { private final JwtHttpHandler jwtHttpHandler; private final BasicAuthenticator basicAuthenticator; - private final SsoAuthenticator ssoAuthenticator; + private final HttpHeadersAuthenticator httpHeadersAuthenticator; - public AuthenticatorsImpl(JwtHttpHandler jwtHttpHandler, BasicAuthenticator basicAuthenticator, SsoAuthenticator ssoAuthenticator) { + public AuthenticatorsImpl(JwtHttpHandler jwtHttpHandler, BasicAuthenticator basicAuthenticator, HttpHeadersAuthenticator httpHeadersAuthenticator) { this.jwtHttpHandler = jwtHttpHandler; this.basicAuthenticator = basicAuthenticator; - this.ssoAuthenticator = ssoAuthenticator; + this.httpHeadersAuthenticator = httpHeadersAuthenticator; } // Try first to authenticate from SSO, then JWT token, then try from basic http header @Override public Optional authenticate(HttpServletRequest request, HttpServletResponse response) { // SSO authentication should come first in order to update JWT if user from header is not the same is user from JWT - Optional user = ssoAuthenticator.authenticate(request, response); + Optional user = httpHeadersAuthenticator.authenticate(request, response); if (user.isPresent()) { return user; } diff --git a/server/sonar-server/src/main/java/org/sonar/server/authentication/SsoAuthenticator.java b/server/sonar-server/src/main/java/org/sonar/server/authentication/HttpHeadersAuthenticator.java similarity index 95% rename from server/sonar-server/src/main/java/org/sonar/server/authentication/SsoAuthenticator.java rename to server/sonar-server/src/main/java/org/sonar/server/authentication/HttpHeadersAuthenticator.java index 8d59e944228..5282b62bd16 100644 --- a/server/sonar-server/src/main/java/org/sonar/server/authentication/SsoAuthenticator.java +++ b/server/sonar-server/src/main/java/org/sonar/server/authentication/HttpHeadersAuthenticator.java @@ -58,9 +58,9 @@ import static org.sonar.process.ProcessProperties.Property.SONAR_WEB_SSO_NAME_HE import static org.sonar.process.ProcessProperties.Property.SONAR_WEB_SSO_REFRESH_INTERVAL_IN_MINUTES; import static org.sonar.server.user.ExternalIdentity.SQ_AUTHORITY; -public class SsoAuthenticator implements Startable { +public class HttpHeadersAuthenticator implements Startable { - private static final Logger LOG = Loggers.get(SsoAuthenticator.class); + private static final Logger LOG = Loggers.get(HttpHeadersAuthenticator.class); private static final Splitter COMA_SPLITTER = Splitter.on(",").trimResults().omitEmptyStrings(); @@ -82,8 +82,8 @@ public class SsoAuthenticator implements Startable { private boolean enabled = false; private Map settingsByKey = new HashMap<>(); - public SsoAuthenticator(System2 system2, Configuration config, UserIdentityAuthenticator userIdentityAuthenticator, - JwtHttpHandler jwtHttpHandler, AuthenticationEvent authenticationEvent) { + public HttpHeadersAuthenticator(System2 system2, Configuration config, UserIdentityAuthenticator userIdentityAuthenticator, + JwtHttpHandler jwtHttpHandler, AuthenticationEvent authenticationEvent) { this.system2 = system2; this.config = config; this.userIdentityAuthenticator = userIdentityAuthenticator; @@ -94,7 +94,7 @@ public class SsoAuthenticator implements Startable { @Override public void start() { if (config.getBoolean(SONAR_WEB_SSO_ENABLE.getKey()).orElse(false)) { - LOG.info("SSO Authentication enabled"); + LOG.info("HTTP headers authentication enabled"); enabled = true; SETTINGS.forEach(entry -> settingsByKey.put(entry.getKey(), config.get(entry.getKey()).orElse(entry.getDefaultValue()))); } diff --git a/server/sonar-server/src/main/java/org/sonar/server/authentication/UserIdentityAuthenticatorImpl.java b/server/sonar-server/src/main/java/org/sonar/server/authentication/UserIdentityAuthenticatorImpl.java index 966f0d97e63..a5247b533b9 100644 --- a/server/sonar-server/src/main/java/org/sonar/server/authentication/UserIdentityAuthenticatorImpl.java +++ b/server/sonar-server/src/main/java/org/sonar/server/authentication/UserIdentityAuthenticatorImpl.java @@ -23,6 +23,7 @@ import com.google.common.collect.Sets; import java.util.ArrayList; import java.util.Collection; import java.util.HashSet; +import java.util.List; import java.util.Map; import java.util.Objects; import java.util.Optional; @@ -135,7 +136,15 @@ public class UserIdentityAuthenticatorImpl implements UserIdentityAuthenticator if (email == null) { return Optional.empty(); } - UserDto existingUser = dbClient.userDao().selectByEmail(dbSession, email); + List existingUsers = dbClient.userDao().selectByEmail(dbSession, email); + if (existingUsers.isEmpty()) { + return Optional.empty(); + } + if (existingUsers.size() > 1) { + throw generateExistingEmailError(authenticatorParameters, email); + } + + UserDto existingUser = existingUsers.get(0); if (existingUser == null || Objects.equals(existingUser.getLogin(), authenticatorParameters.getUserIdentity().getLogin()) || (Objects.equals(existingUser.getExternalId(), authenticatorParameters.getUserIdentity().getProviderId()) @@ -151,14 +160,7 @@ public class UserIdentityAuthenticatorImpl implements UserIdentityAuthenticator case WARN: throw new EmailAlreadyExistsRedirectionException(email, existingUser, authenticatorParameters.getUserIdentity(), authenticatorParameters.getProvider()); case FORBID: - throw AuthenticationException.newBuilder() - .setSource(authenticatorParameters.getSource()) - .setLogin(authenticatorParameters.getUserIdentity().getLogin()) - .setMessage(format("Email '%s' is already used", email)) - .setPublicMessage(format( - "You can't sign up because email '%s' is already used by an existing user. This means that you probably already registered with another account.", - email)) - .build(); + throw generateExistingEmailError(authenticatorParameters, email); default: throw new IllegalStateException(format("Unknown strategy %s", existingEmailStrategy)); } @@ -264,4 +266,15 @@ public class UserIdentityAuthenticatorImpl implements UserIdentityAuthenticator return userDto.map(u -> new UserDto[] {u}).orElse(new UserDto[] {}); } + private static AuthenticationException generateExistingEmailError(UserIdentityAuthenticatorParameters authenticatorParameters, String email) { + return AuthenticationException.newBuilder() + .setSource(authenticatorParameters.getSource()) + .setLogin(authenticatorParameters.getUserIdentity().getLogin()) + .setMessage(format("Email '%s' is already used", email)) + .setPublicMessage(format( + "You can't sign up because email '%s' is already used by an existing user. This means that you probably already registered with another account.", + email)) + .build(); + } + } diff --git a/server/sonar-server/src/test/java/org/sonar/server/authentication/AuthenticatorsImplTest.java b/server/sonar-server/src/test/java/org/sonar/server/authentication/AuthenticatorsImplTest.java index 0924ad34d15..492fb8bfa0b 100644 --- a/server/sonar-server/src/test/java/org/sonar/server/authentication/AuthenticatorsImplTest.java +++ b/server/sonar-server/src/test/java/org/sonar/server/authentication/AuthenticatorsImplTest.java @@ -40,12 +40,12 @@ public class AuthenticatorsImplTest { private HttpServletResponse response = mock(HttpServletResponse.class); private JwtHttpHandler jwtHttpHandler = mock(JwtHttpHandler.class); private BasicAuthenticator basicAuthenticator = mock(BasicAuthenticator.class); - private SsoAuthenticator ssoAuthenticator = mock(SsoAuthenticator.class); - private Authenticators underTest = new AuthenticatorsImpl(jwtHttpHandler, basicAuthenticator, ssoAuthenticator); + private HttpHeadersAuthenticator httpHeadersAuthenticator = mock(HttpHeadersAuthenticator.class); + private Authenticators underTest = new AuthenticatorsImpl(jwtHttpHandler, basicAuthenticator, httpHeadersAuthenticator); @Test public void authenticate_from_jwt_token() { - when(ssoAuthenticator.authenticate(request, response)).thenReturn(Optional.empty()); + when(httpHeadersAuthenticator.authenticate(request, response)).thenReturn(Optional.empty()); when(jwtHttpHandler.validateToken(request, response)).thenReturn(Optional.of(user)); assertThat(underTest.authenticate(request, response)).hasValue(user); @@ -55,7 +55,7 @@ public class AuthenticatorsImplTest { @Test public void authenticate_from_basic_header() { when(basicAuthenticator.authenticate(request)).thenReturn(Optional.of(user)); - when(ssoAuthenticator.authenticate(request, response)).thenReturn(Optional.empty()); + when(httpHeadersAuthenticator.authenticate(request, response)).thenReturn(Optional.empty()); when(jwtHttpHandler.validateToken(request, response)).thenReturn(Optional.empty()); assertThat(underTest.authenticate(request, response)).hasValue(user); @@ -67,12 +67,12 @@ public class AuthenticatorsImplTest { @Test public void authenticate_from_sso() { - when(ssoAuthenticator.authenticate(request, response)).thenReturn(Optional.of(user)); + when(httpHeadersAuthenticator.authenticate(request, response)).thenReturn(Optional.of(user)); when(jwtHttpHandler.validateToken(request, response)).thenReturn(Optional.empty()); assertThat(underTest.authenticate(request, response)).hasValue(user); - verify(ssoAuthenticator).authenticate(request, response); + verify(httpHeadersAuthenticator).authenticate(request, response); verify(jwtHttpHandler, never()).validateToken(request, response); verify(response, never()).setStatus(anyInt()); } @@ -80,7 +80,7 @@ public class AuthenticatorsImplTest { @Test public void return_empty_if_not_authenticated() { when(jwtHttpHandler.validateToken(request, response)).thenReturn(Optional.empty()); - when(ssoAuthenticator.authenticate(request, response)).thenReturn(Optional.empty()); + when(httpHeadersAuthenticator.authenticate(request, response)).thenReturn(Optional.empty()); when(basicAuthenticator.authenticate(request)).thenReturn(Optional.empty()); assertThat(underTest.authenticate(request, response)).isEmpty(); diff --git a/server/sonar-server/src/test/java/org/sonar/server/authentication/SsoAuthenticatorTest.java b/server/sonar-server/src/test/java/org/sonar/server/authentication/HttpHeadersAuthenticatorTest.java similarity index 98% rename from server/sonar-server/src/test/java/org/sonar/server/authentication/SsoAuthenticatorTest.java rename to server/sonar-server/src/test/java/org/sonar/server/authentication/HttpHeadersAuthenticatorTest.java index 98d8b00a15c..cc604880c26 100644 --- a/server/sonar-server/src/test/java/org/sonar/server/authentication/SsoAuthenticatorTest.java +++ b/server/sonar-server/src/test/java/org/sonar/server/authentication/HttpHeadersAuthenticatorTest.java @@ -64,7 +64,7 @@ import static org.mockito.Mockito.when; import static org.sonar.db.user.UserTesting.newUserDto; import static org.sonar.server.authentication.event.AuthenticationExceptionMatcher.authenticationException; -public class SsoAuthenticatorTest { +public class HttpHeadersAuthenticatorTest { private MapSettings settings = new MapSettings(); @@ -113,7 +113,7 @@ public class SsoAuthenticatorTest { private JwtHttpHandler jwtHttpHandler = mock(JwtHttpHandler.class); private AuthenticationEvent authenticationEvent = mock(AuthenticationEvent.class); - private SsoAuthenticator underTest = new SsoAuthenticator(system2, settings.asConfig(), userIdentityAuthenticator, jwtHttpHandler, authenticationEvent); + private HttpHeadersAuthenticator underTest = new HttpHeadersAuthenticator(system2, settings.asConfig(), userIdentityAuthenticator, jwtHttpHandler, authenticationEvent); @Before public void setUp() throws Exception { diff --git a/server/sonar-server/src/test/java/org/sonar/server/authentication/UserIdentityAuthenticatorImplTest.java b/server/sonar-server/src/test/java/org/sonar/server/authentication/UserIdentityAuthenticatorImplTest.java index fe778cb894d..c58afab14bc 100644 --- a/server/sonar-server/src/test/java/org/sonar/server/authentication/UserIdentityAuthenticatorImplTest.java +++ b/server/sonar-server/src/test/java/org/sonar/server/authentication/UserIdentityAuthenticatorImplTest.java @@ -277,10 +277,29 @@ public class UserIdentityAuthenticatorImplTest { @Test public void throw_AuthenticationException_when_authenticating_new_user_when_email_already_exists_and_strategy_is_FORBID() { - db.users().insertUser(newUserDto() - .setLogin("Existing user with same email") - .setActive(true) - .setEmail("john@email.com")); + db.users().insertUser(u -> u.setEmail("john@email.com")); + Source source = Source.realm(AuthenticationEvent.Method.FORM, IDENTITY_PROVIDER.getName()); + + expectedException.expect(authenticationException().from(source) + .withLogin(USER_IDENTITY.getLogin()) + .andPublicMessage("You can't sign up because email 'john@email.com' is already used by an existing user. " + + "This means that you probably already registered with another account.")); + expectedException.expectMessage("Email 'john@email.com' is already used"); + + underTest.authenticate(UserIdentityAuthenticatorParameters.builder() + .setUserIdentity(USER_IDENTITY) + .setProvider(IDENTITY_PROVIDER) + .setSource(source) + .setExistingEmailStrategy(FORBID) + .setExistingEmailStrategy(ExistingEmailStrategy.FORBID) + .setUpdateLoginStrategy(UpdateLoginStrategy.ALLOW) + .build()); + } + + @Test + public void throw_AuthenticationException_when_authenticating_new_user_and_email_already_exists_multiple_times() { + db.users().insertUser(u -> u.setEmail("john@email.com")); + db.users().insertUser(u -> u.setEmail("john@email.com")); Source source = Source.realm(AuthenticationEvent.Method.FORM, IDENTITY_PROVIDER.getName()); expectedException.expect(authenticationException().from(source) diff --git a/tests/src/test/java/org/sonarqube/tests/Category5Suite.java b/tests/src/test/java/org/sonarqube/tests/Category5Suite.java index d45b79800cc..b2a635e0703 100644 --- a/tests/src/test/java/org/sonarqube/tests/Category5Suite.java +++ b/tests/src/test/java/org/sonarqube/tests/Category5Suite.java @@ -37,9 +37,9 @@ import org.sonarqube.tests.settings.SettingsTestRestartingOrchestrator; import org.sonarqube.tests.startup.StartupIndexationTest; import org.sonarqube.tests.telemetry.TelemetryOptOutTest; import org.sonarqube.tests.telemetry.TelemetryUploadTest; +import org.sonarqube.tests.user.HttpHeadersAuthenticationTest; import org.sonarqube.tests.user.OnboardingTest; import org.sonarqube.tests.user.RealmAuthenticationTest; -import org.sonarqube.tests.user.SsoAuthenticationTest; import org.sonarqube.tests.user.UserEsResilienceTest; /** @@ -61,7 +61,7 @@ import org.sonarqube.tests.user.UserEsResilienceTest; // update center UpdateCenterTest.class, RealmAuthenticationTest.class, - SsoAuthenticationTest.class, + HttpHeadersAuthenticationTest.class, OnboardingTest.class, BuiltInQualityProfilesNotificationTest.class, ActiveRuleEsResilienceTest.class, diff --git a/tests/src/test/java/org/sonarqube/tests/user/BaseIdentityProviderTest.java b/tests/src/test/java/org/sonarqube/tests/user/BaseIdentityProviderTest.java index 4545bc08ecd..f9bfa51ce65 100644 --- a/tests/src/test/java/org/sonarqube/tests/user/BaseIdentityProviderTest.java +++ b/tests/src/test/java/org/sonarqube/tests/user/BaseIdentityProviderTest.java @@ -19,14 +19,13 @@ */ package org.sonarqube.tests.user; +import com.codeborne.selenide.Condition; import com.google.common.base.Joiner; import com.sonar.orchestrator.Orchestrator; -import java.io.File; import java.util.Arrays; import java.util.List; import java.util.stream.Collectors; import javax.annotation.Nullable; -import org.apache.commons.io.FileUtils; import org.junit.After; import org.junit.ClassRule; import org.junit.Rule; @@ -41,10 +40,13 @@ import org.sonarqube.ws.client.users.DeactivateRequest; import org.sonarqube.ws.client.users.GroupsRequest; import org.sonarqube.ws.client.users.SearchRequest; +import static com.codeborne.selenide.Selenide.$; +import static java.lang.String.format; +import static java.nio.charset.StandardCharsets.UTF_8; +import static org.apache.commons.io.FileUtils.readFileToString; import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.tuple; import static org.sonarqube.ws.UserGroups.Group; -import static util.selenium.Selenese.runSelenese; public class BaseIdentityProviderTest { @@ -105,8 +107,11 @@ public class BaseIdentityProviderTest { // As this property is null, the plugin will throw an exception tester.settings().setGlobalSettings("sonar.auth.fake-base-id-provider.user", null); - runSelenese(ORCHESTRATOR, "/user/BaseIdentityProviderTest/display_unauthorized_page_when_authentication_failed.html"); + tester.openBrowser() + .logIn() + .useBaseAuth(); + $("#bd").shouldHave(Condition.text("You're not authorized to access this page. Please contact the administrator")); assertThat(tester.users().getByLogin(USER_LOGIN)).isNotPresent(); } @@ -116,21 +121,45 @@ public class BaseIdentityProviderTest { setUserCreatedByAuthPlugin(USER_LOGIN, USER_PROVIDER_ID, USER_PROVIDER_LOGIN, USER_NAME, USER_EMAIL); tester.users().generate(u -> u.setLogin("another").setName("Another").setEmail(USER_EMAIL).setPassword("another")); - runSelenese(ORCHESTRATOR, "/user/BaseIdentityProviderTest/fail_when_email_already_exists.html"); + tester.openBrowser() + .logIn() + .useBaseAuth(); - File logFile = ORCHESTRATOR.getServer().getWebLogs(); - assertThat(FileUtils.readFileToString(logFile)) + $("#bd").shouldHave(Condition.text( + format("You can't sign up because email '%s' is already used by an existing user. This means that you probably already registered with another account.", USER_EMAIL))); + assertThat(readFileToString(ORCHESTRATOR.getServer().getWebLogs(), UTF_8)) .doesNotContain("You can't sign up because email 'john@email.com' is already used by an existing user. This means that you probably already registered with another account"); } + @Test + public void fail_to_authenticate_user_when_email_already_exists_on_several_users() { + enablePlugin(); + setUserCreatedByAuthPlugin(USER_LOGIN, USER_PROVIDER_ID, USER_PROVIDER_LOGIN, USER_NAME, USER_EMAIL); + tester.users().generate(u -> u.setEmail(USER_EMAIL)); + tester.users().generate(u -> u.setEmail(USER_EMAIL)); + + tester.openBrowser() + .logIn() + .useBaseAuth(); + + $("#bd").shouldHave(Condition.text( + format("You can't sign up because email '%s' is already used by an existing user. This means that you probably already registered with another account.", USER_EMAIL))); + assertThat(tester.users().getByLogin(USER_LOGIN)).isNotPresent(); + } + @Test public void fail_to_authenticate_when_not_allowed_to_sign_up() { enablePlugin(); setUserCreatedByAuthPlugin(USER_LOGIN, USER_PROVIDER_ID, USER_PROVIDER_LOGIN, USER_NAME, USER_EMAIL); tester.settings().setGlobalSettings("sonar.auth.fake-base-id-provider.allowsUsersToSignUp", "false"); - runSelenese(ORCHESTRATOR, "/user/BaseIdentityProviderTest/fail_to_authenticate_when_not_allowed_to_sign_up.html"); + tester.openBrowser() + .logIn() + .useBaseAuth(); + $("#bd") + .shouldHave(Condition.text("You're not authorized to access this page. Please contact the administrator.")) + .shouldHave(Condition.text(format("Reason: '%s' users are not allowed to sign up", FAKE_PROVIDER_KEY))); assertThat(tester.users().getByLogin(USER_LOGIN)).isNotPresent(); } @@ -190,13 +219,16 @@ public class BaseIdentityProviderTest { setUserCreatedByAuthPlugin(USER_LOGIN, USER_PROVIDER_ID, USER_PROVIDER_LOGIN, USER_NAME, USER_EMAIL); tester.settings().setGlobalSettings("sonar.auth.fake-base-id-provider.throwUnauthorizedMessage", "true"); - runSelenese(ORCHESTRATOR, - "/user/BaseIdentityProviderTest/display_message_in_ui_but_not_in_log_when_unauthorized_exception.html"); - - File logFile = ORCHESTRATOR.getServer().getWebLogs(); - assertThat(FileUtils.readFileToString(logFile)).doesNotContain("A functional error has happened"); - assertThat(FileUtils.readFileToString(logFile)).doesNotContain("UnauthorizedException"); + tester.openBrowser() + .logIn() + .useBaseAuth(); + $("#bd") + .shouldHave(Condition.text("You're not authorized to access this page. Please contact the administrator")) + .shouldHave(Condition.text("Reason: A functional error has happened")); + assertThat(readFileToString(ORCHESTRATOR.getServer().getWebLogs(), UTF_8)) + .doesNotContain("A functional error has happened") + .doesNotContain("UnauthorizedException"); assertThat(tester.users().getByLogin(USER_LOGIN)).isNotPresent(); } diff --git a/tests/src/test/java/org/sonarqube/tests/user/HttpHeadersAuthenticationTest.java b/tests/src/test/java/org/sonarqube/tests/user/HttpHeadersAuthenticationTest.java new file mode 100644 index 00000000000..300c60c0f60 --- /dev/null +++ b/tests/src/test/java/org/sonarqube/tests/user/HttpHeadersAuthenticationTest.java @@ -0,0 +1,191 @@ +/* + * SonarQube + * Copyright (C) 2009-2018 SonarSource SA + * mailto:info AT sonarsource DOT com + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +package org.sonarqube.tests.user; + +import com.sonar.orchestrator.Orchestrator; +import java.net.URLEncoder; +import java.util.List; +import javax.annotation.Nullable; +import okhttp3.Response; +import org.apache.commons.io.FileUtils; +import org.junit.ClassRule; +import org.junit.Rule; +import org.junit.Test; +import org.sonarqube.qa.util.Tester; +import org.sonarqube.ws.UserGroups.Group; +import org.sonarqube.ws.Users.CreateWsResponse.User; +import org.sonarqube.ws.Users.SearchWsResponse; +import org.sonarqube.ws.client.users.SearchRequest; + +import static java.lang.String.format; +import static java.nio.charset.StandardCharsets.UTF_8; +import static java.util.Arrays.asList; +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.groups.Tuple.tuple; +import static util.ItUtils.call; +import static util.ItUtils.newOrchestratorBuilder; + +/** + * Test authentication using HTTP headers. + *

+ * It starts its own server as it's using a different authentication system + */ +public class HttpHeadersAuthenticationTest { + + private static final String LOGIN_HEADER = "H-Login"; + private static final String NAME_HEADER = "H-Name"; + private static final String EMAIL_HEADER = "H-Email"; + private static final String GROUPS_HEADER = "H-Groups"; + + @ClassRule + public static final Orchestrator orchestrator = newOrchestratorBuilder() + .setServerProperty("sonar.web.sso.enable", "true") + .setServerProperty("sonar.web.sso.loginHeader", LOGIN_HEADER) + .setServerProperty("sonar.web.sso.nameHeader", NAME_HEADER) + .setServerProperty("sonar.web.sso.emailHeader", EMAIL_HEADER) + .setServerProperty("sonar.web.sso.groupsHeader", GROUPS_HEADER) + .build(); + + @Rule + public Tester tester = new Tester(orchestrator).disableOrganizations(); + + @Test + public void authenticate() { + String login = tester.users().generateLogin(); + + doCall(login, "Tester", "tester@email.com", null); + + verifyUser(login, "Tester", "tester@email.com"); + } + + @Test + public void authenticate_with_only_login() { + String login = tester.users().generateLogin(); + + doCall(login, null, null, null); + + assertThat(tester.wsClient().users().search(new SearchRequest().setQ(login)).getUsersList()) + .extracting(SearchWsResponse.User::getLogin, SearchWsResponse.User::getName, SearchWsResponse.User::hasEmail) + .containsExactlyInAnyOrder(tuple(login, login, false)); + } + + @Test + public void update_user_when_headers_are_updated() { + String login = tester.users().generateLogin(); + doCall(login, "Tester", "tester@email.com", null); + verifyUser(login, "Tester", "tester@email.com"); + + // As we don't keep the JWT token is the test, the user is updated + doCall(login, "new name", "new email", null); + verifyUser(login, "new name", "new email"); + } + + @Test + public void authenticate_with_groups() { + String login = tester.users().generateLogin(); + Group group = tester.groups().generate(); + + doCall(login, null, null, group.getName()); + + assertThat(tester.wsClient().users().search(new SearchRequest().setQ(login)).getUsersList()) + .extracting(SearchWsResponse.User::getLogin, u -> u.getGroups().getGroupsList()) + .containsExactlyInAnyOrder(tuple(login, asList(group.getName(), "sonar-users"))); + } + + @Test + public void synchronize_groups_when_authenticating_existing_user() { + User user = tester.users().generate(); + Group group1 = tester.groups().generate(); + Group group2 = tester.groups().generate(); + Group group3 = tester.groups().generate(); + tester.groups().addMemberToGroups(null, user.getLogin(), group1.getName(), group2.getName()); + + doCall(user.getLogin(), null, null, group2.getName() + "," + group3.getName()); + + assertThat(tester.wsClient().users().search(new SearchRequest().setQ(user.getLogin())).getUsersList()) + .extracting(SearchWsResponse.User::getLogin, u -> u.getGroups().getGroupsList()) + .containsExactlyInAnyOrder(tuple(user.getLogin(), asList(group2.getName(), group3.getName(), "sonar-users"))); + } + + @Test + public void authentication_with_local_user_is_possible_when_no_header() { + User user = tester.users().generate(); + + // Check any ws, no error should be thrown + tester.as(user.getLogin(), user.getLogin()).wsClient().system().ping(); + } + + @Test + public void display_message_in_ui_but_not_in_log_when_unauthorized_exception() throws Exception { + String login = "invalid login $"; + Response response = doCall(login, null, null, null); + + assertThat(response.code()).isEqualTo(200); + assertThat(response.request().url().toString()).contains("sessions/unauthorized"); + + List logsLines = FileUtils.readLines(orchestrator.getServer().getWebLogs(), UTF_8); + assertThat(logsLines).doesNotContain("org.sonar.server.exceptions.BadRequestException: Use only letters, numbers, and .-_@ please."); + assertThat(tester.wsClient().users().search(new SearchRequest().setQ(login)).getUsersList()).isEmpty(); + } + + @Test + public void fail_when_email_already_exists() throws Exception { + String login = tester.users().generateLogin(); + User existingUser = tester.users().generate(); + + Response response = doCall(login, "Tester", existingUser.getEmail(), null); + + String expectedError = format("You can't sign up because email '%s' is already used by an existing user. This means that you probably already registered with another account", + existingUser.getEmail()); + assertThat(response.code()).isEqualTo(200); + assertThat(response.request().url().toString()).contains(URLEncoder.encode(expectedError, UTF_8.name())); + assertThat(FileUtils.readLines(orchestrator.getServer().getWebLogs(), UTF_8)).doesNotContain(expectedError); + } + + @Test + public void fail_to_authenticate_user_when_email_already_exists_on_several_users() throws Exception { + String login = tester.users().generateLogin(); + tester.users().generate(u -> u.setEmail("john@email.com")); + tester.users().generate(u -> u.setEmail("john@email.com")); + + Response response = doCall(login, "Tester", "john@email.com", null); + + String expectedError = "You can't sign up because email 'john@email.com' is already used by an existing user. This means that you probably already registered with another account"; + assertThat(response.code()).isEqualTo(200); + assertThat(response.request().url().toString()).contains(URLEncoder.encode(expectedError, UTF_8.name())); + assertThat(FileUtils.readLines(orchestrator.getServer().getWebLogs(), UTF_8)).doesNotContain(expectedError); + } + + private static Response doCall(String login, @Nullable String name, @Nullable String email, @Nullable String groups) { + return call(orchestrator.getServer().getUrl(), + LOGIN_HEADER, login, + NAME_HEADER, name, + EMAIL_HEADER, email, + GROUPS_HEADER, groups); + } + + private void verifyUser(String login, String name, String email) { + assertThat(tester.wsClient().users().search(new SearchRequest().setQ(login)).getUsersList()) + .extracting(SearchWsResponse.User::getLogin, SearchWsResponse.User::getName, SearchWsResponse.User::getEmail, + SearchWsResponse.User::getExternalIdentity, SearchWsResponse.User::getExternalProvider, SearchWsResponse.User::getLocal) + .containsExactlyInAnyOrder(tuple(login, name, email, login, "sonarqube", false)); + } + +} diff --git a/tests/src/test/java/org/sonarqube/tests/user/OAuth2IdentityProviderTest.java b/tests/src/test/java/org/sonarqube/tests/user/OAuth2IdentityProviderTest.java index b7e194b3785..b6a74623aa1 100644 --- a/tests/src/test/java/org/sonarqube/tests/user/OAuth2IdentityProviderTest.java +++ b/tests/src/test/java/org/sonarqube/tests/user/OAuth2IdentityProviderTest.java @@ -21,11 +21,9 @@ package org.sonarqube.tests.user; import com.codeborne.selenide.Condition; import com.sonar.orchestrator.Orchestrator; -import java.io.File; import java.net.HttpURLConnection; import okhttp3.mockwebserver.MockResponse; import okhttp3.mockwebserver.MockWebServer; -import org.apache.commons.io.FileUtils; import org.junit.After; import org.junit.Before; import org.junit.ClassRule; @@ -37,10 +35,12 @@ import org.sonarqube.ws.Users.SearchWsResponse.User; import org.sonarqube.ws.client.GetRequest; import org.sonarqube.ws.client.permissions.AddUserRequest; import org.sonarqube.ws.client.users.CreateRequest; -import util.selenium.Selenese; import static com.codeborne.selenide.Condition.visible; import static com.codeborne.selenide.Selenide.$; +import static java.lang.String.format; +import static java.nio.charset.StandardCharsets.UTF_8; +import static org.apache.commons.io.FileUtils.readFileToString; import static org.assertj.core.api.Assertions.assertThat; /** @@ -137,8 +137,11 @@ public class OAuth2IdentityProviderTest { // As this property is null, the plugin will throw an exception tester.settings().setGlobalSettings("sonar.auth.fake-oauth2-id-provider.user", null); - Selenese.runSelenese(orchestrator, "/user/OAuth2IdentityProviderTest/display_unauthorized_page_when_authentication_failed.html"); + tester.openBrowser() + .logIn() + .useOAuth2(); + $("#bd").shouldHave(Condition.text("You're not authorized to access this page. Please contact the administrator")); assertThatUserDoesNotExist(USER_LOGIN); } @@ -148,8 +151,13 @@ public class OAuth2IdentityProviderTest { enablePlugin(); tester.settings().setGlobalSettings("sonar.auth.fake-oauth2-id-provider.allowsUsersToSignUp", "false"); - Selenese.runSelenese(orchestrator, "/user/OAuth2IdentityProviderTest/fail_to_authenticate_when_not_allowed_to_sign_up.html"); + tester.openBrowser() + .logIn() + .useOAuth2(); + $("#bd") + .shouldHave(Condition.text("You're not authorized to access this page. Please contact the administrator.")) + .shouldHave(Condition.text(format("Reason: '%s' users are not allowed to sign up", FAKE_PROVIDER_KEY))); assertThatUserDoesNotExist(USER_LOGIN); } @@ -159,12 +167,16 @@ public class OAuth2IdentityProviderTest { enablePlugin(); tester.settings().setGlobalSettings("sonar.auth.fake-oauth2-id-provider.throwUnauthorizedMessage", "true"); - Selenese.runSelenese(orchestrator, "/user/OAuth2IdentityProviderTest/display_message_in_ui_but_not_in_log_when_unauthorized_exception.html"); - - File logFile = orchestrator.getServer().getWebLogs(); - assertThat(FileUtils.readFileToString(logFile)).doesNotContain("A functional error has happened"); - assertThat(FileUtils.readFileToString(logFile)).doesNotContain("UnauthorizedException"); - + tester.openBrowser() + .logIn() + .useOAuth2(); + + $("#bd") + .shouldHave(Condition.text("You're not authorized to access this page. Please contact the administrator")) + .shouldHave(Condition.text("Reason: A functional error has happened")); + assertThat(readFileToString(orchestrator.getServer().getWebLogs(), UTF_8)) + .doesNotContain("A functional error has happened") + .doesNotContain("UnauthorizedException"); assertThatUserDoesNotExist(USER_LOGIN); } @@ -205,6 +217,22 @@ public class OAuth2IdentityProviderTest { assertThat(tester.users().getByLogin("another").get().getEmail()).isNullOrEmpty(); } + @Test + public void fail_to_authenticate_user_when_email_already_exists_on_several_users() { + simulateRedirectionToCallback(); + enablePlugin(); + tester.users().generate(u -> u.setEmail(USER_EMAIL)); + tester.users().generate(u -> u.setEmail(USER_EMAIL)); + + tester.openBrowser() + .logIn() + .useOAuth2(); + + $("#bd").shouldHave(Condition.text( + format("You can't sign up because email '%s' is already used by an existing user. This means that you probably already registered with another account.", USER_EMAIL))); + assertThatUserDoesNotExist(USER_LOGIN); + } + @Test public void provision_user_before_authentication() { simulateRedirectionToCallback(); diff --git a/tests/src/test/java/org/sonarqube/tests/user/RealmAuthenticationTest.java b/tests/src/test/java/org/sonarqube/tests/user/RealmAuthenticationTest.java index c733ffab7e6..e34e6371168 100644 --- a/tests/src/test/java/org/sonarqube/tests/user/RealmAuthenticationTest.java +++ b/tests/src/test/java/org/sonarqube/tests/user/RealmAuthenticationTest.java @@ -21,43 +21,30 @@ package org.sonarqube.tests.user; import com.codeborne.selenide.Condition; import com.google.common.collect.ImmutableMap; -import com.google.common.collect.Maps; import com.sonar.orchestrator.Orchestrator; +import java.util.Collections; import java.util.Map; import javax.annotation.CheckForNull; -import org.junit.After; -import org.junit.Before; import org.junit.ClassRule; import org.junit.Rule; import org.junit.Test; import org.junit.rules.ExpectedException; -import org.sonar.wsclient.Host; -import org.sonar.wsclient.Sonar; -import org.sonar.wsclient.base.HttpException; -import org.sonar.wsclient.connectors.HttpClient4Connector; -import org.sonar.wsclient.services.AuthenticationQuery; -import org.sonar.wsclient.user.UserParameters; import org.sonarqube.qa.util.Tester; import org.sonarqube.qa.util.pageobjects.Navigation; import org.sonarqube.qa.util.pageobjects.SystemInfoPage; import org.sonarqube.qa.util.pageobjects.UsersManagementPage; +import org.sonarqube.ws.UserGroups.Group; +import org.sonarqube.ws.Users; import org.sonarqube.ws.Users.SearchWsResponse.User; -import org.sonarqube.ws.client.GetRequest; -import org.sonarqube.ws.client.WsResponse; -import org.sonarqube.ws.client.users.CreateRequest; +import org.sonarqube.ws.client.users.ChangePasswordRequest; import org.sonarqube.ws.client.users.SearchRequest; -import util.user.UserRule; -import static java.net.HttpURLConnection.HTTP_OK; -import static java.net.HttpURLConnection.HTTP_UNAUTHORIZED; +import static java.util.Arrays.asList; import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.groups.Tuple.tuple; -import static org.junit.Assert.fail; +import static util.ItUtils.expectHttpError; import static util.ItUtils.newOrchestratorBuilder; -import static util.ItUtils.newUserWsClient; import static util.ItUtils.pluginArtifact; -import static util.ItUtils.resetSettings; -import static util.selenium.Selenese.runSelenese; /** * Test REALM authentication. @@ -66,72 +53,46 @@ import static util.selenium.Selenese.runSelenese; */ public class RealmAuthenticationTest { - private static final String TECH_USER = "techUser"; - private static final String USER_LOGIN = "tester"; - private static final String ADMIN_USER_LOGIN = "admin-user"; - @Rule public ExpectedException thrown = ExpectedException.none(); - /** - * Property from security-plugin for user management. - */ - private static final String USERS_PROPERTY = "sonar.fakeauthenticator.users"; - @ClassRule public static final Orchestrator orchestrator = newOrchestratorBuilder() .addPlugin(pluginArtifact("security-plugin")) .setServerProperty("sonar.security.realm", "FakeRealm") .build(); - @Rule - public UserRule userRule = UserRule.from(orchestrator); - @Rule public Tester tester = new Tester(orchestrator).disableOrganizations(); - @Before - @After - public void resetData() { - resetSettings(orchestrator, null, USERS_PROPERTY, "sonar.security.updateUserAttributes"); - } - - @Before - public void initAdminUser() { - userRule.createAdminUser(ADMIN_USER_LOGIN, ADMIN_USER_LOGIN); - } - - @After - public void deleteAdminUser() { - userRule.resetUsers(); - } - /** * SONAR-3137, SONAR-2292 * Restriction on password length (minimum 4 characters) should be disabled, when external system enabled. */ @Test - public void shouldSynchronizeDetailsAndGroups() { + public void synchronize_details_and_groups() { // Given clean Sonar installation and no users in external system - String username = USER_LOGIN; + String username = tester.users().generateLogin(); String password = "123"; - Map users = Maps.newHashMap(); + Group group = tester.groups().generate(); // When user created in external system - users.put(username + ".password", password); - users.put(username + ".name", "Tester Testerovich"); - users.put(username + ".email", "tester@example.org"); - users.put(username + ".groups", "sonar-user"); - updateUsersInExtAuth(users); + updateUsersInExtAuth(ImmutableMap.of( + username + ".password", password, + username + ".name", "Tester Testerovich", + username + ".email", "tester@example.org", + username + ".groups", group.getName())); + // Then verifyAuthenticationIsOk(username, password); - verifyUser(); - - // with external details and groups - runSelenese(orchestrator, "/user/ExternalAuthenticationTest/external-user-details.html"); + assertThat(tester.wsClient().users().search(new SearchRequest().setQ(username)).getUsersList()) + .extracting(User::getLogin, User::getName, User::getEmail, + User::getExternalIdentity, User::getExternalProvider, User::getLocal, u -> u.getGroups().getGroupsList()) + .containsExactlyInAnyOrder(tuple(username, "Tester Testerovich", "tester@example.org", username, "sonarqube", false, asList(group.getName(), "sonar-users"))); // SONAR-4462 - SystemInfoPage page = tester.openBrowser().logIn().submitCredentials(ADMIN_USER_LOGIN).openSystemInfo(); + Users.CreateWsResponse.User adminUser = tester.users().generateAdministrator(); + SystemInfoPage page = tester.openBrowser().logIn().submitCredentials(adminUser.getLogin()).openSystemInfo(); page.getCardItem("System").shouldHaveFieldWithValue("External User Authentication", "FakeRealm"); } @@ -139,56 +100,54 @@ public class RealmAuthenticationTest { * SONAR-4034 */ @Test - public void shouldUpdateDetailsByDefault() { + public void update_details_by_default() { // Given clean Sonar installation and no users in external system - String username = USER_LOGIN; + String username = tester.users().generateLogin(); String password = "123"; - Map users = Maps.newHashMap(); // When user created in external system - users.put(username + ".password", password); - users.put(username + ".name", "Tester Testerovich"); - users.put(username + ".email", "tester@example.org"); - users.put(username + ".groups", "sonar-user"); - updateUsersInExtAuth(users); + updateUsersInExtAuth(ImmutableMap.of( + username + ".password", password, + username + ".name", "Tester Testerovich", + username + ".email", "tester@example.org")); + // Then verifyAuthenticationIsOk(username, password); - verifyUser(); - - // with external details and groups - // TODO replace by WS ? Or with new Selenese utils - runSelenese(orchestrator, "/user/ExternalAuthenticationTest/external-user-details.html"); + assertThat(tester.wsClient().users().search(new SearchRequest().setQ(username)).getUsersList()) + .extracting(User::getLogin, User::getName, User::getEmail) + .containsExactlyInAnyOrder(tuple(username, "Tester Testerovich", "tester@example.org")); // Now update user details - users.put(username + ".name", "Tester2 Testerovich"); - users.put(username + ".email", "tester2@example.org"); - updateUsersInExtAuth(users); + updateUsersInExtAuth(ImmutableMap.of( + username + ".password", password, + username + ".name", "Tester2 Testerovich", + username + ".email", "tester2@example.org")); + // Then verifyAuthenticationIsOk(username, password); // with external details and groups updated - runSelenese(orchestrator, "/user/ExternalAuthenticationTest/external-user-details2.html"); + assertThat(tester.wsClient().users().search(new SearchRequest().setQ(username)).getUsersList()) + .extracting(User::getLogin, User::getName, User::getEmail) + .containsExactlyInAnyOrder(tuple(username, "Tester2 Testerovich", "tester2@example.org")); } /** * SONAR-3138 */ @Test - public void shouldNotFallback() { + public void does_not_fallback() { // Given clean Sonar installation and no users in external system - String login = USER_LOGIN; + String login = tester.users().generateLogin(); String password = "1234567"; - Map users = Maps.newHashMap(); // When user created in external system - users.put(login + ".password", password); - updateUsersInExtAuth(users); + updateUsersInExtAuth(ImmutableMap.of(login + ".password", password)); // Then verifyAuthenticationIsOk(login, password); // When external system does not work - users.remove(login + ".password"); - updateUsersInExtAuth(users); + updateUsersInExtAuth(Collections.emptyMap()); // Then verifyAuthenticationIsNotOk(login, password); } @@ -197,16 +156,14 @@ public class RealmAuthenticationTest { * SONAR-4543 */ @Test - public void adminIsLocalAccountByDefault() { + public void admin_is_local_account_by_default() { // Given clean Sonar installation and no users in external system String login = "admin"; String localPassword = "admin"; String remotePassword = "nimda"; - Map users = Maps.newHashMap(); // When admin created in external system with a different password - users.put(login + ".password", remotePassword); - updateUsersInExtAuth(users); + updateUsersInExtAuth(ImmutableMap.of(login + ".password", remotePassword)); // Then this is local DB that should be used verifyAuthenticationIsNotOk(login, remotePassword); @@ -217,52 +174,49 @@ public class RealmAuthenticationTest { * SONAR-1334, SONAR-3185 (createUsers=true is default) */ @Test - public void shouldCreateNewUsers() { + public void create_new_users() { // Given clean Sonar installation and no users in external system - String username = USER_LOGIN; + String username = tester.users().generateLogin(); String password = "1234567"; - Map users = Maps.newHashMap(); // When user not exists in external system // Then verifyAuthenticationIsNotOk(username, password); // When user created in external system - users.put(username + ".password", password); - updateUsersInExtAuth(users); + updateUsersInExtAuth(ImmutableMap.of(username + ".password", password)); // Then verifyAuthenticationIsOk(username, password); - verifyUser(); + verifyUser(username); verifyAuthenticationIsNotOk(username, "wrong"); } // SONAR-3258 @Test - public void shouldAutomaticallyReactivateDeletedUser() { + public void reactivate_deleted_user() { // Given clean Sonar installation and no users in external system + Users.CreateWsResponse.User adminUser = tester.users().generateAdministrator(); // Let's create and delete the user "tester" in Sonar DB + String login = tester.users().generateLogin(); Navigation nav = tester.openBrowser(); - UsersManagementPage page = nav.logIn().submitCredentials(ADMIN_USER_LOGIN).openUsersManagement(); + UsersManagementPage page = nav.logIn().submitCredentials(adminUser.getLogin()).openUsersManagement(); page - .createUser(USER_LOGIN) + .createUser(login) .hasUsersCount(3) - .getUser(USER_LOGIN) + .getUser(login) .deactivateUser(); page.hasUsersCount(2); nav.logOut() - .logIn().submitWrongCredentials(USER_LOGIN, USER_LOGIN) + .logIn().submitWrongCredentials(login, login) .getErrorMessage().shouldHave(Condition.text("Authentication failed")); // And now update the security with the user that was deleted - String login = USER_LOGIN; String password = "1234567"; - Map users = Maps.newHashMap(); - users.put(login + ".password", password); - updateUsersInExtAuth(users); + updateUsersInExtAuth(ImmutableMap.of(login + ".password", password)); // check that the deleted/deactivated user "tester" has been reactivated and can now log in verifyAuthenticationIsOk(login, password); - verifyUser(); + verifyUser(login); } /** @@ -271,24 +225,20 @@ public class RealmAuthenticationTest { @Test public void update_password_of_technical_user() { // Create user in external authentication - updateUsersInExtAuth(ImmutableMap.of(USER_LOGIN + ".password", USER_LOGIN)); - verifyAuthenticationIsOk(USER_LOGIN, USER_LOGIN); + String login = tester.users().generateLogin(); + updateUsersInExtAuth(ImmutableMap.of(login + ".password", login)); + verifyAuthenticationIsOk(login, login); // Create technical user in db - createUserInDb(TECH_USER, "old_password"); - assertThat(checkAuthenticationThroughWebService(TECH_USER, "old_password")).isTrue(); + Users.CreateWsResponse.User techUser = tester.users().generate(u -> u.setPassword("old_password")); + verifyAuthenticationIsOk(techUser.getLogin(), "old_password"); // Updating password of technical user is allowed - updateUserPasswordInDb(TECH_USER, "new_password"); - assertThat(checkAuthenticationThroughWebService(TECH_USER, "new_password")).isTrue(); + tester.users().service().changePassword(new ChangePasswordRequest().setLogin(techUser.getLogin()).setPassword("new_password")); + verifyAuthenticationIsOk(techUser.getLogin(), "new_password"); // But updating password of none local user is not allowed - try { - updateUserPasswordInDb(USER_LOGIN, "new_password"); - fail(); - } catch (HttpException e) { - verifyHttpException(e, 400); - } + expectHttpError(400, () -> tester.users().service().changePassword(new ChangePasswordRequest().setLogin(login).setPassword("new_password"))); } /** @@ -297,16 +247,14 @@ public class RealmAuthenticationTest { @Test public void authentication_with_ws() { // Given clean Sonar installation and no users in external system - String login = USER_LOGIN; + String login = tester.users().generateLogin(); String password = "1234567"; - Map users = Maps.newHashMap(); // When user created in external system - users.put(login + ".password", password); - updateUsersInExtAuth(users); + updateUsersInExtAuth(ImmutableMap.of(login + ".password", password)); verifyAuthenticationIsOk(login, password); - verifyUser(); + verifyUser(login); verifyAuthenticationIsNotOk("wrong", password); verifyAuthenticationIsNotOk(login, "wrong"); verifyAuthenticationIsNotOk(login, null); @@ -332,71 +280,54 @@ public class RealmAuthenticationTest { @Test public void provision_user_before_authentication() { - tester.wsClient().users().create(new CreateRequest() - .setLogin(USER_LOGIN) - .setName("Tester Testerovich") + Users.CreateWsResponse.User user = tester.users().generate(u -> u.setName("Tester Testerovich") .setEmail("tester@example.org") + .setPassword(null) .setLocal("false")); // The user is created in SonarQube but doesn't exist yet in external authentication system - verifyAuthenticationIsNotOk(USER_LOGIN, "123"); + verifyAuthenticationIsNotOk(user.getLogin(), "123"); updateUsersInExtAuth(ImmutableMap.of( - USER_LOGIN + ".password", "123", - USER_LOGIN + ".name", "Tester Testerovich", - USER_LOGIN + ".email", "tester@example.org")); + user.getLogin() + ".password", "123", + user.getLogin() + ".name", "Tester Testerovich", + user.getLogin() + ".email", "tester@example.org")); - verifyAuthenticationIsOk(USER_LOGIN, "123"); - verifyUser(); + verifyAuthenticationIsOk(user.getLogin(), "123"); + verifyUser(user.getLogin()); } @Test public void fail_to_authenticate_user_when_email_already_exists() { - userRule.createUser("another", "Another", "tester@example.org", "another"); - - String username = USER_LOGIN; + Users.CreateWsResponse.User user = tester.users().generate(); + String username = tester.users().generateLogin(); String password = "123"; - Map users = Maps.newHashMap(); - users.put(username + ".password", password); - users.put(username + ".name", "Tester Testerovich"); - users.put(username + ".email", "tester@example.org"); - users.put(username + ".groups", "sonar-user"); - updateUsersInExtAuth(users); + + updateUsersInExtAuth(ImmutableMap.of( + username + ".password", password, + username + ".email", user.getEmail())); verifyAuthenticationIsNotOk(username, password); } - private void verifyHttpException(Exception e, int expectedCode) { - assertThat(e).isInstanceOf(HttpException.class); - HttpException exception = (HttpException) e; - assertThat(exception.status()).isEqualTo(expectedCode); - } + @Test + public void fail_to_authenticate_user_when_email_already_exists_on_several_users() { + Users.CreateWsResponse.User user1 = tester.users().generate(u -> u.setEmail("user@email.com")); + Users.CreateWsResponse.User user2 = tester.users().generate(u -> u.setEmail("user@email.com")); + String username = tester.users().generateLogin(); + String password = "123"; - private boolean checkAuthenticationThroughWebService(String login, String password) { - return createWsClient(login, password).find(new AuthenticationQuery()).isValid(); + updateUsersInExtAuth(ImmutableMap.of( + username + ".password", password, + username + ".email", "user@email.com")); + + verifyAuthenticationIsNotOk(username, password); } /** * Updates information about users in security-plugin. */ private void updateUsersInExtAuth(Map users) { - tester.settings().setGlobalSettings(USERS_PROPERTY, format(users)); - } - - private void createUserInDb(String login, String password) { - orchestrator.getServer().adminWsClient().userClient().create(UserParameters.create().login(login).name(login) - .password(password).passwordConfirmation(password)); - } - - private void updateUserPasswordInDb(String login, String newPassword) { - orchestrator.getServer().adminWsClient().post("/api/users/change_password", "login", login, "password", newPassword); - } - - /** - * Utility method to create {@link Sonar} with specified {@code username} and {@code password}. - * Orchestrator does not provide such method. - */ - private Sonar createWsClient(String username, String password) { - return new Sonar(new HttpClient4Connector(new Host(orchestrator.getServer().getUrl(), username, password))); + tester.settings().setGlobalSettings("sonar.fakeauthenticator.users", format(users)); } @CheckForNull @@ -412,22 +343,17 @@ public class RealmAuthenticationTest { } private void verifyAuthenticationIsOk(String login, String password) { - assertThat(checkAuthenticationWithWebService(login, password).code()).isEqualTo(HTTP_OK); + tester.as(login, password).wsClient().system().ping(); } private void verifyAuthenticationIsNotOk(String login, String password) { - assertThat(checkAuthenticationWithWebService(login, password).code()).isEqualTo(HTTP_UNAUTHORIZED); - } - - private void verifyUser(){ - assertThat(tester.wsClient().users().search(new SearchRequest().setQ(USER_LOGIN)).getUsersList()) - .extracting(User::getLogin, User::getExternalIdentity, User::getExternalProvider, User::getLocal) - .containsExactlyInAnyOrder(tuple(USER_LOGIN, USER_LOGIN, "sonarqube", false)); + expectHttpError(401, () -> tester.as(login, password).wsClient().system().ping()); } - private WsResponse checkAuthenticationWithWebService(String login, String password) { - // Call any WS - return newUserWsClient(orchestrator, login, password).wsConnector().call(new GetRequest("api/rules/search")); + private void verifyUser(String login) { + assertThat(tester.wsClient().users().search(new SearchRequest().setQ(login)).getUsersList()) + .extracting(User::getLogin, User::getExternalIdentity, User::getExternalProvider, User::getLocal) + .containsExactlyInAnyOrder(tuple(login, login, "sonarqube", false)); } } diff --git a/tests/src/test/java/org/sonarqube/tests/user/SsoAuthenticationTest.java b/tests/src/test/java/org/sonarqube/tests/user/SsoAuthenticationTest.java deleted file mode 100644 index 146f37ea777..00000000000 --- a/tests/src/test/java/org/sonarqube/tests/user/SsoAuthenticationTest.java +++ /dev/null @@ -1,166 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2018 SonarSource SA - * mailto:info AT sonarsource DOT com - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ -package org.sonarqube.tests.user; - -import com.sonar.orchestrator.Orchestrator; -import java.net.URLEncoder; -import java.util.List; -import javax.annotation.Nullable; -import okhttp3.Response; -import org.apache.commons.io.FileUtils; -import org.junit.Before; -import org.junit.ClassRule; -import org.junit.Test; -import org.junit.rules.RuleChain; -import util.user.UserRule; - -import static java.nio.charset.StandardCharsets.UTF_8; -import static org.assertj.core.api.Assertions.assertThat; -import static util.ItUtils.call; -import static util.ItUtils.newOrchestratorBuilder; - -/** - * Test SSO authentication (using HTTP headers). - *

- * It starts its own server as it's using a different authentication system - */ -public class SsoAuthenticationTest { - - private static final String LOGIN_HEADER = "H-Login"; - private static final String NAME_HEADER = "H-Name"; - private static final String EMAIL_HEADER = "H-Email"; - private static final String GROUPS_HEADER = "H-Groups"; - - static final String USER_LOGIN = "tester"; - static final String USER_NAME = "Tester"; - static final String USER_EMAIL = "tester@email.com"; - - static final String GROUP_1 = "group-1"; - static final String GROUP_2 = "group-2"; - static final String GROUP_3 = "group-3"; - - @ClassRule - public static final Orchestrator orchestrator = newOrchestratorBuilder() - .setServerProperty("sonar.web.sso.enable", "true") - .setServerProperty("sonar.web.sso.loginHeader", LOGIN_HEADER) - .setServerProperty("sonar.web.sso.nameHeader", NAME_HEADER) - .setServerProperty("sonar.web.sso.emailHeader", EMAIL_HEADER) - .setServerProperty("sonar.web.sso.groupsHeader", GROUPS_HEADER) - .build(); - - private static UserRule userRule = UserRule.from(orchestrator); - - @ClassRule - public static RuleChain ruleChain = RuleChain.outerRule(orchestrator).around(userRule); - - @Before - public void resetData() { - userRule.resetUsers(); - } - - @Test - public void authenticate() { - doCall(USER_LOGIN, USER_NAME, USER_EMAIL, null); - - userRule.verifyUserExists(USER_LOGIN, USER_NAME, USER_EMAIL); - } - - @Test - public void authenticate_with_only_login() { - doCall(USER_LOGIN, null, null, null); - - userRule.verifyUserExists(USER_LOGIN, USER_LOGIN, null); - } - - @Test - public void update_user_when_headers_are_updated() { - doCall(USER_LOGIN, USER_NAME, USER_EMAIL, null); - userRule.verifyUserExists(USER_LOGIN, USER_NAME, USER_EMAIL); - - // As we don't keep the JWT token is the test, the user is updated - doCall(USER_LOGIN, "new name", "new email", null); - userRule.verifyUserExists(USER_LOGIN, "new name", "new email"); - } - - @Test - public void authenticate_with_groups() { - doCall(USER_LOGIN, null, null, GROUP_1); - - userRule.verifyUserGroupMembership(USER_LOGIN, GROUP_1, "sonar-users"); - } - - @Test - public void synchronize_groups_when_authenticating_existing_user() { - userRule.createGroup(GROUP_1); - userRule.createGroup(GROUP_2); - userRule.createGroup(GROUP_3); - userRule.createUser(USER_LOGIN, "password"); - userRule.associateGroupsToUser(USER_LOGIN, GROUP_1, GROUP_2); - - doCall(USER_LOGIN, null, null, GROUP_2 + "," + GROUP_3); - - userRule.verifyUserGroupMembership(USER_LOGIN, GROUP_2, GROUP_3, "sonar-users"); - } - - @Test - public void authentication_with_local_user_is_possible_when_no_header() { - userRule.createUser(USER_LOGIN, "password"); - - checkLocalAuthentication(USER_LOGIN, "password"); - } - - @Test - public void display_message_in_ui_but_not_in_log_when_unauthorized_exception() throws Exception { - Response response = doCall("invalid login $", null, null, null); - - assertThat(response.code()).isEqualTo(200); - assertThat(response.request().url().toString()).contains("sessions/unauthorized"); - - List logsLines = FileUtils.readLines(orchestrator.getServer().getWebLogs(), UTF_8); - assertThat(logsLines).doesNotContain("org.sonar.server.exceptions.BadRequestException: Use only letters, numbers, and .-_@ please."); - userRule.verifyUserDoesNotExist(USER_LOGIN); - } - - @Test - public void fail_when_email_already_exists() throws Exception { - userRule.createUser("another", "Another", USER_EMAIL, "another"); - - Response response = doCall(USER_LOGIN, USER_NAME, USER_EMAIL, null); - - String expectedError = "You can't sign up because email 'tester@email.com' is already used by an existing user. This means that you probably already registered with another account"; - assertThat(response.code()).isEqualTo(200); - assertThat(response.request().url().toString()).contains(URLEncoder.encode(expectedError, UTF_8.name())); - assertThat(FileUtils.readLines(orchestrator.getServer().getWebLogs(), UTF_8)).doesNotContain(expectedError); - } - - private static Response doCall(String login, @Nullable String name, @Nullable String email, @Nullable String groups) { - return call(orchestrator.getServer().getUrl(), - LOGIN_HEADER, login, - NAME_HEADER, name, - EMAIL_HEADER, email, - GROUPS_HEADER, groups); - } - - private boolean checkLocalAuthentication(String login, String password) { - String result = orchestrator.getServer().wsClient(login, password).get("/api/authentication/validate"); - return result.contains("{\"valid\":true}"); - } - -} diff --git a/tests/src/test/resources/user/BaseIdentityProviderTest/display_message_in_ui_but_not_in_log_when_unauthorized_exception.html b/tests/src/test/resources/user/BaseIdentityProviderTest/display_message_in_ui_but_not_in_log_when_unauthorized_exception.html deleted file mode 100644 index d202404dfd1..00000000000 --- a/tests/src/test/resources/user/BaseIdentityProviderTest/display_message_in_ui_but_not_in_log_when_unauthorized_exception.html +++ /dev/null @@ -1,44 +0,0 @@ - - - - - - fail_to_authenticate_when_not_allowed_to_sign_up - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
french
open/sessions/new
waitForTextcontent*Log in with Fake base identity provider*
clickcss=.oauth-providers a
waitForTextbd*You're not authorized to access this page. Please contact the administrator.*
assertTextbd*Reason: A functional error has happened*
- - diff --git a/tests/src/test/resources/user/BaseIdentityProviderTest/display_unauthorized_page_when_authentication_failed.html b/tests/src/test/resources/user/BaseIdentityProviderTest/display_unauthorized_page_when_authentication_failed.html deleted file mode 100644 index 47a19a2df41..00000000000 --- a/tests/src/test/resources/user/BaseIdentityProviderTest/display_unauthorized_page_when_authentication_failed.html +++ /dev/null @@ -1,39 +0,0 @@ - - - - - - display_unauthorized_page_when_authentication_failed - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
french
open/sessions/new
waitForTextcontent*Log in with Fake base identity provider*
clickcss=.oauth-providers a
waitForTextbd*You're not authorized to access this page. Please contact the administrator.*
- - diff --git a/tests/src/test/resources/user/BaseIdentityProviderTest/fail_to_authenticate_when_not_allowed_to_sign_up.html b/tests/src/test/resources/user/BaseIdentityProviderTest/fail_to_authenticate_when_not_allowed_to_sign_up.html deleted file mode 100644 index ddf1b837078..00000000000 --- a/tests/src/test/resources/user/BaseIdentityProviderTest/fail_to_authenticate_when_not_allowed_to_sign_up.html +++ /dev/null @@ -1,39 +0,0 @@ - - - - - - fail_to_authenticate_when_not_allowed_to_sign_up - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
french
open/sessions/new
waitForTextcontent*Log in with Fake base identity provider*
clickcss=.oauth-providers a
waitForTextbd*You're not authorized to access this page. Please contact the administrator.*Reason: 'fake-base-id-provider' users are not allowed to sign up*
- - diff --git a/tests/src/test/resources/user/BaseIdentityProviderTest/fail_when_email_already_exists.html b/tests/src/test/resources/user/BaseIdentityProviderTest/fail_when_email_already_exists.html deleted file mode 100644 index b6f7e600ac3..00000000000 --- a/tests/src/test/resources/user/BaseIdentityProviderTest/fail_when_email_already_exists.html +++ /dev/null @@ -1,44 +0,0 @@ - - - - - - fail_when_email_already_exists - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
french
open/sessions/new
waitForTextcontent*Log in with Fake base identity provider*
clickcss=.oauth-providers a
waitForTextbd*You're not authorized to access this page. Please contact the administrator.*
assertTextbd*You can't sign up because email 'john@email.com' is already used by an existing user. This means that you probably already registered with another account*
- - diff --git a/tests/src/test/resources/user/ExternalAuthenticationTest/external-user-details.html b/tests/src/test/resources/user/ExternalAuthenticationTest/external-user-details.html deleted file mode 100644 index 4b540f77943..00000000000 --- a/tests/src/test/resources/user/ExternalAuthenticationTest/external-user-details.html +++ /dev/null @@ -1,64 +0,0 @@ - - - - - - external_user_details - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
external_user_details
open/sessions/new
typelogintester
typepassword123
clickAndWait[type=submit]
waitForElementPresentcss=.js-user-authenticated
open/account/
waitForTextlogintester
waitForTextid=nameTester Testerovich
waitForTextid=emailtester@example.org
- - diff --git a/tests/src/test/resources/user/ExternalAuthenticationTest/external-user-details2.html b/tests/src/test/resources/user/ExternalAuthenticationTest/external-user-details2.html deleted file mode 100644 index b83aa73edfb..00000000000 --- a/tests/src/test/resources/user/ExternalAuthenticationTest/external-user-details2.html +++ /dev/null @@ -1,64 +0,0 @@ - - - - - - external_user_details - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
external_user_details
open/sessions/new
typelogintester
typepassword123
clickAndWait[type=submit]
waitForElementPresentcss=.js-user-authenticated
open/account
waitForTextlogintester
waitForTextid=nameTester2 Testerovich
waitForTextid=emailtester2@example.org
- - diff --git a/tests/src/test/resources/user/OAuth2IdentityProviderTest/display_message_in_ui_but_not_in_log_when_unauthorized_exception.html b/tests/src/test/resources/user/OAuth2IdentityProviderTest/display_message_in_ui_but_not_in_log_when_unauthorized_exception.html deleted file mode 100644 index a78424c7a91..00000000000 --- a/tests/src/test/resources/user/OAuth2IdentityProviderTest/display_message_in_ui_but_not_in_log_when_unauthorized_exception.html +++ /dev/null @@ -1,44 +0,0 @@ - - - - - - fail_to_authenticate_when_not_allowed_to_sign_up - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
french
open/sessions/new
waitForTextcontent*Log in with Fake oauth2 identity provider*
clickcss=.oauth-providers a
waitForTextbd*You're not authorized to access this page. Please contact the administrator.*
assertTextbd*Reason: A functional error has happened*
- - diff --git a/tests/src/test/resources/user/OAuth2IdentityProviderTest/display_unauthorized_page_when_authentication_failed.html b/tests/src/test/resources/user/OAuth2IdentityProviderTest/display_unauthorized_page_when_authentication_failed.html deleted file mode 100644 index b01d24aad4c..00000000000 --- a/tests/src/test/resources/user/OAuth2IdentityProviderTest/display_unauthorized_page_when_authentication_failed.html +++ /dev/null @@ -1,39 +0,0 @@ - - - - - - display_unauthorized_page_when_authentication_failed - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
french
open/sessions/new
waitForTextcontent*Log in with Fake oauth2 identity provider*
clickcss=.oauth-providers a
waitForTextbd*You're not authorized to access this page. Please contact the administrator.*
- - diff --git a/tests/src/test/resources/user/OAuth2IdentityProviderTest/fail_to_authenticate_when_not_allowed_to_sign_up.html b/tests/src/test/resources/user/OAuth2IdentityProviderTest/fail_to_authenticate_when_not_allowed_to_sign_up.html deleted file mode 100644 index addc1e7818b..00000000000 --- a/tests/src/test/resources/user/OAuth2IdentityProviderTest/fail_to_authenticate_when_not_allowed_to_sign_up.html +++ /dev/null @@ -1,39 +0,0 @@ - - - - - - fail_to_authenticate_when_not_allowed_to_sign_up - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
french
open/sessions/new
waitForTextcontent*Log in with Fake oauth2 identity provider*
clickcss=.oauth-providers a
waitForTextbd*You're not authorized to access this page. Please contact the administrator.*Reason: 'fake-oauth2-id-provider' users are not allowed to sign up*
- - -- 2.39.5