From dedcd07375177612708036458183e5cb221fff6b 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 --- .../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 | 30 +--- .../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 | 117 ++------------- .../resources/org/sonar/l10n/core.properties | 7 - 22 files changed, 23 insertions(+), 773 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 83f668f0e8f..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 c02b8b9c9a4..21fe881a4a6 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 @@ -20,7 +20,6 @@ package org.sonar.server.authentication; import com.google.common.collect.Sets; - import java.util.ArrayList; import java.util.Collection; import java.util.HashSet; @@ -32,7 +31,6 @@ import java.util.Set; import java.util.function.Consumer; import javax.annotation.CheckForNull; import javax.annotation.Nullable; - import org.sonar.api.server.authentication.IdentityProvider; import org.sonar.api.server.authentication.UserIdentity; import org.sonar.api.utils.log.Logger; @@ -42,10 +40,8 @@ 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.AuthenticationEvent; 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; @@ -137,8 +133,7 @@ public class UserRegistrarImpl implements UserRegistrar { userIdentity, source, String.format("Login '%s' is already used", userIdentity.getProviderLogin()), - String.format("You can't sign up because login '%s' is already used by an existing user.", userIdentity.getProviderLogin()) - ); + String.format("You can't sign up because login '%s' is already used by an existing user.", userIdentity.getProviderLogin())); } private static AuthenticationException authException(UserIdentity userIdentity, AuthenticationEvent.Source source, String message, String publicMessage) { @@ -193,19 +188,7 @@ public class UserRegistrarImpl implements UserRegistrar { if (existingUser == null || existingUser.getUuid().equals(authenticatingUserUuid)) { 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 void syncGroups(DbSession dbSession, UserIdentity userIdentity, UserDto userDto) { @@ -278,7 +261,7 @@ public class UserRegistrarImpl implements UserRegistrar { } private static UserDto[] toArray(Optional userDto) { - return userDto.map(u -> new UserDto[]{u}).orElse(new UserDto[]{}); + return userDto.map(u -> new UserDto[] {u}).orElse(new UserDto[] {}); } private static AuthenticationException generateExistingEmailError(UserRegistration authenticatorParameters, String email) { @@ -286,9 +269,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 e9ac84f8095..46ddd229898 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 @@ -34,11 +34,9 @@ import org.sonar.api.utils.log.LogTester; 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.event.AuthenticationException; -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; @@ -51,7 +49,6 @@ import static org.assertj.core.api.Assertions.assertThatThrownBy; 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; @@ -123,7 +120,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(); @@ -213,7 +209,6 @@ public class UserRegistrarImplTest { .setEnabled(true) .setAllowsUsersToSignUp(true)) .setSource(Source.local(BASIC)) - .setExistingEmailStrategy(FORBID) .build(); UserDto newUser = underTest.register(registration); @@ -223,55 +218,15 @@ 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 authenticate_new_user_throws_EmailAlreadyExistException_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 authenticate_new_user_throws_AuthenticationException_when_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.local(BASIC); 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(newUserRegistration()); @@ -285,8 +240,9 @@ 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(newUserRegistration(source)); @@ -308,7 +264,6 @@ public class UserRegistrarImplTest { .setUserIdentity(USER_IDENTITY) .setProvider(identityProvider) .setSource(source) - .setExistingEmailStrategy(ExistingEmailStrategy.FORBID) .build()); } @@ -420,7 +375,6 @@ public class UserRegistrarImplTest { .setName("name of gitlab") .setEnabled(true)) .setSource(Source.local(BASIC)) - .setExistingEmailStrategy(FORBID) .build(); assertThatThrownBy(() -> underTest.register(registration)) @@ -516,54 +470,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.setExternalId("id").setExternalLogin("login").setExternalIdentityProvider(IDENTITY_PROVIDER.getKey()).setEmail(null)); - - UserIdentity userIdentity = UserIdentity.builder() - .setProviderLogin(currentUser.getExternalLogin()) - .setProviderId(currentUser.getExternalId()) - .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 authenticating_existing_user_throws_EmailAlreadyExistException_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 authenticating_existing_user_throws_AuthenticationException_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() @@ -575,15 +482,16 @@ public class UserRegistrarImplTest { Source source = Source.realm(AuthenticationEvent.Method.FORM, IDENTITY_PROVIDER.getName()); expectedException.expect(authenticationException().from(source) .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(newUserRegistration(userIdentity, source)); } @Test - public void authenticate_existing_user_succeeds_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() @@ -658,7 +566,6 @@ public class UserRegistrarImplTest { .setUserIdentity(userIdentity) .setProvider(IDENTITY_PROVIDER) .setSource(source) - .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 112ecffea95..130aa1ff065 100644 --- a/sonar-core/src/main/resources/org/sonar/l10n/core.properties +++ b/sonar-core/src/main/resources/org/sonar/l10n/core.properties @@ -686,13 +686,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