3 * Copyright (C) 2009-2016 SonarSource SA
4 * mailto:contact 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 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;
27 import java.util.Collections;
28 import java.util.HashSet;
30 import javax.servlet.http.HttpServletRequest;
31 import javax.servlet.http.HttpServletResponse;
32 import org.junit.Before;
33 import org.junit.Rule;
34 import org.junit.Test;
35 import org.junit.rules.ExpectedException;
36 import org.sonar.api.config.Settings;
37 import org.sonar.api.server.authentication.UnauthorizedException;
38 import org.sonar.api.server.authentication.UserIdentity;
39 import org.sonar.api.utils.System2;
40 import org.sonar.db.DbClient;
41 import org.sonar.db.DbSession;
42 import org.sonar.db.DbTester;
43 import org.sonar.db.user.GroupDao;
44 import org.sonar.db.user.GroupDto;
45 import org.sonar.db.user.UserDao;
46 import org.sonar.db.user.UserDto;
47 import org.sonar.db.user.UserGroupDto;
48 import org.sonar.db.user.UserTesting;
49 import org.sonar.server.user.NewUserNotifier;
50 import org.sonar.server.user.UserUpdater;
51 import org.sonar.server.user.index.UserIndexer;
53 public class UserIdentityAuthenticatorTest {
55 static String USER_LOGIN = "github-johndoo";
57 static String DEFAULT_GROUP = "default";
59 static UserIdentity USER_IDENTITY = UserIdentity.builder()
60 .setProviderLogin("johndoo")
63 .setEmail("john@email.com")
66 static TestIdentityProvider IDENTITY_PROVIDER = new TestIdentityProvider()
69 .setAllowsUsersToSignUp(true);
72 public ExpectedException thrown = ExpectedException.none();
74 System2 system2 = mock(System2.class);
77 public DbTester dbTester = DbTester.create(system2);
79 DbClient dbClient = dbTester.getDbClient();
80 DbSession dbSession = dbTester.getSession();
81 UserDao userDao = dbClient.userDao();
82 GroupDao groupDao = dbClient.groupDao();
83 Settings settings = new Settings();
85 HttpServletRequest request = mock(HttpServletRequest.class);
86 HttpServletResponse response = mock(HttpServletResponse.class);
88 UserUpdater userUpdater = new UserUpdater(
89 mock(NewUserNotifier.class),
92 mock(UserIndexer.class),
95 UserIdentityAuthenticator underTest = new UserIdentityAuthenticator(dbClient, userUpdater);
98 public void setUp() throws Exception {
99 settings.setProperty("sonar.defaultGroup", DEFAULT_GROUP);
100 addGroup(DEFAULT_GROUP);
104 public void authenticate_new_user() throws Exception {
105 underTest.authenticate(USER_IDENTITY, IDENTITY_PROVIDER);
108 UserDto userDto = userDao.selectByLogin(dbSession, USER_LOGIN);
109 assertThat(userDto).isNotNull();
110 assertThat(userDto.isActive()).isTrue();
111 assertThat(userDto.getName()).isEqualTo("John");
112 assertThat(userDto.getEmail()).isEqualTo("john@email.com");
113 assertThat(userDto.getExternalIdentity()).isEqualTo("johndoo");
114 assertThat(userDto.getExternalIdentityProvider()).isEqualTo("github");
116 verifyUserGroups(USER_LOGIN, DEFAULT_GROUP);
120 public void authenticate_new_user_with_groups() throws Exception {
124 underTest.authenticate(UserIdentity.builder()
125 .setProviderLogin("johndoo")
126 .setLogin(USER_LOGIN)
128 // group3 doesn't exist in db, it will be ignored
129 .setGroups(newHashSet("group1", "group2", "group3"))
130 .build(), IDENTITY_PROVIDER);
133 UserDto userDto = userDao.selectByLogin(dbSession, USER_LOGIN);
134 assertThat(userDto).isNotNull();
136 verifyUserGroups(USER_LOGIN, "group1", "group2");
140 public void authenticate_existing_user() throws Exception {
141 userDao.insert(dbSession, new UserDto()
142 .setLogin(USER_LOGIN)
145 .setEmail("Old email")
146 .setExternalIdentity("old identity")
147 .setExternalIdentityProvider("old provide"));
150 underTest.authenticate(USER_IDENTITY, IDENTITY_PROVIDER);
153 UserDto userDto = userDao.selectByLogin(dbSession, USER_LOGIN);
154 assertThat(userDto).isNotNull();
155 assertThat(userDto.isActive()).isTrue();
156 assertThat(userDto.getName()).isEqualTo("John");
157 assertThat(userDto.getEmail()).isEqualTo("john@email.com");
158 assertThat(userDto.getExternalIdentity()).isEqualTo("johndoo");
159 assertThat(userDto.getExternalIdentityProvider()).isEqualTo("github");
163 public void authenticate_existing_disabled_user() throws Exception {
164 userDao.insert(dbSession, new UserDto()
165 .setLogin(USER_LOGIN)
168 .setEmail("Old email")
169 .setExternalIdentity("old identity")
170 .setExternalIdentityProvider("old provide"));
173 underTest.authenticate(USER_IDENTITY, IDENTITY_PROVIDER);
176 UserDto userDto = userDao.selectByLogin(dbSession, USER_LOGIN);
177 assertThat(userDto).isNotNull();
178 assertThat(userDto.isActive()).isTrue();
179 assertThat(userDto.getName()).isEqualTo("John");
180 assertThat(userDto.getEmail()).isEqualTo("john@email.com");
181 assertThat(userDto.getExternalIdentity()).isEqualTo("johndoo");
182 assertThat(userDto.getExternalIdentityProvider()).isEqualTo("github");
186 public void authenticate_existing_user_and_add_new_groups() throws Exception {
187 userDao.insert(dbSession, new UserDto()
188 .setLogin(USER_LOGIN)
195 underTest.authenticate(UserIdentity.builder()
196 .setProviderLogin("johndoo")
197 .setLogin(USER_LOGIN)
199 // group3 doesn't exist in db, it will be ignored
200 .setGroups(newHashSet("group1", "group2", "group3"))
201 .build(), IDENTITY_PROVIDER);
204 Set<String> userGroups = new HashSet<>(dbClient.groupMembershipDao().selectGroupsByLogins(dbSession, singletonList(USER_LOGIN)).get(USER_LOGIN));
205 assertThat(userGroups).containsOnly("group1", "group2");
209 public void authenticate_existing_user_and_remove_groups() throws Exception {
210 UserDto user = new UserDto()
211 .setLogin(USER_LOGIN)
214 userDao.insert(dbSession, user);
216 GroupDto group1 = addGroup("group1");
217 GroupDto group2 = addGroup("group2");
218 dbClient.userGroupDao().insert(dbSession, new UserGroupDto().setUserId(user.getId()).setGroupId(group1.getId()));
219 dbClient.userGroupDao().insert(dbSession, new UserGroupDto().setUserId(user.getId()).setGroupId(group2.getId()));
222 Set<String> userGroups = new HashSet<>(dbClient.groupMembershipDao().selectGroupsByLogins(dbSession, singletonList(USER_LOGIN)).get(USER_LOGIN));
223 assertThat(userGroups).containsOnly("group1", "group2");
225 underTest.authenticate(UserIdentity.builder()
226 .setProviderLogin("johndoo")
227 .setLogin(USER_LOGIN)
229 // Only group1 is returned by the id provider => group2 will be removed
230 .setGroups(newHashSet("group1"))
231 .build(), IDENTITY_PROVIDER);
234 verifyUserGroups(USER_LOGIN, "group1");
238 public void authenticate_existing_user_and_remove_all_groups() throws Exception {
239 UserDto user = new UserDto()
240 .setLogin(USER_LOGIN)
243 userDao.insert(dbSession, user);
245 GroupDto group1 = addGroup("group1");
246 GroupDto group2 = addGroup("group2");
247 dbClient.userGroupDao().insert(dbSession, new UserGroupDto().setUserId(user.getId()).setGroupId(group1.getId()));
248 dbClient.userGroupDao().insert(dbSession, new UserGroupDto().setUserId(user.getId()).setGroupId(group2.getId()));
251 Set<String> userGroups = new HashSet<>(dbClient.groupMembershipDao().selectGroupsByLogins(dbSession, singletonList(USER_LOGIN)).get(USER_LOGIN));
252 assertThat(userGroups).containsOnly("group1", "group2");
254 underTest.authenticate(UserIdentity.builder()
255 .setProviderLogin("johndoo")
256 .setLogin(USER_LOGIN)
258 // No group => group1 and group2 will be removed
259 .setGroups(Collections.<String>emptySet())
260 .build(), IDENTITY_PROVIDER);
263 verifyNoUserGroups(USER_LOGIN);
267 public void fail_to_authenticate_new_user_when_allow_users_to_signup_is_false() throws Exception {
268 TestIdentityProvider identityProvider = new TestIdentityProvider()
272 .setAllowsUsersToSignUp(false);
274 thrown.expect(UnauthorizedException.class);
275 thrown.expectMessage("'github' users are not allowed to sign up");
276 underTest.authenticate(USER_IDENTITY, identityProvider);
280 public void fail_to_authenticate_new_user_when_email_already_exists() throws Exception {
281 UserDto userDto = UserTesting.newUserDto()
282 .setLogin("Existing user with same email")
284 .setEmail("john@email.com");
285 userDao.insert(dbSession, userDto);
288 thrown.expect(UnauthorizedException.class);
289 thrown.expectMessage("You can't sign up because email 'john@email.com' is already used by an existing user. " +
290 "This means that you probably already registered with another account.");
291 underTest.authenticate(USER_IDENTITY, IDENTITY_PROVIDER);
294 private void verifyUserGroups(String userLogin, String... groups) {
295 Set<String> userGroups = new HashSet<>(dbClient.groupMembershipDao().selectGroupsByLogins(dbSession, singletonList(USER_LOGIN)).get(userLogin));
296 assertThat(userGroups).containsOnly(groups);
299 private void verifyNoUserGroups(String userLogin) {
300 Set<String> userGroups = new HashSet<>(dbClient.groupMembershipDao().selectGroupsByLogins(dbSession, singletonList(USER_LOGIN)).get(userLogin));
301 assertThat(userGroups).isEmpty();
304 private GroupDto addGroup(String name) {
305 GroupDto group = new GroupDto().setName(name);
306 groupDao.insert(dbSession, group);