3 * Copyright (C) 2009-2019 SonarSource SA
4 * mailto:info AT sonarsource DOT com
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 3 of the License, or (at your option) any later version.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public License
17 * along with this program; if not, write to the Free Software Foundation,
18 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
20 package org.sonar.server.authentication;
22 import com.google.common.collect.ImmutableSet;
23 import org.junit.Rule;
24 import org.junit.Test;
25 import org.junit.rules.ExpectedException;
26 import org.sonar.api.config.internal.MapSettings;
27 import org.sonar.api.impl.utils.AlwaysIncreasingSystem2;
28 import org.sonar.api.resources.Qualifiers;
29 import org.sonar.api.resources.ResourceTypes;
30 import org.sonar.api.server.authentication.UserIdentity;
31 import org.sonar.api.utils.System2;
32 import org.sonar.db.DbTester;
33 import org.sonar.db.alm.AlmAppInstallDto;
34 import org.sonar.db.component.ResourceTypesRule;
35 import org.sonar.db.organization.OrganizationDto;
36 import org.sonar.db.user.UserDto;
37 import org.sonar.server.authentication.UserRegistration.ExistingEmailStrategy;
38 import org.sonar.server.authentication.event.AuthenticationEvent.Source;
39 import org.sonar.server.es.EsTester;
40 import org.sonar.server.organization.DefaultOrganizationProvider;
41 import org.sonar.server.organization.MemberUpdater;
42 import org.sonar.server.organization.OrganizationUpdater;
43 import org.sonar.server.organization.TestDefaultOrganizationProvider;
44 import org.sonar.server.organization.TestOrganizationFlags;
45 import org.sonar.server.permission.PermissionService;
46 import org.sonar.server.permission.PermissionServiceImpl;
47 import org.sonar.server.user.NewUserNotifier;
48 import org.sonar.server.user.UserUpdater;
49 import org.sonar.server.user.index.UserIndexer;
50 import org.sonar.server.usergroups.DefaultGroupFinder;
52 import static org.mockito.Mockito.mock;
53 import static org.sonar.db.alm.ALM.BITBUCKETCLOUD;
54 import static org.sonar.db.alm.ALM.GITHUB;
55 import static org.sonar.server.authentication.event.AuthenticationEvent.Method.BASIC;
57 public class UserRegistrarImplOrgMembershipSyncTest {
59 private System2 system2 = new AlwaysIncreasingSystem2();
61 private static String USER_LOGIN = "github-johndoo";
63 private static UserIdentity USER_IDENTITY = UserIdentity.builder()
64 .setProviderId("ABCD")
65 .setProviderLogin("johndoo")
68 .setEmail("john@email.com")
71 private static TestIdentityProvider GITHUB_PROVIDER = new TestIdentityProvider()
75 .setAllowsUsersToSignUp(true);
77 private static TestIdentityProvider BITBUCKET_PROVIDER = new TestIdentityProvider()
81 .setAllowsUsersToSignUp(true);
83 private MapSettings settings = new MapSettings();
86 public ExpectedException expectedException = ExpectedException.none();
88 public DbTester db = DbTester.create(new AlwaysIncreasingSystem2());
90 public EsTester es = EsTester.create();
91 private UserIndexer userIndexer = new UserIndexer(db.getDbClient(), es.client());
92 private DefaultOrganizationProvider defaultOrganizationProvider = TestDefaultOrganizationProvider.from(db);
93 private OrganizationUpdater organizationUpdater = mock(OrganizationUpdater.class);
94 private TestOrganizationFlags organizationFlags = TestOrganizationFlags.standalone();
95 private CredentialsLocalAuthentication localAuthentication = new CredentialsLocalAuthentication(db.getDbClient());
96 private UserUpdater userUpdater = new UserUpdater(
98 mock(NewUserNotifier.class),
102 defaultOrganizationProvider,
103 new DefaultGroupFinder(db.getDbClient()),
105 localAuthentication);
107 private ResourceTypes resourceTypes = new ResourceTypesRule().setRootQualifiers(Qualifiers.PROJECT);
108 private PermissionService permissionService = new PermissionServiceImpl(resourceTypes);
109 private DefaultGroupFinder defaultGroupFinder = new DefaultGroupFinder(db.getDbClient());
111 private UserRegistrarImpl underTest = new UserRegistrarImpl(db.getDbClient(), userUpdater, defaultOrganizationProvider, organizationFlags,
112 defaultGroupFinder, new MemberUpdater(db.getDbClient(), defaultGroupFinder, userIndexer));
115 public void authenticate_new_github_user_syncs_organization() {
116 organizationFlags.setEnabled(true);
117 OrganizationDto organization = db.organizations().insert();
118 db.users().insertDefaultGroup(organization, "Members");
119 AlmAppInstallDto gitHubInstall = db.alm().insertAlmAppInstall(a -> a.setAlm(GITHUB));
120 db.alm().insertOrganizationAlmBinding(organization, gitHubInstall, true);
122 underTest.register(UserRegistration.builder()
123 .setUserIdentity(USER_IDENTITY)
124 .setProvider(GITHUB_PROVIDER)
125 .setSource(Source.realm(BASIC, GITHUB_PROVIDER.getName()))
126 .setExistingEmailStrategy(ExistingEmailStrategy.ALLOW)
127 .setOrganizationAlmIds(ImmutableSet.of(gitHubInstall.getOrganizationAlmId()))
130 UserDto user = db.users().selectUserByLogin(USER_LOGIN).get();
131 db.organizations().assertUserIsMemberOfOrganization(organization, user);
135 public void authenticate_new_github_user_does_not_sync_organization_when_no_org_alm_ids_provided() {
136 organizationFlags.setEnabled(true);
137 OrganizationDto organization = db.organizations().insert();
138 db.users().insertDefaultGroup(organization, "Members");
139 AlmAppInstallDto gitHubInstall = db.alm().insertAlmAppInstall(a -> a.setAlm(GITHUB));
140 db.alm().insertOrganizationAlmBinding(organization, gitHubInstall, true);
142 underTest.register(UserRegistration.builder()
143 .setUserIdentity(USER_IDENTITY)
144 .setProvider(GITHUB_PROVIDER)
145 .setSource(Source.realm(BASIC, GITHUB_PROVIDER.getName()))
146 .setExistingEmailStrategy(ExistingEmailStrategy.ALLOW)
147 .setOrganizationAlmIds(null)
150 UserDto user = db.users().selectUserByLogin(USER_LOGIN).get();
151 db.organizations().assertUserIsNotMemberOfOrganization(organization, user);
155 public void authenticate_new_bitbucket_user_does_not_sync_organization() {
156 organizationFlags.setEnabled(true);
157 OrganizationDto organization = db.organizations().insert();
158 db.users().insertDefaultGroup(organization, "Members");
159 AlmAppInstallDto gitHubInstall = db.alm().insertAlmAppInstall(a -> a.setAlm(BITBUCKETCLOUD));
160 db.alm().insertOrganizationAlmBinding(organization, gitHubInstall, true);
162 underTest.register(UserRegistration.builder()
163 .setUserIdentity(USER_IDENTITY)
164 .setProvider(BITBUCKET_PROVIDER)
165 .setSource(Source.realm(BASIC, BITBUCKET_PROVIDER.getName()))
166 .setExistingEmailStrategy(ExistingEmailStrategy.ALLOW)
167 .setOrganizationAlmIds(ImmutableSet.of(gitHubInstall.getOrganizationAlmId()))
170 UserDto user = db.users().selectUserByLogin(USER_LOGIN).get();
171 db.organizations().assertUserIsNotMemberOfOrganization(organization, user);
175 public void authenticate_new_user_using_unknown_alm_does_not_sync_organization() {
176 organizationFlags.setEnabled(true);
177 OrganizationDto organization = db.organizations().insert();
178 db.users().insertDefaultGroup(organization, "Members");
179 AlmAppInstallDto almAppInstall = db.alm().insertAlmAppInstall(a -> a.setAlm(GITHUB));
180 db.alm().insertOrganizationAlmBinding(organization, almAppInstall, true);
181 TestIdentityProvider identityProvider = new TestIdentityProvider()
185 .setAllowsUsersToSignUp(true);
187 underTest.register(UserRegistration.builder()
188 .setUserIdentity(USER_IDENTITY)
189 .setProvider(identityProvider)
190 .setSource(Source.realm(BASIC, identityProvider.getName()))
191 .setExistingEmailStrategy(ExistingEmailStrategy.ALLOW)
192 .setOrganizationAlmIds(ImmutableSet.of(almAppInstall.getOrganizationAlmId()))
195 UserDto user = db.users().selectUserByLogin(USER_LOGIN).get();
196 db.organizations().assertUserIsNotMemberOfOrganization(organization, user);
200 public void authenticate_existing_github_user_does_not_sync_organization() {
201 organizationFlags.setEnabled(true);
202 OrganizationDto organization = db.organizations().insert();
203 db.users().insertDefaultGroup(organization, "Members");
204 AlmAppInstallDto gitHubInstall = db.alm().insertAlmAppInstall(a -> a.setAlm(GITHUB));
205 db.alm().insertOrganizationAlmBinding(organization, gitHubInstall, true);
206 UserDto user = db.users().insertUser(u -> u
207 .setLogin("Old login")
208 .setExternalId(USER_IDENTITY.getProviderId())
209 .setExternalIdentityProvider(GITHUB_PROVIDER.getKey()));
211 underTest.register(UserRegistration.builder()
212 .setUserIdentity(USER_IDENTITY)
213 .setProvider(GITHUB_PROVIDER)
214 .setSource(Source.local(BASIC))
215 .setExistingEmailStrategy(ExistingEmailStrategy.FORBID)
216 .setOrganizationAlmIds(ImmutableSet.of(gitHubInstall.getOrganizationAlmId()))
219 db.organizations().assertUserIsNotMemberOfOrganization(organization, user);
223 public void authenticate_disabled_github_user_syncs_organization() {
224 organizationFlags.setEnabled(true);
225 OrganizationDto organization = db.organizations().insert();
226 db.users().insertDefaultGroup(organization, "Members");
227 AlmAppInstallDto gitHubInstall = db.alm().insertAlmAppInstall(a -> a.setAlm(GITHUB));
228 db.alm().insertOrganizationAlmBinding(organization, gitHubInstall, true);
229 UserDto user = db.users().insertDisabledUser(u -> u.setLogin(USER_LOGIN));
231 underTest.register(UserRegistration.builder()
232 .setUserIdentity(USER_IDENTITY)
233 .setProvider(GITHUB_PROVIDER)
234 .setSource(Source.local(BASIC))
235 .setExistingEmailStrategy(ExistingEmailStrategy.FORBID)
236 .setOrganizationAlmIds(ImmutableSet.of(gitHubInstall.getOrganizationAlmId()))
239 db.organizations().assertUserIsMemberOfOrganization(organization, user);