From 69cde7c085be98494f81aaa5dae998a26132bc88 Mon Sep 17 00:00:00 2001 From: Jacek Date: Wed, 7 Jul 2021 13:37:17 +0200 Subject: [PATCH] SONAR-15137 Prevent users from associating their account with a new identity provider (cherry picked from commit aa293bae8cf08737d0e3dc856f40847021fad514) --- .../components/EmailAlreadyExists.tsx | 142 ------------------ .../__tests__/EmailAlreadyExists-test.tsx | 59 -------- .../EmailAlreadyExists-test.tsx.snap | 118 --------------- .../src/main/js/apps/sessions/routes.ts | 4 - .../authentication/BaseContextFactory.java | 2 - .../CredentialsExternalAuthentication.java | 2 - .../HttpHeadersAuthentication.java | 2 - .../server/authentication/InitFilter.java | 6 - .../OAuth2AuthenticationParameters.java | 4 - .../OAuth2AuthenticationParametersImpl.java | 22 --- .../authentication/OAuth2CallbackFilter.java | 6 - .../authentication/OAuth2ContextFactory.java | 3 - .../authentication/UserRegistrarImpl.java | 23 +-- .../authentication/UserRegistration.java | 34 ----- ...mailAlreadyExistsRedirectionException.java | 73 --------- ...CredentialsExternalAuthenticationTest.java | 2 - .../server/authentication/InitFilterTest.java | 44 ------ ...Auth2AuthenticationParametersImplTest.java | 54 +------ .../OAuth2CallbackFilterTest.java | 42 ------ .../OAuth2ContextFactoryTest.java | 23 --- .../authentication/UserRegistrarImplTest.java | 133 ++-------------- .../resources/org/sonar/l10n/core.properties | 7 - 22 files changed, 21 insertions(+), 784 deletions(-) delete mode 100644 server/sonar-web/src/main/js/apps/sessions/components/EmailAlreadyExists.tsx delete mode 100644 server/sonar-web/src/main/js/apps/sessions/components/__tests__/EmailAlreadyExists-test.tsx delete mode 100644 server/sonar-web/src/main/js/apps/sessions/components/__tests__/__snapshots__/EmailAlreadyExists-test.tsx.snap delete mode 100644 server/sonar-webserver-auth/src/main/java/org/sonar/server/authentication/exception/EmailAlreadyExistsRedirectionException.java diff --git a/server/sonar-web/src/main/js/apps/sessions/components/EmailAlreadyExists.tsx b/server/sonar-web/src/main/js/apps/sessions/components/EmailAlreadyExists.tsx deleted file mode 100644 index 08d5157a1ba..00000000000 --- a/server/sonar-web/src/main/js/apps/sessions/components/EmailAlreadyExists.tsx +++ /dev/null @@ -1,142 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2021 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. - */ -import * as React from 'react'; -import { FormattedMessage } from 'react-intl'; -import { Alert } from 'sonar-ui-common/components/ui/Alert'; -import { getTextColor } from 'sonar-ui-common/helpers/colors'; -import { getCookie } from 'sonar-ui-common/helpers/cookies'; -import { translate } from 'sonar-ui-common/helpers/l10n'; -import { getBaseUrl } from 'sonar-ui-common/helpers/urls'; -import { getIdentityProviders } from '../../../api/users'; -import { colors } from '../../../app/theme'; - -interface State { - identityProviders: T.IdentityProvider[]; -} - -export default class EmailAlreadyExists extends React.PureComponent<{}, State> { - mounted = false; - state: State = { identityProviders: [] }; - - componentDidMount() { - this.mounted = true; - this.fetchIdentityProviders(); - } - - componentWillUnmount() { - this.mounted = false; - } - - fetchIdentityProviders = () => { - getIdentityProviders().then( - ({ identityProviders }) => { - if (this.mounted) { - this.setState({ identityProviders }); - } - }, - () => {} - ); - }; - - getAuthError = (): { - email?: string; - login?: string; - provider?: string; - existingLogin?: string; - existingProvider?: string; - } => { - const cookie = getCookie('AUTHENTICATION-ERROR'); - if (cookie) { - return JSON.parse(decodeURIComponent(cookie)); - } - return {}; - }; - - renderIdentityProvier = (provider?: string, login?: string) => { - const identityProvider = this.state.identityProviders.find(p => p.key === provider); - - return identityProvider ? ( -
- {identityProvider.name} - {login} -
- ) : ( -
- {provider !== 'sonarqube' && provider} {login} -
- ); - }; - - render() { - const authError = this.getAuthError(); - return ( -
-
-
-

- {authError.email} }} - /> -

- {this.renderIdentityProvier(authError.existingProvider, authError.existingLogin)} -
- -
-

{translate('sessions.email_already_exists.2')}

- {this.renderIdentityProvier(authError.provider, authError.login)} -
- - - {translate('sessions.email_already_exists.3')} -
    -
  • {translate('sessions.email_already_exists.4')}
  • -
  • {translate('sessions.email_already_exists.5')}
  • -
  • {translate('sessions.email_already_exists.6')}
  • -
-
- -
- - {translate('continue')} - - - {translate('cancel')} - -
-
-
- ); - } -} diff --git a/server/sonar-web/src/main/js/apps/sessions/components/__tests__/EmailAlreadyExists-test.tsx b/server/sonar-web/src/main/js/apps/sessions/components/__tests__/EmailAlreadyExists-test.tsx deleted file mode 100644 index 411c33384bc..00000000000 --- a/server/sonar-web/src/main/js/apps/sessions/components/__tests__/EmailAlreadyExists-test.tsx +++ /dev/null @@ -1,59 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2021 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. - */ -import { shallow } from 'enzyme'; -import * as React from 'react'; -import { waitAndUpdate } from 'sonar-ui-common/helpers/testUtils'; -import EmailAlreadyExists from '../EmailAlreadyExists'; - -jest.mock('../../../../api/users', () => ({ - getIdentityProviders: () => - Promise.resolve({ - identityProviders: [ - { - key: 'bitbucket', - name: 'Bitbucket', - iconPath: '/static/authbitbucket/bitbucket.svg', - backgroundColor: '#0052cc' - }, - { - key: 'github', - name: 'GitHub', - iconPath: '/static/authgithub/github.svg', - backgroundColor: '#444444' - } - ] - }) -})); - -jest.mock('sonar-ui-common/helpers/cookies', () => ({ - getCookie: jest - .fn() - .mockReturnValue( - '%7B%22email%22%3A%22mail%40example.com%22%2C%22login%22%3A%22foo%22%2C%22provider%22%3A%22github%22%2C%22existingLogin%22%3A%22bar%22%2C%22existingProvider%22%3A%22bitbucket%22%7D' - ) -})); - -it('render', async () => { - const wrapper = shallow(); - (wrapper.instance() as EmailAlreadyExists).mounted = true; - (wrapper.instance() as EmailAlreadyExists).fetchIdentityProviders(); - await waitAndUpdate(wrapper); - expect(wrapper).toMatchSnapshot(); -}); diff --git a/server/sonar-web/src/main/js/apps/sessions/components/__tests__/__snapshots__/EmailAlreadyExists-test.tsx.snap b/server/sonar-web/src/main/js/apps/sessions/components/__tests__/__snapshots__/EmailAlreadyExists-test.tsx.snap deleted file mode 100644 index 26c56ed365c..00000000000 --- a/server/sonar-web/src/main/js/apps/sessions/components/__tests__/__snapshots__/EmailAlreadyExists-test.tsx.snap +++ /dev/null @@ -1,118 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`render 1`] = ` -
-
-
-

- - mail@example.com - , - } - } - /> -

-
- Bitbucket - bar -
-
-
-

- sessions.email_already_exists.2 -

-
- GitHub - foo -
-
- - sessions.email_already_exists.3 -
    -
  • - sessions.email_already_exists.4 -
  • -
  • - sessions.email_already_exists.5 -
  • -
  • - sessions.email_already_exists.6 -
  • -
-
-
- - continue - - - cancel - -
-
-
-`; diff --git a/server/sonar-web/src/main/js/apps/sessions/routes.ts b/server/sonar-web/src/main/js/apps/sessions/routes.ts index f3197bbb219..ec67f583593 100644 --- a/server/sonar-web/src/main/js/apps/sessions/routes.ts +++ b/server/sonar-web/src/main/js/apps/sessions/routes.ts @@ -31,10 +31,6 @@ const routes = [ { path: 'unauthorized', component: lazyLoadComponent(() => import('./components/Unauthorized')) - }, - { - path: 'email_already_exists', - component: lazyLoadComponent(() => import('./components/EmailAlreadyExists')) } ]; diff --git a/server/sonar-webserver-auth/src/main/java/org/sonar/server/authentication/BaseContextFactory.java b/server/sonar-webserver-auth/src/main/java/org/sonar/server/authentication/BaseContextFactory.java index 011e13f6cb7..2466985f22d 100644 --- a/server/sonar-webserver-auth/src/main/java/org/sonar/server/authentication/BaseContextFactory.java +++ b/server/sonar-webserver-auth/src/main/java/org/sonar/server/authentication/BaseContextFactory.java @@ -25,7 +25,6 @@ import org.sonar.api.platform.Server; import org.sonar.api.server.authentication.BaseIdentityProvider; import org.sonar.api.server.authentication.UserIdentity; import org.sonar.db.user.UserDto; -import org.sonar.server.authentication.UserRegistration.ExistingEmailStrategy; import org.sonar.server.authentication.event.AuthenticationEvent.Source; import org.sonar.server.user.ThreadLocalUserSession; import org.sonar.server.user.UserSessionFactory; @@ -84,7 +83,6 @@ public class BaseContextFactory { .setUserIdentity(userIdentity) .setProvider(identityProvider) .setSource(Source.external(identityProvider)) - .setExistingEmailStrategy(ExistingEmailStrategy.FORBID) .build()); jwtHttpHandler.generateToken(userDto, request, response); threadLocalUserSession.set(userSessionFactory.create(userDto)); diff --git a/server/sonar-webserver-auth/src/main/java/org/sonar/server/authentication/CredentialsExternalAuthentication.java b/server/sonar-webserver-auth/src/main/java/org/sonar/server/authentication/CredentialsExternalAuthentication.java index 85aa225f746..4a1780fccdd 100644 --- a/server/sonar-webserver-auth/src/main/java/org/sonar/server/authentication/CredentialsExternalAuthentication.java +++ b/server/sonar-webserver-auth/src/main/java/org/sonar/server/authentication/CredentialsExternalAuthentication.java @@ -37,7 +37,6 @@ import org.sonar.api.server.authentication.UserIdentity; import org.sonar.api.utils.log.Logger; import org.sonar.api.utils.log.Loggers; import org.sonar.db.user.UserDto; -import org.sonar.server.authentication.UserRegistration.ExistingEmailStrategy; import org.sonar.server.authentication.event.AuthenticationEvent; import org.sonar.server.authentication.event.AuthenticationEvent.Source; import org.sonar.server.authentication.event.AuthenticationException; @@ -146,7 +145,6 @@ public class CredentialsExternalAuthentication implements Startable { .setUserIdentity(userIdentityBuilder.build()) .setProvider(new ExternalIdentityProvider()) .setSource(realmEventSource(method)) - .setExistingEmailStrategy(ExistingEmailStrategy.FORBID) .build()); } diff --git a/server/sonar-webserver-auth/src/main/java/org/sonar/server/authentication/HttpHeadersAuthentication.java b/server/sonar-webserver-auth/src/main/java/org/sonar/server/authentication/HttpHeadersAuthentication.java index 2e367ecd799..fdbcba6864e 100644 --- a/server/sonar-webserver-auth/src/main/java/org/sonar/server/authentication/HttpHeadersAuthentication.java +++ b/server/sonar-webserver-auth/src/main/java/org/sonar/server/authentication/HttpHeadersAuthentication.java @@ -42,7 +42,6 @@ import org.sonar.api.utils.log.Logger; import org.sonar.api.utils.log.Loggers; import org.sonar.db.user.UserDto; import org.sonar.process.ProcessProperties; -import org.sonar.server.authentication.UserRegistration.ExistingEmailStrategy; import org.sonar.server.authentication.event.AuthenticationEvent; import org.sonar.server.authentication.event.AuthenticationEvent.Source; import org.sonar.server.authentication.event.AuthenticationException; @@ -169,7 +168,6 @@ public class HttpHeadersAuthentication implements Startable { .setUserIdentity(userIdentityBuilder.build()) .setProvider(new SsoIdentityProvider()) .setSource(Source.sso()) - .setExistingEmailStrategy(ExistingEmailStrategy.FORBID) .build()); } diff --git a/server/sonar-webserver-auth/src/main/java/org/sonar/server/authentication/InitFilter.java b/server/sonar-webserver-auth/src/main/java/org/sonar/server/authentication/InitFilter.java index 496c4bdaef4..33eadc4ccc9 100644 --- a/server/sonar-webserver-auth/src/main/java/org/sonar/server/authentication/InitFilter.java +++ b/server/sonar-webserver-auth/src/main/java/org/sonar/server/authentication/InitFilter.java @@ -31,12 +31,10 @@ import org.sonar.api.server.authentication.OAuth2IdentityProvider; import org.sonar.api.server.authentication.UnauthorizedException; import org.sonar.server.authentication.event.AuthenticationEvent; import org.sonar.server.authentication.event.AuthenticationException; -import org.sonar.server.authentication.exception.EmailAlreadyExistsRedirectionException; import static java.lang.String.format; import static org.sonar.server.authentication.AuthenticationError.handleAuthenticationError; import static org.sonar.server.authentication.AuthenticationError.handleError; -import static org.sonar.server.authentication.AuthenticationRedirection.redirectTo; import static org.sonar.server.authentication.event.AuthenticationEvent.Source; public class InitFilter extends AuthenticationFilter { @@ -83,10 +81,6 @@ public class InitFilter extends AuthenticationFilter { } else { handleError(request, response, format("Unsupported IdentityProvider class: %s", provider.getClass())); } - } catch (EmailAlreadyExistsRedirectionException e) { - oAuthOAuth2AuthenticationParameters.delete(request, response); - e.addCookie(request, response); - redirectTo(response, e.getPath(request.getContextPath())); } catch (AuthenticationException e) { oAuthOAuth2AuthenticationParameters.delete(request, response); authenticationEvent.loginFailure(request, e); diff --git a/server/sonar-webserver-auth/src/main/java/org/sonar/server/authentication/OAuth2AuthenticationParameters.java b/server/sonar-webserver-auth/src/main/java/org/sonar/server/authentication/OAuth2AuthenticationParameters.java index 5575f5ec94d..2dfdde2d9fa 100644 --- a/server/sonar-webserver-auth/src/main/java/org/sonar/server/authentication/OAuth2AuthenticationParameters.java +++ b/server/sonar-webserver-auth/src/main/java/org/sonar/server/authentication/OAuth2AuthenticationParameters.java @@ -37,10 +37,6 @@ public interface OAuth2AuthenticationParameters { Optional getReturnTo(HttpServletRequest request); - Optional getAllowEmailShift(HttpServletRequest request); - - Optional getAllowUpdateLogin(HttpServletRequest request); - void delete(HttpServletRequest request, HttpServletResponse response); } diff --git a/server/sonar-webserver-auth/src/main/java/org/sonar/server/authentication/OAuth2AuthenticationParametersImpl.java b/server/sonar-webserver-auth/src/main/java/org/sonar/server/authentication/OAuth2AuthenticationParametersImpl.java index b6ee5091abb..207d2736f27 100644 --- a/server/sonar-webserver-auth/src/main/java/org/sonar/server/authentication/OAuth2AuthenticationParametersImpl.java +++ b/server/sonar-webserver-auth/src/main/java/org/sonar/server/authentication/OAuth2AuthenticationParametersImpl.java @@ -36,7 +36,6 @@ import javax.servlet.http.HttpServletResponse; import static java.net.URLDecoder.decode; import static java.nio.charset.StandardCharsets.UTF_8; import static java.util.Optional.empty; -import static org.apache.commons.lang.StringUtils.isNotBlank; import static org.sonar.server.authentication.AuthenticationRedirection.encodeMessage; import static org.sonar.server.authentication.Cookies.findCookie; import static org.sonar.server.authentication.Cookies.newCookieBuilder; @@ -53,11 +52,6 @@ public class OAuth2AuthenticationParametersImpl implements OAuth2AuthenticationP */ private static final String RETURN_TO_PARAMETER = "return_to"; - /** - * This parameter is used to allow the shift of email from an existing user to the authenticating user - */ - private static final String ALLOW_EMAIL_SHIFT_PARAMETER = "allowEmailShift"; - /** * This parameter is used to allow the update of login */ @@ -69,13 +63,9 @@ public class OAuth2AuthenticationParametersImpl implements OAuth2AuthenticationP @Override public void init(HttpServletRequest request, HttpServletResponse response) { String returnTo = request.getParameter(RETURN_TO_PARAMETER); - String allowEmailShift = request.getParameter(ALLOW_EMAIL_SHIFT_PARAMETER); Map parameters = new HashMap<>(); Optional sanitizeRedirectUrl = sanitizeRedirectUrl(returnTo); sanitizeRedirectUrl.ifPresent(s -> parameters.put(RETURN_TO_PARAMETER, s)); - if (isNotBlank(allowEmailShift)) { - parameters.put(ALLOW_EMAIL_SHIFT_PARAMETER, allowEmailShift); - } if (parameters.isEmpty()) { return; } @@ -93,18 +83,6 @@ public class OAuth2AuthenticationParametersImpl implements OAuth2AuthenticationP .flatMap(OAuth2AuthenticationParametersImpl::sanitizeRedirectUrl); } - @Override - public Optional getAllowEmailShift(HttpServletRequest request) { - Optional parameter = getParameter(request, ALLOW_EMAIL_SHIFT_PARAMETER); - return parameter.map(Boolean::parseBoolean); - } - - @Override - public Optional getAllowUpdateLogin(HttpServletRequest request) { - Optional parameter = getParameter(request, ALLOW_LOGIN_UPDATE_PARAMETER); - return parameter.map(Boolean::parseBoolean); - } - private static Optional getParameter(HttpServletRequest request, String parameterKey) { Optional cookie = findCookie(AUTHENTICATION_COOKIE_NAME, request); if (!cookie.isPresent()) { diff --git a/server/sonar-webserver-auth/src/main/java/org/sonar/server/authentication/OAuth2CallbackFilter.java b/server/sonar-webserver-auth/src/main/java/org/sonar/server/authentication/OAuth2CallbackFilter.java index e32e6425d2d..25490db8aa8 100644 --- a/server/sonar-webserver-auth/src/main/java/org/sonar/server/authentication/OAuth2CallbackFilter.java +++ b/server/sonar-webserver-auth/src/main/java/org/sonar/server/authentication/OAuth2CallbackFilter.java @@ -30,13 +30,11 @@ import org.sonar.api.server.authentication.OAuth2IdentityProvider; import org.sonar.api.server.authentication.UnauthorizedException; import org.sonar.server.authentication.event.AuthenticationEvent; import org.sonar.server.authentication.event.AuthenticationException; -import org.sonar.server.authentication.exception.EmailAlreadyExistsRedirectionException; import org.sonar.server.user.ThreadLocalUserSession; import static java.lang.String.format; import static org.sonar.server.authentication.AuthenticationError.handleAuthenticationError; import static org.sonar.server.authentication.AuthenticationError.handleError; -import static org.sonar.server.authentication.AuthenticationRedirection.redirectTo; import static org.sonar.server.authentication.event.AuthenticationEvent.Source; public class OAuth2CallbackFilter extends AuthenticationFilter { @@ -78,10 +76,6 @@ public class OAuth2CallbackFilter extends AuthenticationFilter { } else { handleError(request, response, format("Not an OAuth2IdentityProvider: %s", provider.getClass())); } - } catch (EmailAlreadyExistsRedirectionException e) { - oauth2Parameters.delete(request, response); - e.addCookie(request, response); - redirectTo(response, e.getPath(request.getContextPath())); } catch (AuthenticationException e) { oauth2Parameters.delete(request, response); authenticationEvent.loginFailure(request, e); diff --git a/server/sonar-webserver-auth/src/main/java/org/sonar/server/authentication/OAuth2ContextFactory.java b/server/sonar-webserver-auth/src/main/java/org/sonar/server/authentication/OAuth2ContextFactory.java index 915257bb2d4..0299db307ae 100644 --- a/server/sonar-webserver-auth/src/main/java/org/sonar/server/authentication/OAuth2ContextFactory.java +++ b/server/sonar-webserver-auth/src/main/java/org/sonar/server/authentication/OAuth2ContextFactory.java @@ -30,7 +30,6 @@ import org.sonar.api.server.ServerSide; import org.sonar.api.server.authentication.OAuth2IdentityProvider; import org.sonar.api.server.authentication.UserIdentity; import org.sonar.db.user.UserDto; -import org.sonar.server.authentication.UserRegistration.ExistingEmailStrategy; import org.sonar.server.authentication.event.AuthenticationEvent; import org.sonar.server.user.ThreadLocalUserSession; import org.sonar.server.user.UserSessionFactory; @@ -137,13 +136,11 @@ public class OAuth2ContextFactory { @Override public void authenticate(UserIdentity userIdentity, @Nullable Set organizationAlmIds) { - Boolean allowEmailShift = oAuthParameters.getAllowEmailShift(request).orElse(false); UserDto userDto = userRegistrar.register( UserRegistration.builder() .setUserIdentity(userIdentity) .setProvider(identityProvider) .setSource(AuthenticationEvent.Source.oauth2(identityProvider)) - .setExistingEmailStrategy(allowEmailShift ? ExistingEmailStrategy.ALLOW : ExistingEmailStrategy.WARN) .setOrganizationAlmIds(organizationAlmIds) .build()); jwtHttpHandler.generateToken(userDto, request, response); diff --git a/server/sonar-webserver-auth/src/main/java/org/sonar/server/authentication/UserRegistrarImpl.java b/server/sonar-webserver-auth/src/main/java/org/sonar/server/authentication/UserRegistrarImpl.java index 5fd6d5b5919..e98100e99d7 100644 --- a/server/sonar-webserver-auth/src/main/java/org/sonar/server/authentication/UserRegistrarImpl.java +++ b/server/sonar-webserver-auth/src/main/java/org/sonar/server/authentication/UserRegistrarImpl.java @@ -40,9 +40,7 @@ import org.sonar.db.DbSession; import org.sonar.db.user.GroupDto; import org.sonar.db.user.UserDto; import org.sonar.db.user.UserGroupDto; -import org.sonar.server.authentication.UserRegistration.ExistingEmailStrategy; import org.sonar.server.authentication.event.AuthenticationException; -import org.sonar.server.authentication.exception.EmailAlreadyExistsRedirectionException; import org.sonar.server.user.ExternalIdentity; import org.sonar.server.user.NewUser; import org.sonar.server.user.UpdateUser; @@ -136,19 +134,7 @@ public class UserRegistrarImpl implements UserRegistrar { if (existingUser == null || isSameUser(existingUser, authenticatorParameters)) { return Optional.empty(); } - ExistingEmailStrategy existingEmailStrategy = authenticatorParameters.getExistingEmailStrategy(); - switch (existingEmailStrategy) { - case ALLOW: - existingUser.setEmail(null); - dbClient.userDao().update(dbSession, existingUser); - return Optional.of(existingUser); - case WARN: - throw new EmailAlreadyExistsRedirectionException(email, existingUser, authenticatorParameters.getUserIdentity(), authenticatorParameters.getProvider()); - case FORBID: - throw generateExistingEmailError(authenticatorParameters, email); - default: - throw new IllegalStateException(format("Unknown strategy %s", existingEmailStrategy)); - } + throw generateExistingEmailError(authenticatorParameters, email); } private static boolean isSameUser(UserDto existingUser, UserRegistration authenticatorParameters) { @@ -236,9 +222,10 @@ public class UserRegistrarImpl implements UserRegistrar { .setSource(authenticatorParameters.getSource()) .setLogin(authenticatorParameters.getUserIdentity().getProviderLogin()) .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)) + .setPublicMessage( + "This account is already associated with another authentication method. " + + "Sign in using the current authentication method, " + + "or contact your administrator to transfer your account to a different authentication method.") .build(); } diff --git a/server/sonar-webserver-auth/src/main/java/org/sonar/server/authentication/UserRegistration.java b/server/sonar-webserver-auth/src/main/java/org/sonar/server/authentication/UserRegistration.java index cd3144532d7..249316e5a74 100644 --- a/server/sonar-webserver-auth/src/main/java/org/sonar/server/authentication/UserRegistration.java +++ b/server/sonar-webserver-auth/src/main/java/org/sonar/server/authentication/UserRegistration.java @@ -30,35 +30,15 @@ import static java.util.Objects.requireNonNull; class UserRegistration { - /** - * Strategy to be executed when the email of the user is already used by another user - */ - enum ExistingEmailStrategy { - /** - * Authentication is allowed, the email is moved from other user to current user - */ - ALLOW, - /** - * Authentication process is stopped, the user is redirected to a page explaining that the email is already used - */ - WARN, - /** - * Forbid authentication of the user - */ - FORBID - } - private final UserIdentity userIdentity; private final IdentityProvider provider; private final AuthenticationEvent.Source source; - private final ExistingEmailStrategy existingEmailStrategy; private final Set organizationAlmIds; UserRegistration(Builder builder) { this.userIdentity = builder.userIdentity; this.provider = builder.provider; this.source = builder.source; - this.existingEmailStrategy = builder.existingEmailStrategy; this.organizationAlmIds = builder.organizationAlmIds; } @@ -74,10 +54,6 @@ class UserRegistration { return source; } - public ExistingEmailStrategy getExistingEmailStrategy() { - return existingEmailStrategy; - } - @CheckForNull public Set getOrganizationAlmIds() { return organizationAlmIds; @@ -91,7 +67,6 @@ class UserRegistration { private UserIdentity userIdentity; private IdentityProvider provider; private AuthenticationEvent.Source source; - private ExistingEmailStrategy existingEmailStrategy; private Set organizationAlmIds; public Builder setUserIdentity(UserIdentity userIdentity) { @@ -109,14 +84,6 @@ class UserRegistration { return this; } - /** - * Strategy to be executed when the email of the user is already used by another user - */ - public Builder setExistingEmailStrategy(ExistingEmailStrategy existingEmailStrategy) { - this.existingEmailStrategy = existingEmailStrategy; - return this; - } - /** * List of ALM organization the user is member of. * When set to null, it means that no organization membership synchronization should be done. @@ -130,7 +97,6 @@ class UserRegistration { requireNonNull(userIdentity, "userIdentity must be set"); requireNonNull(provider, "identityProvider must be set"); requireNonNull(source, "Source must be set"); - requireNonNull(existingEmailStrategy, "existingEmailStrategy must be set "); return new UserRegistration(this); } } diff --git a/server/sonar-webserver-auth/src/main/java/org/sonar/server/authentication/exception/EmailAlreadyExistsRedirectionException.java b/server/sonar-webserver-auth/src/main/java/org/sonar/server/authentication/exception/EmailAlreadyExistsRedirectionException.java deleted file mode 100644 index 4a145413f68..00000000000 --- a/server/sonar-webserver-auth/src/main/java/org/sonar/server/authentication/exception/EmailAlreadyExistsRedirectionException.java +++ /dev/null @@ -1,73 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2021 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.sonar.server.authentication.exception; - -import com.google.common.collect.ImmutableMap; -import com.google.gson.Gson; -import com.google.gson.GsonBuilder; -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; -import org.sonar.api.server.authentication.IdentityProvider; -import org.sonar.api.server.authentication.UserIdentity; -import org.sonar.db.user.UserDto; - -import static org.sonar.server.authentication.AuthenticationError.addErrorCookie; - -/** - * This exception is used to redirect the user to a page explaining him that his email is already used by another account, - * and where he has the ability to authenticate by "steeling" this email. - */ -public class EmailAlreadyExistsRedirectionException extends RedirectionException { - - private static final String PATH = "/sessions/email_already_exists"; - private static final String EMAIL_FIELD = "email"; - private static final String LOGIN_FIELD = "login"; - private static final String PROVIDER_FIELD = "provider"; - private static final String EXISTING_LOGIN_FIELD = "existingLogin"; - private static final String EXISTING_PROVIDER_FIELD = "existingProvider"; - - private final String email; - private final UserDto existingUser; - private final UserIdentity userIdentity; - private final IdentityProvider provider; - - public EmailAlreadyExistsRedirectionException(String email, UserDto existingUser, UserIdentity userIdentity, IdentityProvider provider) { - this.email = email; - this.existingUser = existingUser; - this.userIdentity = userIdentity; - this.provider = provider; - } - - public void addCookie(HttpServletRequest request, HttpServletResponse response) { - Gson gson = new GsonBuilder().create(); - String message = gson.toJson(ImmutableMap.of( - EMAIL_FIELD, email, - LOGIN_FIELD, userIdentity.getProviderLogin(), - PROVIDER_FIELD, provider.getKey(), - EXISTING_LOGIN_FIELD, existingUser.getExternalLogin(), - EXISTING_PROVIDER_FIELD, existingUser.getExternalIdentityProvider())); - addErrorCookie(request, response, message); - } - - @Override - public String getPath(String contextPath) { - return contextPath + PATH; - } -} diff --git a/server/sonar-webserver-auth/src/test/java/org/sonar/server/authentication/CredentialsExternalAuthenticationTest.java b/server/sonar-webserver-auth/src/test/java/org/sonar/server/authentication/CredentialsExternalAuthenticationTest.java index d336ff32970..61074bea768 100644 --- a/server/sonar-webserver-auth/src/test/java/org/sonar/server/authentication/CredentialsExternalAuthenticationTest.java +++ b/server/sonar-webserver-auth/src/test/java/org/sonar/server/authentication/CredentialsExternalAuthenticationTest.java @@ -44,7 +44,6 @@ import static org.mockito.Mockito.verify; import static org.mockito.Mockito.verifyNoMoreInteractions; import static org.mockito.Mockito.verifyZeroInteractions; import static org.mockito.Mockito.when; -import static org.sonar.server.authentication.UserRegistration.ExistingEmailStrategy.FORBID; import static org.sonar.server.authentication.event.AuthenticationEvent.Method.BASIC; import static org.sonar.server.authentication.event.AuthenticationEvent.Method.BASIC_TOKEN; import static org.sonar.server.authentication.event.AuthenticationExceptionMatcher.authenticationException; @@ -91,7 +90,6 @@ public class CredentialsExternalAuthenticationTest { underTest.authenticate(new Credentials(LOGIN, PASSWORD), request, BASIC); assertThat(userIdentityAuthenticator.isAuthenticated()).isTrue(); - assertThat(userIdentityAuthenticator.getAuthenticatorParameters().getExistingEmailStrategy()).isEqualTo(FORBID); assertThat(userIdentityAuthenticator.getAuthenticatorParameters().getUserIdentity().getProviderLogin()).isEqualTo(LOGIN); assertThat(userIdentityAuthenticator.getAuthenticatorParameters().getUserIdentity().getProviderId()).isNull(); assertThat(userIdentityAuthenticator.getAuthenticatorParameters().getUserIdentity().getName()).isEqualTo("name"); diff --git a/server/sonar-webserver-auth/src/test/java/org/sonar/server/authentication/InitFilterTest.java b/server/sonar-webserver-auth/src/test/java/org/sonar/server/authentication/InitFilterTest.java index b65f067eebb..1a450e5f9e4 100644 --- a/server/sonar-webserver-auth/src/test/java/org/sonar/server/authentication/InitFilterTest.java +++ b/server/sonar-webserver-auth/src/test/java/org/sonar/server/authentication/InitFilterTest.java @@ -33,13 +33,10 @@ import org.sonar.api.server.authentication.Display; import org.sonar.api.server.authentication.IdentityProvider; import org.sonar.api.server.authentication.OAuth2IdentityProvider; import org.sonar.api.server.authentication.UnauthorizedException; -import org.sonar.api.server.authentication.UserIdentity; import org.sonar.api.utils.log.LogTester; import org.sonar.api.utils.log.LoggerLevel; -import org.sonar.db.user.UserDto; import org.sonar.server.authentication.event.AuthenticationEvent; import org.sonar.server.authentication.event.AuthenticationException; -import org.sonar.server.authentication.exception.EmailAlreadyExistsRedirectionException; import static org.assertj.core.api.Assertions.assertThat; import static org.mockito.ArgumentMatchers.eq; @@ -48,7 +45,6 @@ import static org.mockito.Mockito.never; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.verifyZeroInteractions; import static org.mockito.Mockito.when; -import static org.sonar.db.user.UserTesting.newUserDto; public class InitFilterTest { @@ -225,27 +221,6 @@ public class InitFilterTest { verify(response).sendRedirect("/sonarqube/sessions/unauthorized"); } - @Test - public void redirect_contains_cookie_when_failing_because_of_EmailAlreadyExistException() throws Exception { - UserDto existingUser = newUserDto().setEmail("john@email.com").setExternalLogin("john.bitbucket").setExternalIdentityProvider("bitbucket"); - FailWithEmailAlreadyExistException identityProvider = new FailWithEmailAlreadyExistException("failing", existingUser); - when(request.getRequestURI()).thenReturn("/sessions/init/" + identityProvider.getKey()); - identityProviderRepository.addIdentityProvider(identityProvider); - - underTest.doFilter(request, response, chain); - - verify(response).sendRedirect("/sessions/email_already_exists"); - verify(auth2AuthenticationParameters).delete(eq(request), eq(response)); - verify(response).addCookie(cookieArgumentCaptor.capture()); - Cookie cookie = cookieArgumentCaptor.getValue(); - assertThat(cookie.getName()).isEqualTo("AUTHENTICATION-ERROR"); - assertThat(cookie.getValue()).contains("john%40email.com"); - assertThat(cookie.getPath()).isEqualTo("/"); - assertThat(cookie.isHttpOnly()).isFalse(); - assertThat(cookie.getMaxAge()).isEqualTo(300); - assertThat(cookie.getSecure()).isFalse(); - } - @Test public void redirect_when_failing_because_of_Exception() throws Exception { IdentityProvider identityProvider = new FailWithIllegalStateException("failing"); @@ -315,25 +290,6 @@ public class InitFilterTest { } } - private static class FailWithEmailAlreadyExistException extends FakeBasicIdentityProvider { - - private final UserDto existingUser; - - public FailWithEmailAlreadyExistException(String key, UserDto existingUser) { - super(key, true); - this.existingUser = existingUser; - } - - @Override - public void init(Context context) { - throw new EmailAlreadyExistsRedirectionException(existingUser.getEmail(), existingUser, UserIdentity.builder() - .setProviderLogin("john.github") - .setName(existingUser.getName()) - .setEmail(existingUser.getEmail()) - .build(), this); - } - } - private static class UnsupportedIdentityProvider implements IdentityProvider { private final String unsupportedKey; diff --git a/server/sonar-webserver-auth/src/test/java/org/sonar/server/authentication/OAuth2AuthenticationParametersImplTest.java b/server/sonar-webserver-auth/src/test/java/org/sonar/server/authentication/OAuth2AuthenticationParametersImplTest.java index aae20a5c38f..7ca012795bd 100644 --- a/server/sonar-webserver-auth/src/test/java/org/sonar/server/authentication/OAuth2AuthenticationParametersImplTest.java +++ b/server/sonar-webserver-auth/src/test/java/org/sonar/server/authentication/OAuth2AuthenticationParametersImplTest.java @@ -105,7 +105,7 @@ public class OAuth2AuthenticationParametersImplTest { @Test public void get_return_to_parameter() { - when(request.getCookies()).thenReturn(new Cookie[]{new Cookie(AUTHENTICATION_COOKIE_NAME, "{\"return_to\":\"/settings\"}")}); + when(request.getCookies()).thenReturn(new Cookie[] {new Cookie(AUTHENTICATION_COOKIE_NAME, "{\"return_to\":\"/settings\"}")}); Optional redirection = underTest.getReturnTo(request); @@ -114,7 +114,7 @@ public class OAuth2AuthenticationParametersImplTest { @Test public void get_return_to_is_empty_when_no_cookie() { - when(request.getCookies()).thenReturn(new Cookie[]{}); + when(request.getCookies()).thenReturn(new Cookie[] {}); Optional redirection = underTest.getReturnTo(request); @@ -123,62 +123,16 @@ public class OAuth2AuthenticationParametersImplTest { @Test public void get_return_to_is_empty_when_no_value() { - when(request.getCookies()).thenReturn(new Cookie[]{new Cookie(AUTHENTICATION_COOKIE_NAME, "{}")}); + when(request.getCookies()).thenReturn(new Cookie[] {new Cookie(AUTHENTICATION_COOKIE_NAME, "{}")}); Optional redirection = underTest.getReturnTo(request); assertThat(redirection).isEmpty(); } - @Test - public void get_allowEmailShift_parameter() { - when(request.getCookies()).thenReturn(new Cookie[]{new Cookie(AUTHENTICATION_COOKIE_NAME, "{\"allowEmailShift\":\"true\"}")}); - - Optional allowEmailShift = underTest.getAllowEmailShift(request); - - assertThat(allowEmailShift).isNotEmpty(); - assertThat(allowEmailShift.get()).isTrue(); - } - - @Test - public void get_allowEmailShift_is_empty_when_no_cookie() { - when(request.getCookies()).thenReturn(new Cookie[]{}); - - Optional allowEmailShift = underTest.getAllowEmailShift(request); - - assertThat(allowEmailShift).isEmpty(); - } - - @Test - public void get_allowEmailShift_is_empty_when_no_value() { - when(request.getCookies()).thenReturn(new Cookie[]{new Cookie(AUTHENTICATION_COOKIE_NAME, "{}")}); - - Optional allowEmailShift = underTest.getAllowEmailShift(request); - - assertThat(allowEmailShift).isEmpty(); - } - - @Test - public void getAllowUpdateLogin_is_empty_when_no_cookie() { - when(request.getCookies()).thenReturn(new Cookie[]{}); - - Optional allowLoginUpdate = underTest.getAllowUpdateLogin(request); - - assertThat(allowLoginUpdate).isEmpty(); - } - - @Test - public void getAllowUpdateLogin_is_empty_when_no_value() { - when(request.getCookies()).thenReturn(new Cookie[]{new Cookie(AUTHENTICATION_COOKIE_NAME, "{}")}); - - Optional allowLoginUpdate = underTest.getAllowUpdateLogin(request); - - assertThat(allowLoginUpdate).isEmpty(); - } - @Test public void delete() { - when(request.getCookies()).thenReturn(new Cookie[]{new Cookie(AUTHENTICATION_COOKIE_NAME, "{\"return_to\":\"/settings\"}")}); + when(request.getCookies()).thenReturn(new Cookie[] {new Cookie(AUTHENTICATION_COOKIE_NAME, "{\"return_to\":\"/settings\"}")}); underTest.delete(request, response); diff --git a/server/sonar-webserver-auth/src/test/java/org/sonar/server/authentication/OAuth2CallbackFilterTest.java b/server/sonar-webserver-auth/src/test/java/org/sonar/server/authentication/OAuth2CallbackFilterTest.java index e693f0143c4..6c45615d3bf 100644 --- a/server/sonar-webserver-auth/src/test/java/org/sonar/server/authentication/OAuth2CallbackFilterTest.java +++ b/server/sonar-webserver-auth/src/test/java/org/sonar/server/authentication/OAuth2CallbackFilterTest.java @@ -33,10 +33,8 @@ import org.sonar.api.server.authentication.UnauthorizedException; import org.sonar.api.server.authentication.UserIdentity; import org.sonar.api.utils.log.LogTester; import org.sonar.api.utils.log.LoggerLevel; -import org.sonar.db.user.UserDto; import org.sonar.server.authentication.event.AuthenticationEvent; import org.sonar.server.authentication.event.AuthenticationException; -import org.sonar.server.authentication.exception.EmailAlreadyExistsRedirectionException; import org.sonar.server.user.ThreadLocalUserSession; import static org.assertj.core.api.Assertions.assertThat; @@ -45,7 +43,6 @@ import static org.mockito.Mockito.mock; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.verifyZeroInteractions; import static org.mockito.Mockito.when; -import static org.sonar.db.user.UserTesting.newUserDto; import static org.sonar.server.authentication.event.AuthenticationEvent.Source; public class OAuth2CallbackFilterTest { @@ -221,27 +218,6 @@ public class OAuth2CallbackFilterTest { verify(response).sendRedirect("/sonarqube/sessions/unauthorized"); } - @Test - public void redirect_when_failing_because_of_EmailAlreadyExistException() throws Exception { - UserDto existingUser = newUserDto().setEmail("john@email.com").setExternalLogin("john.bitbucket").setExternalIdentityProvider("bitbucket"); - FailWithEmailAlreadyExistException identityProvider = new FailWithEmailAlreadyExistException(existingUser); - when(request.getRequestURI()).thenReturn("/oauth2/callback/" + identityProvider.getKey()); - identityProviderRepository.addIdentityProvider(identityProvider); - - underTest.doFilter(request, response, chain); - - verify(response).sendRedirect("/sessions/email_already_exists"); - verify(oAuthRedirection).delete(eq(request), eq(response)); - verify(response).addCookie(cookieArgumentCaptor.capture()); - Cookie cookie = cookieArgumentCaptor.getValue(); - assertThat(cookie.getName()).isEqualTo("AUTHENTICATION-ERROR"); - assertThat(cookie.getValue()).contains("john%40email.com"); - assertThat(cookie.getPath()).isEqualTo("/"); - assertThat(cookie.isHttpOnly()).isFalse(); - assertThat(cookie.getMaxAge()).isEqualTo(300); - assertThat(cookie.getSecure()).isFalse(); - } - @Test public void fail_when_no_oauth2_provider_provided() throws Exception { when(request.getRequestURI()).thenReturn("/oauth2/callback"); @@ -277,24 +253,6 @@ public class OAuth2CallbackFilterTest { } } - private static class FailWithEmailAlreadyExistException extends FailingIdentityProvider { - - private final UserDto existingUser; - - public FailWithEmailAlreadyExistException(UserDto existingUser) { - this.existingUser = existingUser; - } - - @Override - public void callback(CallbackContext context) { - throw new EmailAlreadyExistsRedirectionException(existingUser.getEmail(), existingUser, UserIdentity.builder() - .setProviderLogin("john.github") - .setName(existingUser.getName()) - .setEmail(existingUser.getEmail()) - .build(), this); - } - } - private static abstract class FailingIdentityProvider extends TestIdentityProvider implements OAuth2IdentityProvider { FailingIdentityProvider() { this.setKey("failing"); diff --git a/server/sonar-webserver-auth/src/test/java/org/sonar/server/authentication/OAuth2ContextFactoryTest.java b/server/sonar-webserver-auth/src/test/java/org/sonar/server/authentication/OAuth2ContextFactoryTest.java index 4241ed798a7..88bb0e0b719 100644 --- a/server/sonar-webserver-auth/src/test/java/org/sonar/server/authentication/OAuth2ContextFactoryTest.java +++ b/server/sonar-webserver-auth/src/test/java/org/sonar/server/authentication/OAuth2ContextFactoryTest.java @@ -35,7 +35,6 @@ import org.sonar.api.server.authentication.OAuth2IdentityProvider; import org.sonar.api.server.authentication.UserIdentity; import org.sonar.db.user.UserDto; import org.sonar.server.authentication.OAuth2ContextFactory.OAuthContextImpl; -import org.sonar.server.authentication.UserRegistration.ExistingEmailStrategy; import org.sonar.server.user.TestUserSessionFactory; import org.sonar.server.user.ThreadLocalUserSession; import org.sonar.server.user.UserSession; @@ -139,28 +138,6 @@ public class OAuth2ContextFactoryTest { assertThat(userArgumentCaptor.getValue().getExternalIdentityProvider()).isEqualTo(PROVIDER_KEY); } - @Test - public void authenticate_with_allow_email_shift() { - when(oAuthParameters.getAllowEmailShift(request)).thenReturn(Optional.of(true)); - OAuth2IdentityProvider.CallbackContext callback = newCallbackContext(); - - callback.authenticate(USER_IDENTITY); - - assertThat(userIdentityAuthenticator.isAuthenticated()).isTrue(); - assertThat(userIdentityAuthenticator.getAuthenticatorParameters().getExistingEmailStrategy()).isEqualTo(ExistingEmailStrategy.ALLOW); - } - - @Test - public void authenticate_without_email_shift() { - when(oAuthParameters.getAllowEmailShift(request)).thenReturn(Optional.of(false)); - OAuth2IdentityProvider.CallbackContext callback = newCallbackContext(); - - callback.authenticate(USER_IDENTITY); - - assertThat(userIdentityAuthenticator.isAuthenticated()).isTrue(); - assertThat(userIdentityAuthenticator.getAuthenticatorParameters().getExistingEmailStrategy()).isEqualTo(ExistingEmailStrategy.WARN); - } - @Test public void authenticate_with_organization_alm_ids() { OAuthContextImpl callback = (OAuthContextImpl) newCallbackContext(); diff --git a/server/sonar-webserver-auth/src/test/java/org/sonar/server/authentication/UserRegistrarImplTest.java b/server/sonar-webserver-auth/src/test/java/org/sonar/server/authentication/UserRegistrarImplTest.java index 280f8cb5c6c..1ab2f29b662 100644 --- a/server/sonar-webserver-auth/src/test/java/org/sonar/server/authentication/UserRegistrarImplTest.java +++ b/server/sonar-webserver-auth/src/test/java/org/sonar/server/authentication/UserRegistrarImplTest.java @@ -32,10 +32,8 @@ import org.sonar.core.util.stream.MoreCollectors; import org.sonar.db.DbTester; import org.sonar.db.user.GroupDto; import org.sonar.db.user.UserDto; -import org.sonar.server.authentication.UserRegistration.ExistingEmailStrategy; import org.sonar.server.authentication.event.AuthenticationEvent; import org.sonar.server.authentication.event.AuthenticationEvent.Source; -import org.sonar.server.authentication.exception.EmailAlreadyExistsRedirectionException; import org.sonar.server.es.EsTester; import org.sonar.server.user.NewUserNotifier; import org.sonar.server.user.UserUpdater; @@ -47,7 +45,6 @@ import static org.assertj.core.api.Assertions.assertThat; import static org.mockito.Mockito.mock; import static org.sonar.db.user.UserTesting.newUserDto; import static org.sonar.process.ProcessProperties.Property.ONBOARDING_TUTORIAL_SHOW_TO_NEW_USERS; -import static org.sonar.server.authentication.UserRegistration.ExistingEmailStrategy.FORBID; import static org.sonar.server.authentication.event.AuthenticationEvent.Method.BASIC; import static org.sonar.server.authentication.event.AuthenticationExceptionMatcher.authenticationException; @@ -100,7 +97,6 @@ public class UserRegistrarImplTest { .setUserIdentity(USER_IDENTITY) .setProvider(IDENTITY_PROVIDER) .setSource(Source.realm(BASIC, IDENTITY_PROVIDER.getName())) - .setExistingEmailStrategy(ExistingEmailStrategy.FORBID) .build()); UserDto user = db.users().selectUserByLogin(createdUser.getLogin()).get(); @@ -127,7 +123,6 @@ public class UserRegistrarImplTest { .setUserIdentity(USER_IDENTITY) .setProvider(sqIdentityProvider) .setSource(Source.realm(BASIC, sqIdentityProvider.getName())) - .setExistingEmailStrategy(ExistingEmailStrategy.FORBID) .build()); UserDto user = db.users().selectUserByLogin(createdUser.getLogin()).get(); @@ -155,7 +150,6 @@ public class UserRegistrarImplTest { .build()) .setProvider(IDENTITY_PROVIDER) .setSource(Source.realm(BASIC, IDENTITY_PROVIDER.getName())) - .setExistingEmailStrategy(ExistingEmailStrategy.FORBID) .build()); UserDto user = db.getDbClient().userDao().selectByEmail(db.getSession(), "john@email.com").get(0); @@ -199,7 +193,6 @@ public class UserRegistrarImplTest { .setUserIdentity(USER_IDENTITY) .setProvider(IDENTITY_PROVIDER) .setSource(Source.local(BASIC)) - .setExistingEmailStrategy(ExistingEmailStrategy.FORBID) .build()); assertThat(db.users().selectUserByLogin(user.getLogin()).get().isOnboarded()).isFalse(); @@ -213,7 +206,6 @@ public class UserRegistrarImplTest { .setUserIdentity(USER_IDENTITY) .setProvider(IDENTITY_PROVIDER) .setSource(Source.local(BASIC)) - .setExistingEmailStrategy(ExistingEmailStrategy.FORBID) .build()); assertThat(db.users().selectUserByLogin(user.getLogin()).get().isOnboarded()).isTrue(); @@ -231,7 +223,6 @@ public class UserRegistrarImplTest { .setUserIdentity(newUser) .setProvider(IDENTITY_PROVIDER) .setSource(Source.local(BASIC)) - .setExistingEmailStrategy(ExistingEmailStrategy.FORBID) .build()); assertThat(db.users().selectUserByLogin(user.getLogin()).get()) @@ -240,63 +231,21 @@ public class UserRegistrarImplTest { } @Test - public void authenticate_new_user_update_existing_user_email_when_strategy_is_ALLOW() { - UserDto existingUser = db.users().insertUser(u -> u.setEmail("john@email.com")); - UserIdentity newUser = UserIdentity.builder() - .setProviderLogin("johndoo") - .setName(existingUser.getName()) - .setEmail(existingUser.getEmail()) - .build(); - - UserDto user = underTest.register(UserRegistration.builder() - .setUserIdentity(newUser) - .setProvider(IDENTITY_PROVIDER) - .setSource(Source.local(BASIC)) - .setExistingEmailStrategy(ExistingEmailStrategy.ALLOW) - .build()); - - UserDto newUserReloaded = db.users().selectUserByLogin(user.getLogin()).get(); - assertThat(newUserReloaded.getEmail()).isEqualTo(existingUser.getEmail()); - UserDto existingUserReloaded = db.users().selectUserByLogin(existingUser.getLogin()).get(); - assertThat(existingUserReloaded.getEmail()).isNull(); - } - - @Test - public void throw_EmailAlreadyExistException_when_authenticating_new_user_when_email_already_exists_and_strategy_is_WARN() { - UserDto existingUser = db.users().insertUser(u -> u.setEmail("john@email.com")); - UserIdentity newUser = UserIdentity.builder() - .setProviderLogin("johndoo") - .setName(existingUser.getName()) - .setEmail(existingUser.getEmail()) - .build(); - - expectedException.expect(EmailAlreadyExistsRedirectionException.class); - - underTest.register(UserRegistration.builder() - .setUserIdentity(newUser) - .setProvider(IDENTITY_PROVIDER) - .setSource(Source.local(BASIC)) - .setExistingEmailStrategy(ExistingEmailStrategy.WARN) - .build()); - } - - @Test - public void throw_AuthenticationException_when_authenticating_new_user_when_email_already_exists_and_strategy_is_FORBID() { + public void authenticate_new_user_throws_AuthenticationException_when_when_email_already_exists() { 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.getProviderLogin()) - .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.")); + .andPublicMessage("This account is already associated with another authentication method." + + " Sign in using the current authentication method," + + " or contact your administrator to transfer your account to a different authentication method.")); expectedException.expectMessage("Email 'john@email.com' is already used"); underTest.register(UserRegistration.builder() .setUserIdentity(USER_IDENTITY) .setProvider(IDENTITY_PROVIDER) .setSource(source) - .setExistingEmailStrategy(FORBID) - .setExistingEmailStrategy(ExistingEmailStrategy.FORBID) .build()); } @@ -308,16 +257,15 @@ public class UserRegistrarImplTest { expectedException.expect(authenticationException().from(source) .withLogin(USER_IDENTITY.getProviderLogin()) - .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.")); + .andPublicMessage("This account is already associated with another authentication method." + + " Sign in using the current authentication method," + + " or contact your administrator to transfer your account to a different authentication method.")); expectedException.expectMessage("Email 'john@email.com' is already used"); underTest.register(UserRegistration.builder() .setUserIdentity(USER_IDENTITY) .setProvider(IDENTITY_PROVIDER) .setSource(source) - .setExistingEmailStrategy(FORBID) - .setExistingEmailStrategy(ExistingEmailStrategy.FORBID) .build()); } @@ -337,7 +285,6 @@ public class UserRegistrarImplTest { .setUserIdentity(USER_IDENTITY) .setProvider(identityProvider) .setSource(source) - .setExistingEmailStrategy(ExistingEmailStrategy.FORBID) .build()); } @@ -354,7 +301,6 @@ public class UserRegistrarImplTest { .setUserIdentity(USER_IDENTITY) .setProvider(IDENTITY_PROVIDER) .setSource(Source.local(BASIC)) - .setExistingEmailStrategy(ExistingEmailStrategy.FORBID) .build()); assertThat(db.users().selectUserByLogin(user.getLogin()).get()) @@ -376,7 +322,6 @@ public class UserRegistrarImplTest { .setUserIdentity(USER_IDENTITY) .setProvider(IDENTITY_PROVIDER) .setSource(Source.local(BASIC)) - .setExistingEmailStrategy(ExistingEmailStrategy.FORBID) .build()); assertThat(db.getDbClient().userDao().selectByUuid(db.getSession(), user.getUuid())) @@ -399,7 +344,6 @@ public class UserRegistrarImplTest { .setUserIdentity(USER_IDENTITY) .setProvider(IDENTITY_PROVIDER) .setSource(Source.local(BASIC)) - .setExistingEmailStrategy(ExistingEmailStrategy.FORBID) .build()); assertThat(db.getDbClient().userDao().selectByUuid(db.getSession(), user.getUuid())) @@ -422,7 +366,6 @@ public class UserRegistrarImplTest { .setUserIdentity(USER_IDENTITY) .setProvider(IDENTITY_PROVIDER) .setSource(Source.local(BASIC)) - .setExistingEmailStrategy(ExistingEmailStrategy.FORBID) .build()); // no new user should be created @@ -453,7 +396,6 @@ public class UserRegistrarImplTest { .build()) .setProvider(IDENTITY_PROVIDER) .setSource(Source.local(BASIC)) - .setExistingEmailStrategy(ExistingEmailStrategy.FORBID) .build()); assertThat(db.getDbClient().userDao().selectByUuid(db.getSession(), user.getUuid())) @@ -476,7 +418,6 @@ public class UserRegistrarImplTest { .build()) .setProvider(IDENTITY_PROVIDER) .setSource(Source.local(BASIC)) - .setExistingEmailStrategy(ExistingEmailStrategy.FORBID) .build()); // No new user is created @@ -499,7 +440,6 @@ public class UserRegistrarImplTest { .setUserIdentity(USER_IDENTITY) .setProvider(IDENTITY_PROVIDER) .setSource(Source.local(BASIC)) - .setExistingEmailStrategy(ExistingEmailStrategy.FORBID) .build()); assertThat(db.getDbClient().userDao().selectByUuid(db.getSession(), user.getUuid())) @@ -522,7 +462,6 @@ public class UserRegistrarImplTest { .setUserIdentity(USER_IDENTITY) .setProvider(IDENTITY_PROVIDER) .setSource(Source.local(BASIC)) - .setExistingEmailStrategy(ExistingEmailStrategy.FORBID) .build()); UserDto userDto = db.users().selectUserByLogin(USER_LOGIN).get(); @@ -536,53 +475,7 @@ public class UserRegistrarImplTest { } @Test - public void authenticate_existing_user_when_email_already_exists_and_strategy_is_ALLOW() { - UserDto existingUser = db.users().insertUser(u -> u.setEmail("john@email.com")); - UserDto currentUser = db.users().insertUser(u -> u.setExternalLogin("johndoo").setExternalIdentityProvider(IDENTITY_PROVIDER.getKey()).setEmail(null)); - - UserIdentity userIdentity = UserIdentity.builder() - .setProviderLogin(currentUser.getExternalLogin()) - .setName("John") - .setEmail("john@email.com") - .build(); - - currentUser = underTest.register(UserRegistration.builder() - .setUserIdentity(userIdentity) - .setProvider(IDENTITY_PROVIDER) - .setSource(Source.local(BASIC)) - .setExistingEmailStrategy(ExistingEmailStrategy.ALLOW) - .build()); - - UserDto existingUserReloaded = db.users().selectUserByLogin(existingUser.getLogin()).get(); - assertThat(existingUserReloaded.getEmail()).isNull(); - - UserDto currentUserReloaded = db.users().selectUserByLogin(currentUser.getLogin()).get(); - assertThat(currentUserReloaded.getEmail()).isEqualTo("john@email.com"); - - } - - @Test - public void throw_EmailAlreadyExistException_when_authenticating_existing_user_when_email_already_exists_and_strategy_is_WARN() { - UserDto existingUser = db.users().insertUser(u -> u.setEmail("john@email.com")); - UserDto currentUser = db.users().insertUser(u -> u.setEmail(null)); - UserIdentity userIdentity = UserIdentity.builder() - .setProviderLogin("johndoo") - .setName("John") - .setEmail("john@email.com") - .build(); - - expectedException.expect(EmailAlreadyExistsRedirectionException.class); - - underTest.register(UserRegistration.builder() - .setUserIdentity(userIdentity) - .setProvider(IDENTITY_PROVIDER) - .setSource(Source.local(BASIC)) - .setExistingEmailStrategy(ExistingEmailStrategy.WARN) - .build()); - } - - @Test - public void throw_AuthenticationException_when_authenticating_existing_user_when_email_already_exists_and_strategy_is_FORBID() { + public void authenticating_existing_user_throws_AuthenticationException_when_email_already_exists() { UserDto existingUser = db.users().insertUser(u -> u.setEmail("john@email.com")); UserDto currentUser = db.users().insertUser(u -> u.setEmail(null)); UserIdentity userIdentity = UserIdentity.builder() @@ -593,20 +486,20 @@ public class UserRegistrarImplTest { expectedException.expect(authenticationException().from(Source.realm(AuthenticationEvent.Method.FORM, IDENTITY_PROVIDER.getName())) .withLogin(userIdentity.getProviderLogin()) - .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.")); + .andPublicMessage("This account is already associated with another authentication method." + + " Sign in using the current authentication method," + + " or contact your administrator to transfer your account to a different authentication method.")); expectedException.expectMessage("Email 'john@email.com' is already used"); underTest.register(UserRegistration.builder() .setUserIdentity(userIdentity) .setProvider(IDENTITY_PROVIDER) .setSource(Source.realm(AuthenticationEvent.Method.FORM, IDENTITY_PROVIDER.getName())) - .setExistingEmailStrategy(ExistingEmailStrategy.FORBID) .build()); } @Test - public void does_not_fail_to_authenticate_user_when_email_has_not_changed_and_strategy_is_FORBID() { + public void authenticate_existing_user_succeeds_when_email_has_not_changed() { UserDto currentUser = db.users().insertUser(u -> u.setEmail("john@email.com") .setExternalIdentityProvider(IDENTITY_PROVIDER.getKey())); UserIdentity userIdentity = UserIdentity.builder() @@ -620,7 +513,6 @@ public class UserRegistrarImplTest { .setUserIdentity(userIdentity) .setProvider(IDENTITY_PROVIDER) .setSource(Source.local(BASIC)) - .setExistingEmailStrategy(ExistingEmailStrategy.FORBID) .build()); UserDto currentUserReloaded = db.users().selectUserByLogin(currentUser.getLogin()).get(); @@ -685,7 +577,6 @@ public class UserRegistrarImplTest { .build()) .setProvider(IDENTITY_PROVIDER) .setSource(Source.local(BASIC)) - .setExistingEmailStrategy(ExistingEmailStrategy.FORBID) .build()); } diff --git a/sonar-core/src/main/resources/org/sonar/l10n/core.properties b/sonar-core/src/main/resources/org/sonar/l10n/core.properties index 8c0bf019fd2..293c587cd1e 100644 --- a/sonar-core/src/main/resources/org/sonar/l10n/core.properties +++ b/sonar-core/src/main/resources/org/sonar/l10n/core.properties @@ -682,13 +682,6 @@ process.fail=Failed #------------------------------------------------------------------------------ sessions.log_in=Log in -sessions.email_already_exists.1=The email address {email} is already associated to this user account: -sessions.email_already_exists.2=By clicking on "Continue" you will associate this email address to another user account: -sessions.email_already_exists.3=This means the following: -sessions.email_already_exists.4=Your email address will be erased from the first account. -sessions.email_already_exists.5=You will no longer receive email notifications from this account. -sessions.email_already_exists.6=Issues won't be automatically assigned to this account anymore. - #------------------------------------------------------------------------------ # # HOTSPOTS -- 2.39.5