]> source.dussan.org Git - sonarqube.git/blob
9f84bab5786159b3f15c549cbd1e9571cd71eea7
[sonarqube.git] /
1 /*
2  * SonarQube
3  * Copyright (C) 2009-2017 SonarSource SA
4  * mailto:info AT sonarsource DOT com
5  *
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.
10  *
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.
15  *
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.
19  */
20 package org.sonar.server.authentication;
21
22 import java.util.Optional;
23 import java.util.stream.Collectors;
24 import org.junit.Rule;
25 import org.junit.Test;
26 import org.junit.rules.ExpectedException;
27 import org.sonar.api.config.internal.MapSettings;
28 import org.sonar.api.server.authentication.UserIdentity;
29 import org.sonar.api.utils.System2;
30 import org.sonar.api.utils.internal.AlwaysIncreasingSystem2;
31 import org.sonar.core.util.stream.MoreCollectors;
32 import org.sonar.db.DbTester;
33 import org.sonar.db.organization.OrganizationDto;
34 import org.sonar.db.user.GroupDto;
35 import org.sonar.db.user.UserDto;
36 import org.sonar.server.organization.DefaultOrganizationProvider;
37 import org.sonar.server.organization.OrganizationCreation;
38 import org.sonar.server.organization.TestDefaultOrganizationProvider;
39 import org.sonar.server.organization.TestOrganizationFlags;
40 import org.sonar.server.user.NewUserNotifier;
41 import org.sonar.server.user.UserUpdater;
42 import org.sonar.server.user.index.UserIndexer;
43 import org.sonar.server.usergroups.DefaultGroupFinder;
44
45 import static com.google.common.collect.Sets.newHashSet;
46 import static java.util.Arrays.stream;
47 import static org.assertj.core.api.Assertions.assertThat;
48 import static org.mockito.Mockito.mock;
49 import static org.sonar.core.config.CorePropertyDefinitions.ONBOARDING_TUTORIAL_SHOW_TO_NEW_USERS;
50 import static org.sonar.db.user.UserTesting.newUserDto;
51 import static org.sonar.server.authentication.event.AuthenticationEvent.Method;
52 import static org.sonar.server.authentication.event.AuthenticationEvent.Source;
53 import static org.sonar.server.authentication.event.AuthenticationExceptionMatcher.authenticationException;
54
55 public class UserIdentityAuthenticatorTest {
56
57   private static String USER_LOGIN = "github-johndoo";
58
59   private static UserIdentity USER_IDENTITY = UserIdentity.builder()
60     .setProviderLogin("johndoo")
61     .setLogin(USER_LOGIN)
62     .setName("John")
63     .setEmail("john@email.com")
64     .build();
65
66   private static TestIdentityProvider IDENTITY_PROVIDER = new TestIdentityProvider()
67     .setKey("github")
68     .setName("name of github")
69     .setEnabled(true)
70     .setAllowsUsersToSignUp(true);
71
72   @Rule
73   public ExpectedException thrown = ExpectedException.none();
74
75   @Rule
76   public DbTester db = DbTester.create(new AlwaysIncreasingSystem2());
77
78   private DefaultOrganizationProvider defaultOrganizationProvider = TestDefaultOrganizationProvider.from(db);
79   private OrganizationCreation organizationCreation = mock(OrganizationCreation.class);
80   private TestOrganizationFlags organizationFlags = TestOrganizationFlags.standalone();
81   private MapSettings settings = new MapSettings();
82
83   private UserUpdater userUpdater = new UserUpdater(
84     mock(NewUserNotifier.class),
85     db.getDbClient(),
86     mock(UserIndexer.class),
87     System2.INSTANCE,
88     organizationFlags,
89     defaultOrganizationProvider,
90     organizationCreation,
91     new DefaultGroupFinder(db.getDbClient()),
92     settings);
93   private UserIdentityAuthenticator underTest = new UserIdentityAuthenticator(db.getDbClient(), userUpdater, defaultOrganizationProvider, organizationFlags,
94     new DefaultGroupFinder(db.getDbClient()));
95
96   @Test
97   public void authenticate_new_user() throws Exception {
98     organizationFlags.setEnabled(true);
99     underTest.authenticate(USER_IDENTITY, IDENTITY_PROVIDER, Source.realm(Method.BASIC, IDENTITY_PROVIDER.getName()));
100
101     UserDto user = db.users().selectUserByLogin(USER_LOGIN).get();
102     assertThat(user).isNotNull();
103     assertThat(user.isActive()).isTrue();
104     assertThat(user.getName()).isEqualTo("John");
105     assertThat(user.getEmail()).isEqualTo("john@email.com");
106     assertThat(user.getExternalIdentity()).isEqualTo("johndoo");
107     assertThat(user.getExternalIdentityProvider()).isEqualTo("github");
108     assertThat(user.isRoot()).isFalse();
109
110     checkGroupMembership(user);
111   }
112
113   @Test
114   public void authenticate_new_user_with_groups() throws Exception {
115     organizationFlags.setEnabled(true);
116     GroupDto group1 = db.users().insertGroup(db.getDefaultOrganization(), "group1");
117     GroupDto group2 = db.users().insertGroup(db.getDefaultOrganization(), "group2");
118
119     authenticate(USER_LOGIN, "group1", "group2", "group3");
120
121     Optional<UserDto> user = db.users().selectUserByLogin(USER_LOGIN);
122     checkGroupMembership(user.get(), group1, group2);
123   }
124
125   @Test
126   public void authenticate_new_user_and_force_default_group_when_organizations_are_disabled() throws Exception {
127     organizationFlags.setEnabled(false);
128     UserDto user = db.users().insertUser();
129     GroupDto group1 = db.users().insertGroup(db.getDefaultOrganization(), "group1");
130     GroupDto defaultGroup = insertDefaultGroup();
131     db.users().insertMember(group1, user);
132     db.users().insertMember(defaultGroup, user);
133
134     authenticate(user.getLogin(), "group1");
135
136     checkGroupMembership(user, group1, defaultGroup);
137   }
138
139   @Test
140   public void does_not_force_default_group_when_authenticating_new_user_if_organizations_are_enabled() throws Exception {
141     organizationFlags.setEnabled(true);
142     UserDto user = db.users().insertUser();
143     GroupDto group1 = db.users().insertGroup(db.getDefaultOrganization(), "group1");
144     GroupDto defaultGroup = insertDefaultGroup();
145     db.users().insertMember(group1, user);
146     db.users().insertMember(defaultGroup, user);
147
148     authenticate(user.getLogin(), "group1");
149
150     checkGroupMembership(user, group1);
151   }
152
153   @Test
154   public void authenticate_new_user_sets_onboarded_flag_to_false_when_onboarding_setting_is_set_to_true() {
155     organizationFlags.setEnabled(true);
156     settings.setProperty(ONBOARDING_TUTORIAL_SHOW_TO_NEW_USERS, true);
157
158     underTest.authenticate(USER_IDENTITY, IDENTITY_PROVIDER, Source.realm(Method.BASIC, IDENTITY_PROVIDER.getName()));
159
160     assertThat(db.users().selectUserByLogin(USER_LOGIN).get().isOnboarded()).isFalse();
161   }
162
163   @Test
164   public void authenticate_new_user_sets_onboarded_flag_to_true_when_onboarding_setting_is_set_to_false() {
165     organizationFlags.setEnabled(true);
166     settings.setProperty(ONBOARDING_TUTORIAL_SHOW_TO_NEW_USERS, false);
167
168     underTest.authenticate(USER_IDENTITY, IDENTITY_PROVIDER, Source.realm(Method.BASIC, IDENTITY_PROVIDER.getName()));
169
170     assertThat(db.users().selectUserByLogin(USER_LOGIN).get().isOnboarded()).isTrue();
171   }
172
173   @Test
174   public void authenticate_existing_user() throws Exception {
175     db.users().insertUser(newUserDto()
176       .setLogin(USER_LOGIN)
177       .setActive(true)
178       .setName("Old name")
179       .setEmail("Old email")
180       .setExternalIdentity("old identity")
181       .setExternalIdentityProvider("old provide"));
182
183     underTest.authenticate(USER_IDENTITY, IDENTITY_PROVIDER, Source.local(Method.BASIC));
184
185     UserDto userDto = db.users().selectUserByLogin(USER_LOGIN).get();
186     assertThat(userDto.isActive()).isTrue();
187     assertThat(userDto.getName()).isEqualTo("John");
188     assertThat(userDto.getEmail()).isEqualTo("john@email.com");
189     assertThat(userDto.getExternalIdentity()).isEqualTo("johndoo");
190     assertThat(userDto.getExternalIdentityProvider()).isEqualTo("github");
191     assertThat(userDto.isRoot()).isFalse();
192   }
193
194   @Test
195   public void authenticate_existing_disabled_user() throws Exception {
196     organizationFlags.setEnabled(true);
197     db.users().insertUser(newUserDto()
198       .setLogin(USER_LOGIN)
199       .setActive(false)
200       .setName("Old name")
201       .setEmail("Old email")
202       .setExternalIdentity("old identity")
203       .setExternalIdentityProvider("old provide"));
204
205     underTest.authenticate(USER_IDENTITY, IDENTITY_PROVIDER, Source.local(Method.BASIC_TOKEN));
206
207     UserDto userDto = db.users().selectUserByLogin(USER_LOGIN).get();
208     assertThat(userDto.isActive()).isTrue();
209     assertThat(userDto.getName()).isEqualTo("John");
210     assertThat(userDto.getEmail()).isEqualTo("john@email.com");
211     assertThat(userDto.getExternalIdentity()).isEqualTo("johndoo");
212     assertThat(userDto.getExternalIdentityProvider()).isEqualTo("github");
213     assertThat(userDto.isRoot()).isFalse();
214   }
215
216   @Test
217   public void authenticate_existing_user_and_add_new_groups() throws Exception {
218     organizationFlags.setEnabled(true);
219     UserDto user = db.users().insertUser(newUserDto()
220       .setLogin(USER_LOGIN)
221       .setActive(true)
222       .setName("John"));
223     GroupDto group1 = db.users().insertGroup(db.getDefaultOrganization(), "group1");
224     GroupDto group2 = db.users().insertGroup(db.getDefaultOrganization(), "group2");
225
226     authenticate(USER_LOGIN, "group1", "group2", "group3");
227
228     checkGroupMembership(user, group1, group2);
229   }
230
231   @Test
232   public void authenticate_existing_user_and_remove_groups() throws Exception {
233     organizationFlags.setEnabled(true);
234     UserDto user = db.users().insertUser(newUserDto()
235       .setLogin(USER_LOGIN)
236       .setActive(true)
237       .setName("John"));
238     GroupDto group1 = db.users().insertGroup(db.getDefaultOrganization(), "group1");
239     GroupDto group2 = db.users().insertGroup(db.getDefaultOrganization(), "group2");
240     db.users().insertMember(group1, user);
241     db.users().insertMember(group2, user);
242
243     authenticate(USER_LOGIN, "group1");
244
245     checkGroupMembership(user, group1);
246   }
247
248   @Test
249   public void authenticate_existing_user_and_remove_all_groups_expect_default_when_organizations_are_disabled() throws Exception {
250     organizationFlags.setEnabled(false);
251     UserDto user = db.users().insertUser();
252     GroupDto group1 = db.users().insertGroup(db.getDefaultOrganization(), "group1");
253     GroupDto group2 = db.users().insertGroup(db.getDefaultOrganization(), "group2");
254     GroupDto defaultGroup = insertDefaultGroup();
255     db.users().insertMember(group1, user);
256     db.users().insertMember(group2, user);
257     db.users().insertMember(defaultGroup, user);
258
259     authenticate(user.getLogin());
260
261     checkGroupMembership(user, defaultGroup);
262   }
263
264   @Test
265   public void does_not_force_default_group_when_authenticating_existing_user_when_organizations_are_enabled() throws Exception {
266     organizationFlags.setEnabled(true);
267     UserDto user = db.users().insertUser();
268     GroupDto group1 = db.users().insertGroup(db.getDefaultOrganization(), "group1");
269     GroupDto defaultGroup = insertDefaultGroup();
270     db.users().insertMember(group1, user);
271     db.users().insertMember(defaultGroup, user);
272
273     authenticate(user.getLogin(), "group1");
274
275     checkGroupMembership(user, group1);
276   }
277
278   @Test
279   public void ignore_groups_on_non_default_organizations() throws Exception {
280     organizationFlags.setEnabled(true);
281     OrganizationDto org = db.organizations().insert();
282     UserDto user = db.users().insertUser(newUserDto()
283       .setLogin(USER_LOGIN)
284       .setActive(true)
285       .setName("John"));
286     String groupName = "a-group";
287     GroupDto groupInDefaultOrg = db.users().insertGroup(db.getDefaultOrganization(), groupName);
288     GroupDto groupInOrg = db.users().insertGroup(org, groupName);
289
290     // adding a group with the same name than in non-default organization
291     underTest.authenticate(UserIdentity.builder()
292       .setProviderLogin("johndoo")
293       .setLogin(user.getLogin())
294       .setName(user.getName())
295       .setGroups(newHashSet(groupName))
296       .build(), IDENTITY_PROVIDER, Source.sso());
297
298     checkGroupMembership(user, groupInDefaultOrg);
299   }
300
301   @Test
302   public void fail_to_authenticate_new_user_when_allow_users_to_signup_is_false() throws Exception {
303     TestIdentityProvider identityProvider = new TestIdentityProvider()
304       .setKey("github")
305       .setName("Github")
306       .setEnabled(true)
307       .setAllowsUsersToSignUp(false);
308     Source source = Source.realm(Method.FORM, identityProvider.getName());
309
310     thrown.expect(authenticationException().from(source).withLogin(USER_IDENTITY.getLogin()).andPublicMessage("'github' users are not allowed to sign up"));
311     thrown.expectMessage("User signup disabled for provider 'github'");
312     underTest.authenticate(USER_IDENTITY, identityProvider, source);
313   }
314
315   @Test
316   public void fail_to_authenticate_new_user_when_email_already_exists() throws Exception {
317     db.users().insertUser(newUserDto()
318       .setLogin("Existing user with same email")
319       .setActive(true)
320       .setEmail("john@email.com"));
321     Source source = Source.realm(Method.FORM, IDENTITY_PROVIDER.getName());
322
323     thrown.expect(authenticationException().from(source)
324       .withLogin(USER_IDENTITY.getLogin())
325       .andPublicMessage("You can't sign up because email 'john@email.com' is already used by an existing user. " +
326         "This means that you probably already registered with another account."));
327     thrown.expectMessage("Email 'john@email.com' is already used");
328     underTest.authenticate(USER_IDENTITY, IDENTITY_PROVIDER, source);
329   }
330
331   private void authenticate(String login, String... groups) {
332     underTest.authenticate(UserIdentity.builder()
333       .setProviderLogin("johndoo")
334       .setLogin(login)
335       .setName("John")
336       // No group
337       .setGroups(stream(groups).collect(MoreCollectors.toSet()))
338       .build(), IDENTITY_PROVIDER, Source.sso());
339   }
340
341   private void checkGroupMembership(UserDto user, GroupDto... expectedGroups) {
342     assertThat(db.users().selectGroupIdsOfUser(user)).containsOnly(stream(expectedGroups).map(GroupDto::getId).collect(Collectors.toList()).toArray(new Integer[] {}));
343   }
344
345   private GroupDto insertDefaultGroup() {
346     return db.users().insertDefaultGroup(db.getDefaultOrganization(), "sonar-users");
347   }
348 }