]> source.dussan.org Git - sonarqube.git/blob
645c468fc4f9d01be3e9ceff2a68ba466ad44123
[sonarqube.git] /
1 /*
2  * SonarQube
3  * Copyright (C) 2009-2016 SonarSource SA
4  * mailto:contact 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 static com.google.common.collect.Sets.newHashSet;
23 import static java.util.Collections.singletonList;
24 import static org.assertj.core.api.Assertions.assertThat;
25 import static org.mockito.Mockito.mock;
26 import static org.mockito.Mockito.verify;
27 import static org.mockito.Mockito.when;
28
29 import java.util.Collections;
30 import java.util.HashSet;
31 import java.util.Set;
32 import javax.servlet.http.HttpServletRequest;
33 import javax.servlet.http.HttpServletResponse;
34 import javax.servlet.http.HttpSession;
35 import org.junit.Before;
36 import org.junit.Rule;
37 import org.junit.Test;
38 import org.junit.rules.ExpectedException;
39 import org.sonar.api.config.Settings;
40 import org.sonar.api.server.authentication.UnauthorizedException;
41 import org.sonar.api.server.authentication.UserIdentity;
42 import org.sonar.api.utils.System2;
43 import org.sonar.db.DbClient;
44 import org.sonar.db.DbSession;
45 import org.sonar.db.DbTester;
46 import org.sonar.db.user.GroupDao;
47 import org.sonar.db.user.GroupDto;
48 import org.sonar.db.user.UserDao;
49 import org.sonar.db.user.UserDto;
50 import org.sonar.db.user.UserGroupDto;
51 import org.sonar.db.user.UserTesting;
52 import org.sonar.server.user.NewUserNotifier;
53 import org.sonar.server.user.UserUpdater;
54 import org.sonar.server.user.index.UserIndexer;
55
56 public class UserIdentityAuthenticatorTest {
57
58   static String USER_LOGIN = "github-johndoo";
59
60   static String DEFAULT_GROUP = "default";
61
62   static UserIdentity USER_IDENTITY = UserIdentity.builder()
63     .setProviderLogin("johndoo")
64     .setLogin(USER_LOGIN)
65     .setName("John")
66     .setEmail("john@email.com")
67     .build();
68
69   static TestIdentityProvider IDENTITY_PROVIDER = new TestIdentityProvider()
70     .setKey("github")
71     .setEnabled(true)
72     .setAllowsUsersToSignUp(true);
73
74   @Rule
75   public ExpectedException thrown = ExpectedException.none();
76
77   System2 system2 = mock(System2.class);
78
79   @Rule
80   public DbTester dbTester = DbTester.create(system2);
81
82   DbClient dbClient = dbTester.getDbClient();
83   DbSession dbSession = dbTester.getSession();
84   UserDao userDao = dbClient.userDao();
85   GroupDao groupDao = dbClient.groupDao();
86   Settings settings = new Settings();
87   JwtHttpHandler jwtHttpHandler = mock(JwtHttpHandler.class);
88
89   HttpServletRequest request = mock(HttpServletRequest.class);
90   HttpServletResponse response = mock(HttpServletResponse.class);
91   HttpSession httpSession = mock(HttpSession.class);
92
93   UserUpdater userUpdater = new UserUpdater(
94     mock(NewUserNotifier.class),
95     settings,
96     dbClient,
97     mock(UserIndexer.class),
98     system2
99     );
100
101   UserIdentityAuthenticator underTest = new UserIdentityAuthenticator(dbClient, userUpdater, jwtHttpHandler);
102
103   @Before
104   public void setUp() throws Exception {
105     settings.setProperty("sonar.defaultGroup", DEFAULT_GROUP);
106     addGroup(DEFAULT_GROUP);
107     when(request.getSession()).thenReturn(httpSession);
108   }
109
110   @Test
111   public void authenticate_new_user() throws Exception {
112     underTest.authenticate(USER_IDENTITY, IDENTITY_PROVIDER, request, response);
113     dbSession.commit();
114
115     UserDto userDto = userDao.selectByLogin(dbSession, USER_LOGIN);
116     assertThat(userDto).isNotNull();
117     assertThat(userDto.isActive()).isTrue();
118     assertThat(userDto.getName()).isEqualTo("John");
119     assertThat(userDto.getEmail()).isEqualTo("john@email.com");
120     assertThat(userDto.getExternalIdentity()).isEqualTo("johndoo");
121     assertThat(userDto.getExternalIdentityProvider()).isEqualTo("github");
122
123     verifyUserGroups(USER_LOGIN, DEFAULT_GROUP);
124   }
125
126   @Test
127   public void authenticate_new_user_with_groups() throws Exception {
128     addGroup("group1");
129     addGroup("group2");
130
131     underTest.authenticate(UserIdentity.builder()
132       .setProviderLogin("johndoo")
133       .setLogin(USER_LOGIN)
134       .setName("John")
135       // group3 doesn't exist in db, it will be ignored
136       .setGroups(newHashSet("group1", "group2", "group3"))
137       .build(), IDENTITY_PROVIDER, request, response);
138     dbSession.commit();
139
140     UserDto userDto = userDao.selectByLogin(dbSession, USER_LOGIN);
141     assertThat(userDto).isNotNull();
142
143     verifyUserGroups(USER_LOGIN, "group1", "group2");
144   }
145
146   @Test
147   public void authenticate_existing_user() throws Exception {
148     userDao.insert(dbSession, new UserDto()
149       .setLogin(USER_LOGIN)
150       .setActive(true)
151       .setName("Old name")
152       .setEmail("Old email")
153       .setExternalIdentity("old identity")
154       .setExternalIdentityProvider("old provide")
155       );
156     dbSession.commit();
157
158     underTest.authenticate(USER_IDENTITY, IDENTITY_PROVIDER, request, response);
159     dbSession.commit();
160
161     UserDto userDto = userDao.selectByLogin(dbSession, USER_LOGIN);
162     assertThat(userDto).isNotNull();
163     assertThat(userDto.isActive()).isTrue();
164     assertThat(userDto.getName()).isEqualTo("John");
165     assertThat(userDto.getEmail()).isEqualTo("john@email.com");
166     assertThat(userDto.getExternalIdentity()).isEqualTo("johndoo");
167     assertThat(userDto.getExternalIdentityProvider()).isEqualTo("github");
168   }
169
170   @Test
171   public void authenticate_existing_disabled_user() throws Exception {
172     userDao.insert(dbSession, new UserDto()
173       .setLogin(USER_LOGIN)
174       .setActive(false)
175       .setName("Old name")
176       .setEmail("Old email")
177       .setExternalIdentity("old identity")
178       .setExternalIdentityProvider("old provide")
179       );
180     dbSession.commit();
181
182     underTest.authenticate(USER_IDENTITY, IDENTITY_PROVIDER, request, response);
183     dbSession.commit();
184
185     UserDto userDto = userDao.selectByLogin(dbSession, USER_LOGIN);
186     assertThat(userDto).isNotNull();
187     assertThat(userDto.isActive()).isTrue();
188     assertThat(userDto.getName()).isEqualTo("John");
189     assertThat(userDto.getEmail()).isEqualTo("john@email.com");
190     assertThat(userDto.getExternalIdentity()).isEqualTo("johndoo");
191     assertThat(userDto.getExternalIdentityProvider()).isEqualTo("github");
192   }
193
194   @Test
195   public void authenticate_existing_user_and_add_new_groups() throws Exception {
196     userDao.insert(dbSession, new UserDto()
197       .setLogin(USER_LOGIN)
198       .setActive(true)
199       .setName("John")
200       );
201     addGroup("group1");
202     addGroup("group2");
203     dbSession.commit();
204
205     underTest.authenticate(UserIdentity.builder()
206       .setProviderLogin("johndoo")
207       .setLogin(USER_LOGIN)
208       .setName("John")
209       // group3 doesn't exist in db, it will be ignored
210       .setGroups(newHashSet("group1", "group2", "group3"))
211       .build(), IDENTITY_PROVIDER, request, response);
212     dbSession.commit();
213
214     Set<String> userGroups = new HashSet<>(dbClient.groupMembershipDao().selectGroupsByLogins(dbSession, singletonList(USER_LOGIN)).get(USER_LOGIN));
215     assertThat(userGroups).containsOnly("group1", "group2");
216   }
217
218   @Test
219   public void authenticate_existing_user_and_remove_groups() throws Exception {
220     UserDto user = new UserDto()
221       .setLogin(USER_LOGIN)
222       .setActive(true)
223       .setName("John");
224     userDao.insert(dbSession, user);
225
226     GroupDto group1 = addGroup("group1");
227     GroupDto group2 = addGroup("group2");
228     dbClient.userGroupDao().insert(dbSession, new UserGroupDto().setUserId(user.getId()).setGroupId(group1.getId()));
229     dbClient.userGroupDao().insert(dbSession, new UserGroupDto().setUserId(user.getId()).setGroupId(group2.getId()));
230     dbSession.commit();
231
232     Set<String> userGroups = new HashSet<>(dbClient.groupMembershipDao().selectGroupsByLogins(dbSession, singletonList(USER_LOGIN)).get(USER_LOGIN));
233     assertThat(userGroups).containsOnly("group1", "group2");
234
235     underTest.authenticate(UserIdentity.builder()
236       .setProviderLogin("johndoo")
237       .setLogin(USER_LOGIN)
238       .setName("John")
239       // Only group1 is returned by the id provider => group2 will be removed
240       .setGroups(newHashSet("group1"))
241       .build(), IDENTITY_PROVIDER, request, response);
242     dbSession.commit();
243
244     verifyUserGroups(USER_LOGIN, "group1");
245   }
246
247   @Test
248   public void authenticate_existing_user_and_remove_all_groups() throws Exception {
249     UserDto user = new UserDto()
250       .setLogin(USER_LOGIN)
251       .setActive(true)
252       .setName("John");
253     userDao.insert(dbSession, user);
254
255     GroupDto group1 = addGroup("group1");
256     GroupDto group2 = addGroup("group2");
257     dbClient.userGroupDao().insert(dbSession, new UserGroupDto().setUserId(user.getId()).setGroupId(group1.getId()));
258     dbClient.userGroupDao().insert(dbSession, new UserGroupDto().setUserId(user.getId()).setGroupId(group2.getId()));
259     dbSession.commit();
260
261     Set<String> userGroups = new HashSet<>(dbClient.groupMembershipDao().selectGroupsByLogins(dbSession, singletonList(USER_LOGIN)).get(USER_LOGIN));
262     assertThat(userGroups).containsOnly("group1", "group2");
263
264     underTest.authenticate(UserIdentity.builder()
265       .setProviderLogin("johndoo")
266       .setLogin(USER_LOGIN)
267       .setName("John")
268       // No group => group1 and group2 will be removed
269       .setGroups(Collections.<String>emptySet())
270       .build(), IDENTITY_PROVIDER, request, response);
271     dbSession.commit();
272
273     verifyNoUserGroups(USER_LOGIN);
274   }
275
276   @Test
277   public void update_session_for_rails() throws Exception {
278     UserDto userDto = UserTesting.newUserDto().setLogin(USER_LOGIN);
279     userDao.insert(dbSession, userDto);
280     dbSession.commit();
281
282     underTest.authenticate(USER_IDENTITY, IDENTITY_PROVIDER, request, response);
283
284     verify(httpSession).setAttribute("user_id", userDto.getId());
285   }
286
287   @Test
288   public void create_jwt_token() throws Exception {
289     UserDto userDto = UserTesting.newUserDto().setLogin(USER_LOGIN);
290     userDao.insert(dbSession, userDto);
291     dbSession.commit();
292
293     underTest.authenticate(USER_IDENTITY, IDENTITY_PROVIDER, request, response);
294
295     verify(httpSession).setAttribute("user_id", userDto.getId());
296     verify(jwtHttpHandler).generateToken(USER_LOGIN, response);
297   }
298
299   @Test
300   public void fail_to_authenticate_new_user_when_allow_users_to_signup_is_false() throws Exception {
301     TestIdentityProvider identityProvider = new TestIdentityProvider()
302       .setKey("github")
303       .setName("Github")
304       .setEnabled(true)
305       .setAllowsUsersToSignUp(false);
306
307     thrown.expect(UnauthorizedException.class);
308     thrown.expectMessage("'github' users are not allowed to sign up");
309     underTest.authenticate(USER_IDENTITY, identityProvider, request, response);
310   }
311
312   @Test
313   public void fail_to_authenticate_new_user_when_email_already_exists() throws Exception {
314     UserDto userDto = UserTesting.newUserDto()
315       .setLogin("Existing user with same email")
316       .setActive(true)
317       .setEmail("john@email.com");
318     userDao.insert(dbSession, userDto);
319     dbSession.commit();
320
321     thrown.expect(UnauthorizedException.class);
322     thrown.expectMessage("You can't sign up because email 'john@email.com' is already used by an existing user. " +
323       "This means that you probably already registered with another account.");
324     underTest.authenticate(USER_IDENTITY, IDENTITY_PROVIDER, request, response);
325   }
326
327   private void verifyUserGroups(String userLogin, String... groups) {
328     Set<String> userGroups = new HashSet<>(dbClient.groupMembershipDao().selectGroupsByLogins(dbSession, singletonList(USER_LOGIN)).get(userLogin));
329     assertThat(userGroups).containsOnly(groups);
330   }
331
332   private void verifyNoUserGroups(String userLogin) {
333     Set<String> userGroups = new HashSet<>(dbClient.groupMembershipDao().selectGroupsByLogins(dbSession, singletonList(USER_LOGIN)).get(userLogin));
334     assertThat(userGroups).isEmpty();
335   }
336
337   private GroupDto addGroup(String name) {
338     GroupDto group = new GroupDto().setName(name);
339     groupDao.insert(dbSession, group);
340     dbSession.commit();
341     return group;
342   }
343 }