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,
104 new DefaultGroupFinder(db.getDbClient()),
106 localAuthentication);
108 private ResourceTypes resourceTypes = new ResourceTypesRule().setRootQualifiers(Qualifiers.PROJECT);
109 private PermissionService permissionService = new PermissionServiceImpl(resourceTypes);
110 private DefaultGroupFinder defaultGroupFinder = new DefaultGroupFinder(db.getDbClient());
112 private UserRegistrarImpl underTest = new UserRegistrarImpl(db.getDbClient(), userUpdater, defaultOrganizationProvider, organizationFlags,
113 defaultGroupFinder, new MemberUpdater(db.getDbClient(), defaultGroupFinder, userIndexer));
116 public void authenticate_new_github_user_syncs_organization() {
117 organizationFlags.setEnabled(true);
118 OrganizationDto organization = db.organizations().insert();
119 db.users().insertDefaultGroup(organization, "Members");
120 AlmAppInstallDto gitHubInstall = db.alm().insertAlmAppInstall(a -> a.setAlm(GITHUB));
121 db.alm().insertOrganizationAlmBinding(organization, gitHubInstall, true);
123 underTest.register(UserRegistration.builder()
124 .setUserIdentity(USER_IDENTITY)
125 .setProvider(GITHUB_PROVIDER)
126 .setSource(Source.realm(BASIC, GITHUB_PROVIDER.getName()))
127 .setExistingEmailStrategy(ExistingEmailStrategy.ALLOW)
128 .setOrganizationAlmIds(ImmutableSet.of(gitHubInstall.getOrganizationAlmId()))
131 UserDto user = db.users().selectUserByLogin(USER_LOGIN).get();
132 db.organizations().assertUserIsMemberOfOrganization(organization, user);
136 public void authenticate_new_github_user_does_not_sync_organization_when_no_org_alm_ids_provided() {
137 organizationFlags.setEnabled(true);
138 OrganizationDto organization = db.organizations().insert();
139 db.users().insertDefaultGroup(organization, "Members");
140 AlmAppInstallDto gitHubInstall = db.alm().insertAlmAppInstall(a -> a.setAlm(GITHUB));
141 db.alm().insertOrganizationAlmBinding(organization, gitHubInstall, true);
143 underTest.register(UserRegistration.builder()
144 .setUserIdentity(USER_IDENTITY)
145 .setProvider(GITHUB_PROVIDER)
146 .setSource(Source.realm(BASIC, GITHUB_PROVIDER.getName()))
147 .setExistingEmailStrategy(ExistingEmailStrategy.ALLOW)
148 .setOrganizationAlmIds(null)
151 UserDto user = db.users().selectUserByLogin(USER_LOGIN).get();
152 db.organizations().assertUserIsNotMemberOfOrganization(organization, user);
156 public void authenticate_new_bitbucket_user_does_not_sync_organization() {
157 organizationFlags.setEnabled(true);
158 OrganizationDto organization = db.organizations().insert();
159 db.users().insertDefaultGroup(organization, "Members");
160 AlmAppInstallDto gitHubInstall = db.alm().insertAlmAppInstall(a -> a.setAlm(BITBUCKETCLOUD));
161 db.alm().insertOrganizationAlmBinding(organization, gitHubInstall, true);
163 underTest.register(UserRegistration.builder()
164 .setUserIdentity(USER_IDENTITY)
165 .setProvider(BITBUCKET_PROVIDER)
166 .setSource(Source.realm(BASIC, BITBUCKET_PROVIDER.getName()))
167 .setExistingEmailStrategy(ExistingEmailStrategy.ALLOW)
168 .setOrganizationAlmIds(ImmutableSet.of(gitHubInstall.getOrganizationAlmId()))
171 UserDto user = db.users().selectUserByLogin(USER_LOGIN).get();
172 db.organizations().assertUserIsNotMemberOfOrganization(organization, user);
176 public void authenticate_new_user_using_unknown_alm_does_not_sync_organization() {
177 organizationFlags.setEnabled(true);
178 OrganizationDto organization = db.organizations().insert();
179 db.users().insertDefaultGroup(organization, "Members");
180 AlmAppInstallDto almAppInstall = db.alm().insertAlmAppInstall(a -> a.setAlm(GITHUB));
181 db.alm().insertOrganizationAlmBinding(organization, almAppInstall, true);
182 TestIdentityProvider identityProvider = new TestIdentityProvider()
186 .setAllowsUsersToSignUp(true);
188 underTest.register(UserRegistration.builder()
189 .setUserIdentity(USER_IDENTITY)
190 .setProvider(identityProvider)
191 .setSource(Source.realm(BASIC, identityProvider.getName()))
192 .setExistingEmailStrategy(ExistingEmailStrategy.ALLOW)
193 .setOrganizationAlmIds(ImmutableSet.of(almAppInstall.getOrganizationAlmId()))
196 UserDto user = db.users().selectUserByLogin(USER_LOGIN).get();
197 db.organizations().assertUserIsNotMemberOfOrganization(organization, user);
201 public void authenticate_existing_github_user_does_not_sync_organization() {
202 organizationFlags.setEnabled(true);
203 OrganizationDto organization = db.organizations().insert();
204 db.users().insertDefaultGroup(organization, "Members");
205 AlmAppInstallDto gitHubInstall = db.alm().insertAlmAppInstall(a -> a.setAlm(GITHUB));
206 db.alm().insertOrganizationAlmBinding(organization, gitHubInstall, true);
207 UserDto user = db.users().insertUser(u -> u
208 .setLogin("Old login")
209 .setExternalId(USER_IDENTITY.getProviderId())
210 .setExternalIdentityProvider(GITHUB_PROVIDER.getKey()));
212 underTest.register(UserRegistration.builder()
213 .setUserIdentity(USER_IDENTITY)
214 .setProvider(GITHUB_PROVIDER)
215 .setSource(Source.local(BASIC))
216 .setExistingEmailStrategy(ExistingEmailStrategy.FORBID)
217 .setOrganizationAlmIds(ImmutableSet.of(gitHubInstall.getOrganizationAlmId()))
220 db.organizations().assertUserIsNotMemberOfOrganization(organization, user);
224 public void authenticate_disabled_github_user_syncs_organization() {
225 organizationFlags.setEnabled(true);
226 OrganizationDto organization = db.organizations().insert();
227 db.users().insertDefaultGroup(organization, "Members");
228 AlmAppInstallDto gitHubInstall = db.alm().insertAlmAppInstall(a -> a.setAlm(GITHUB));
229 db.alm().insertOrganizationAlmBinding(organization, gitHubInstall, true);
230 UserDto user = db.users().insertDisabledUser(u -> u.setLogin(USER_LOGIN));
232 underTest.register(UserRegistration.builder()
233 .setUserIdentity(USER_IDENTITY)
234 .setProvider(GITHUB_PROVIDER)
235 .setSource(Source.local(BASIC))
236 .setExistingEmailStrategy(ExistingEmailStrategy.FORBID)
237 .setOrganizationAlmIds(ImmutableSet.of(gitHubInstall.getOrganizationAlmId()))
240 db.organizations().assertUserIsMemberOfOrganization(organization, user);