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