/* * Copyright 2017 ThoughtWorks, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.thoughtworks.go.server.service; import com.thoughtworks.go.config.*; import com.thoughtworks.go.domain.*; import com.thoughtworks.go.domain.Users; import com.thoughtworks.go.domain.config.Admin; import com.thoughtworks.go.domain.exception.ValidationException; import com.thoughtworks.go.helper.ConfigFileFixture; import com.thoughtworks.go.helper.UserRoleMatcherMother; import com.thoughtworks.go.i18n.Localizer; import com.thoughtworks.go.presentation.TriStateSelection; import com.thoughtworks.go.presentation.UserModel; import com.thoughtworks.go.presentation.UserSearchModel; import com.thoughtworks.go.presentation.UserSourceType; import com.thoughtworks.go.server.cache.GoCache; import com.thoughtworks.go.server.dao.DatabaseAccessHelper; import com.thoughtworks.go.server.dao.UserDao; import com.thoughtworks.go.server.domain.Username; import com.thoughtworks.go.server.domain.oauth.OauthAuthorization; import com.thoughtworks.go.server.domain.oauth.OauthClient; import com.thoughtworks.go.server.domain.oauth.OauthToken; import com.thoughtworks.go.server.persistence.OauthRepository; import com.thoughtworks.go.server.security.GoAuthority; import com.thoughtworks.go.server.service.result.HttpLocalizedOperationResult; import com.thoughtworks.go.server.util.UserHelper; import com.thoughtworks.go.util.GoConfigFileHelper; import com.thoughtworks.go.util.TriState; import org.hamcrest.CoreMatchers; import org.hamcrest.Matcher; import org.junit.After; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.orm.hibernate3.HibernateTemplate; import org.springframework.security.GrantedAuthority; import org.springframework.security.providers.UsernamePasswordAuthenticationToken; import org.springframework.test.context.ContextConfiguration; import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; import javax.servlet.http.HttpServletResponse; import java.util.ArrayList; import java.util.Arrays; import java.util.List; import static org.hamcrest.CoreMatchers.containsString; import static org.hamcrest.Matchers.instanceOf; import static org.hamcrest.core.Is.is; import static org.hamcrest.core.IsCollectionContaining.hasItem; import static org.hamcrest.core.IsNot.not; import static org.junit.Assert.assertThat; import static org.junit.Assert.fail; @RunWith(SpringJUnit4ClassRunner.class) @ContextConfiguration(locations = { "classpath:WEB-INF/applicationContext-global.xml", "classpath:WEB-INF/applicationContext-dataLocalAccess.xml", "classpath:WEB-INF/applicationContext-acegi-security.xml", "classpath:WEB-INF/spring-rest-servlet.xml" }) public class UserServiceIntegrationTest { @Autowired private UserDao userDao; @Autowired private UserService userService; @Autowired private GoConfigDao goConfigDao; @Autowired private DatabaseAccessHelper dbHelper; @Autowired private Localizer localizer; @Autowired private GoCache goCache; @Autowired private OauthRepository repo; private HibernateTemplate template; private static GoConfigFileHelper configFileHelper = new GoConfigFileHelper(ConfigFileFixture.XML_WITH_ENTERPRISE_LICENSE_FOR_TWO_USERS); private Username ROOT = new Username(new CaseInsensitiveString("root")); @Before public void setUp() throws Exception { dbHelper.onSetUp(); configFileHelper.onSetUp(); configFileHelper.usingCruiseConfigDao(goConfigDao); template = repo.getHibernateTemplate(); goCache.clear(); } @After public void teardown() throws Exception { configFileHelper.onTearDown(); dbHelper.onTearDown(); goCache.clear(); } @Test public void shouldSaveUser() throws ValidationException { User user = new User("name1", new String[]{"regx"}, "user@mail.com", true); userService.saveOrUpdate(user); User savedUser = userDao.findUser("name1"); assertThat(savedUser, is(user)); assertThat(userService.load(savedUser.getId()), is(user)); } @Test public void shouldUpdateWhenUserAlreadyExist() throws ValidationException { addUser(new User("name1", new String[]{"regx"}, "user@mail.com", true)); User updatedUser = userService.findUserByName("name1"); updatedUser.setEmail("user2@mail.com"); updatedUser.setMatcher("regx2"); userService.saveOrUpdate(updatedUser); User user = userDao.findUser("name1"); assertThat(user, is(updatedUser)); assertThat(user.getId(), is(updatedUser.getId())); } @Test public void addUserIfDoesNotExist_shouldAddUserIfDoesNotExist() throws Exception { UsernamePasswordAuthenticationToken auth = new UsernamePasswordAuthenticationToken(getAuthUser("new_user"), "credentials", new GrantedAuthority[]{GoAuthority.ROLE_USER.asAuthority()}); assertThat(userDao.findUser("new_user"), isANullUser()); userService.addUserIfDoesNotExist(UserHelper.getUser(auth)); User loadedUser = userDao.findUser("new_user"); assertThat(loadedUser, is(new User("new_user", "new_user", ""))); assertThat(loadedUser, not(isANullUser())); } @Test public void addUserIfDoesNotExist_shouldNotAddUserIfExists() throws Exception { User user = new User("old_user"); UsernamePasswordAuthenticationToken auth = new UsernamePasswordAuthenticationToken(getAuthUser("old_user"), "credentials", new GrantedAuthority[]{GoAuthority.ROLE_USER.asAuthority()}); addUser(user); userService.addUserIfDoesNotExist(UserHelper.getUser(auth)); } @Test public void addUserIfDoesNotExist_shouldNotAddUserIfAnonymous() throws Exception { userService.addUserIfDoesNotExist(new User(CaseInsensitiveString.str(Username.ANONYMOUS.getUsername()))); assertThat(userDao.findUser(CaseInsensitiveString.str(Username.ANONYMOUS.getUsername())), isANullUser()); assertThat(userDao.findUser(Username.ANONYMOUS.getDisplayName()), isANullUser()); } private org.springframework.security.userdetails.User getAuthUser(String userName) { return new org.springframework.security.userdetails.User(userName, "pass", true, true, true, true, new GrantedAuthority[]{GoAuthority.ROLE_USER.asAuthority()}); } @Test public void shouldvalidateUser() throws Exception { try { userService.validate(new User("username", new String[]{"committer"}, "mail.com", false)); fail("should have thrown when email is invalid"); } catch (ValidationException ignored) { } } @Test public void shouldNotSaveUserWhenValidationFailed() throws Exception { try { userService.saveOrUpdate(new User("username", new String[]{"committer"}, "mail.com", false)); fail("should have thrown when email is invalid"); } catch (ValidationException e) { assertThat(userService.findUserByName("username"), is(instanceOf(NullUser.class))); } } @Test public void shouldAddNotificationFilterForExistingUser() throws ValidationException { User user = new User("jez", new String[]{"jez"}, "user@mail.com", true); userService.saveOrUpdate(user); user = userDao.findUser(user.getName()); NotificationFilter filter = new NotificationFilter("cruise", "dev", StageEvent.Fixed, false); userService.addNotificationFilter(user.getId(), filter); user = userService.findUserByName("jez"); assertThat(user.getNotificationFilters().size(), is(1)); assertThat(user.getNotificationFilters(), hasItem(filter)); } @Test public void shouldRemoveNotificationFilterForUser() throws ValidationException { User user = new User("jez", new String[]{"jez"}, "user@mail.com", true); addUser(user); user = userDao.findUser(user.getName()); NotificationFilter filter = new NotificationFilter("cruise", "dev", StageEvent.Fixed, false); userService.addNotificationFilter(user.getId(), filter); user = userService.findUserByName(user.getName()); assertThat(user.getNotificationFilters().size(), is(1)); long deletedNotificationId = user.getNotificationFilters().get(0).getId(); userService.removeNotificationFilter(user.getId(), deletedNotificationId); assertThat(userService.findUserByName(user.getName()).getNotificationFilters().size(), is(0)); } @Test public void shouldNotAddDuplicateNotificationFilter() throws ValidationException { User user = new User("jez", new String[]{"jez"}, "user@mail.com", true); NotificationFilter filter = new NotificationFilter("cruise", "dev", StageEvent.Fixed, false); addUserWithNotificationFilter(user, filter); user = userDao.findUser(user.getName()); try { userService.addNotificationFilter(user.getId(), filter); fail("shouldNotAddDuplicateNotificationFilter"); } catch (Exception e) { assertThat(e.getMessage(), containsString("Duplicate notification filter")); } } @Test public void shouldNotAddUnnecessaryNotificationFilter() throws ValidationException { User user = new User("jez", new String[]{"jez"}, "user@mail.com", true); userService.saveOrUpdate(user); user = userDao.findUser(user.getName()); userService.addNotificationFilter(user.getId(), new NotificationFilter("cruise", "dev", StageEvent.Fixed, false)); try { userService.addNotificationFilter(user.getId(), new NotificationFilter("cruise", "dev", StageEvent.Fixed, false)); fail("shouldNotAddUnnecessaryNotificationFilter"); } catch (Exception e) { assertThat(e.getMessage(), containsString("Duplicate notification filter")); } } @Test public void shouldLoadUsersWhoSubscribedNotificationOnStage() { User tom = new User("tom", new String[]{"tom"}, "tom@mail.com", true); addUserWithNotificationFilter(tom, new NotificationFilter("p1", "s1", StageEvent.Breaks, true)); User jez = new User("jez", new String[]{"jez"}, "user@mail.com", true); addUserWithNotificationFilter(jez, new NotificationFilter("cruise", "dev", StageEvent.All, false), new NotificationFilter("mingle", "dev", StageEvent.All, false)); Users users = userService.findValidSubscribers(new StageConfigIdentifier("cruise", "dev")); assertThat(users.size(), is(1)); assertThat(users.get(0), is(jez)); assertThat(users.get(0).getNotificationFilters().size(), is(2)); } @Test public void shouldLoadAuthorizedUser() throws Exception { givingJezViewPermissionToMingle(); User tom = new User("tom", new String[]{"tom"}, "tom@mail.com", true); User jez = new User("jez", new String[]{"jez"}, "user@mail.com", true); addUserWithNotificationFilter(jez, new NotificationFilter("mingle", "dev", StageEvent.All, false)); addUserWithNotificationFilter(tom, new NotificationFilter("mingle", "dev", StageEvent.All, false)); Users users = userService.findValidSubscribers(new StageConfigIdentifier("mingle", "dev")); assertThat(users.size(), is(1)); assertThat(users.get(0), is(jez)); assertThat(users.get(0).getNotificationFilters().size(), is(1)); } @Test public void shouldCreateANewUser() throws Exception { UserSearchModel foo = new UserSearchModel(new User("fooUser", "Mr Foo", "foo@cruise.com"), UserSourceType.LDAP); HttpLocalizedOperationResult result = new HttpLocalizedOperationResult(); userService.create(Arrays.asList(foo), result); assertThat(result.isSuccessful(), is(true)); assertThat(result.message(localizer), is("User 'fooUser' successfully added.")); } @Test public void shouldReturnErrorWhenTryingToAddAnonymousUser() throws Exception { UserSearchModel anonymous = new UserSearchModel(new User(CaseInsensitiveString.str(Username.ANONYMOUS.getUsername()), "Mr. Anonymous", "anon@cruise.com"), UserSourceType.LDAP); HttpLocalizedOperationResult result = new HttpLocalizedOperationResult(); userService.create(Arrays.asList(anonymous), result); assertThat(result.isSuccessful(), is(false)); assertThat(result.message(localizer), is("Failed to add user. Username 'anonymous' is not permitted.")); } @Test public void shouldReturnErrorWhenUserAlreadyExists() throws Exception { UserSearchModel foo = new UserSearchModel(new User("fooUser", "Mr Foo", "foo@cruise.com"), UserSourceType.LDAP); addUser(foo.getUser()); HttpLocalizedOperationResult result = new HttpLocalizedOperationResult(); userService.create(Arrays.asList(foo), result); assertThat(result.isSuccessful(), is(false)); assertThat(result.message(localizer), is("Failed to add user. The user 'fooUser' already exists.")); } @Test public void create_shouldReturnErrorWhenNoUsersSelected() throws Exception { HttpLocalizedOperationResult result = new HttpLocalizedOperationResult(); userService.create(new ArrayList<>(), result); assertThat(result.isSuccessful(), is(false)); assertThat(result.message(localizer), is("No users selected.")); } @Test public void disableUsers_shouldAlsoExpireOauthTokens() throws Exception { addUser(new User("user_one")); addUser(new User("user_two")); generateOauthTokenFor("user_one"); HttpLocalizedOperationResult result = new HttpLocalizedOperationResult(); userService.disable(Arrays.asList("user_one"), result); assertThat(result.isSuccessful(), is(true)); List<UserModel> models = userService.allUsersForDisplay(UserService.SortableColumn.USERNAME, UserService.SortDirection.ASC); assertThat("user should be disabled", models.get(0).isEnabled(), is(false)); assertThat("user should be enabled", models.get(1).isEnabled(), is(true)); assertThat(template.find("from OauthAuthorization").size(), is(0)); assertThat(template.find("from OauthToken").size(), is(0)); } private void generateOauthTokenFor(String userId) { OauthClient mingle = new OauthClient("mingle09", "client_id", "client_secret", "http://some-tracking-tool"); template.save(mingle); OauthAuthorization authorization = new OauthAuthorization(userId, mingle, "code", 332333); template.save(authorization); OauthToken oauthToken = new OauthToken(userId, mingle, "access-token", "refresh-token", 23324324); template.save(oauthToken); } @Test public void shouldEnableUsers() throws Exception { HttpLocalizedOperationResult result = new HttpLocalizedOperationResult(); User user1 = new User("user_one"); user1.disable(); addUser(user1); createDisabledUser("user_two"); userService.enable(Arrays.asList("user_one"), new HttpLocalizedOperationResult()); assertThat(result.isSuccessful(), is(true)); List<UserModel> models = userService.allUsersForDisplay(UserService.SortableColumn.USERNAME, UserService.SortDirection.ASC); assertThat("user should be enabled", models.get(0).isEnabled(), is(true)); assertThat("user should be disabled", models.get(1).isEnabled(), is(false)); } @Test public void shouldKnowEnabledAndDisbaledUsersCount() throws Exception { addUser(new User("user_one")); addUser(new User("user_three")); createDisabledUser("user_two"); assertThat(userService.enabledUserCount(), is(2)); assertThat(userService.disabledUserCount(), is(1)); } @Test public void shouldReturnErrorMessageWhenUserValidationsFail() throws Exception { HttpLocalizedOperationResult result = new HttpLocalizedOperationResult(); User invalidUser = new User("fooUser", "Foo User", "invalidEmail"); UserSearchModel searchModel = new UserSearchModel(invalidUser, UserSourceType.LDAP); userService.create(Arrays.asList(searchModel), result); assertThat(result.isSuccessful(), is(false)); assertThat(result.message(localizer), is("Failed to add user. Validations failed. Invalid email address.")); } @Test public void shouldDeleteAllUsers() throws Exception { UserSearchModel foo = new UserSearchModel(new User("fooUser", "Mr Foo", "foo@cruise.com")); HttpLocalizedOperationResult result = new HttpLocalizedOperationResult(); userService.create(Arrays.asList(foo), result); assertThat(userService.allUsersForDisplay(UserService.SortableColumn.EMAIL, UserService.SortDirection.ASC).size(), is(1)); userService.deleteAll(); assertThat(userService.allUsersForDisplay(UserService.SortableColumn.EMAIL, UserService.SortDirection.ASC).size(), is(0)); } @Test public void shouldReturnErrorMessageWhenTheLastAdminIsBeingDisabled() throws Exception { HttpLocalizedOperationResult result = new HttpLocalizedOperationResult(); configFileHelper.turnOnSecurity(); configFileHelper.addAdmins("Jake", "Pavan", "Yogi"); userService.create(users("Jake", "Pavan", "Shilpa", "Yogi"), new HttpLocalizedOperationResult()); userService.disable(Arrays.asList("Yogi"), result); assertThat(result.isSuccessful(), is(true)); userService.disable(Arrays.asList("Pavan", "Jake"), result);//disable remaining admins assertThat(result.isSuccessful(), is(false)); assertThat(result.httpCode(), is(HttpServletResponse.SC_BAD_REQUEST)); assertThat(result.message(localizer), is("Did not disable any of the selected users. Ensure that all configured admins are not being disabled.")); } @Test public void modifyRoles_shouldAddUserToExistingRole() throws Exception { configFileHelper.addRole(new RoleConfig(new CaseInsensitiveString("dev"))); addUser(new User("user-1")); HttpLocalizedOperationResult result = new HttpLocalizedOperationResult(); userService.modifyRolesAndUserAdminPrivileges(Arrays.asList("user-1"), new TriStateSelection(Admin.GO_SYSTEM_ADMIN, TriStateSelection.Action.nochange), Arrays.asList(new TriStateSelection("dev", TriStateSelection.Action.add)), result); CruiseConfig cruiseConfig = goConfigDao.load(); assertThat(cruiseConfig.server().security().getRoles().findByName(new CaseInsensitiveString("dev")).hasMember(new CaseInsensitiveString("user-1")), is(true)); assertThat(result.isSuccessful(), is(true)); } @Test public void modifyRoles_shouldNotAddUserToExistingRoleIfAlreadyAMember() throws Exception { addUser(new User("user-1")); // first time userService.modifyRolesAndUserAdminPrivileges(Arrays.asList("user-1"), new TriStateSelection(Admin.GO_SYSTEM_ADMIN, TriStateSelection.Action.nochange), Arrays.asList(new TriStateSelection("dev", TriStateSelection.Action.add)), new HttpLocalizedOperationResult()); // second time userService.modifyRolesAndUserAdminPrivileges(Arrays.asList("user-1"), new TriStateSelection(Admin.GO_SYSTEM_ADMIN, TriStateSelection.Action.nochange), Arrays.asList(new TriStateSelection("dev", TriStateSelection.Action.add)), new HttpLocalizedOperationResult()); CruiseConfig cruiseConfig = goConfigDao.load(); assertThat(cruiseConfig.server().security().getRoles().findByName(new CaseInsensitiveString("dev")).hasMember(new CaseInsensitiveString("user-1")), is(true)); } @Test public void modifyRoles_shouldCreateRoleAndAddUserIfRoleDoesntExist() throws Exception { addUser(new User("user-1")); userService.modifyRolesAndUserAdminPrivileges(Arrays.asList("user-1"), new TriStateSelection(Admin.GO_SYSTEM_ADMIN, TriStateSelection.Action.nochange), Arrays.asList(new TriStateSelection("dev", TriStateSelection.Action.add)), new HttpLocalizedOperationResult()); CruiseConfig cruiseConfig = goConfigDao.load(); assertThat(cruiseConfig.server().security().getRoles().findByName(new CaseInsensitiveString("dev")).hasMember(new CaseInsensitiveString("user-1")), is(true)); } @Test public void modifyRoles_shouldNotCreateRoleIfItHasInvalidCharacters() throws Exception { addUser(new User("user-1")); HttpLocalizedOperationResult result = new HttpLocalizedOperationResult(); userService.modifyRolesAndUserAdminPrivileges(Arrays.asList("user-1"), new TriStateSelection(Admin.GO_SYSTEM_ADMIN, TriStateSelection.Action.nochange), Arrays.asList(new TriStateSelection(".dev+", TriStateSelection.Action.add)), result); assertThat(result.isSuccessful(), is(false)); assertThat(result.message(localizer), containsString("Failed to add role. Reason - ")); } @Test public void modifyRoles_shouldRemoveUserFromRole() throws Exception { addUser(new User("user-1")); // add it first userService.modifyRolesAndUserAdminPrivileges(Arrays.asList("user-1"), new TriStateSelection(Admin.GO_SYSTEM_ADMIN, TriStateSelection.Action.nochange), Arrays.asList(new TriStateSelection("dev", TriStateSelection.Action.add)), new HttpLocalizedOperationResult()); // now remove it userService.modifyRolesAndUserAdminPrivileges(Arrays.asList("user-1"), new TriStateSelection(Admin.GO_SYSTEM_ADMIN, TriStateSelection.Action.nochange), Arrays.asList(new TriStateSelection("dev", TriStateSelection.Action.remove)), new HttpLocalizedOperationResult()); CruiseConfig cruiseConfig = goConfigDao.load(); assertThat(cruiseConfig.server().security().getRoles().findByName(new CaseInsensitiveString("dev")).hasMember(new CaseInsensitiveString("user-1")), is(false)); } @Test public void modifyRoles_shouldNotModifyRolesWhenActionIsNoChange() throws Exception { addUser(new User("user-1")); // add it first userService.modifyRolesAndUserAdminPrivileges(Arrays.asList("user-1"), new TriStateSelection(Admin.GO_SYSTEM_ADMIN, TriStateSelection.Action.nochange), Arrays.asList(new TriStateSelection("dev", TriStateSelection.Action.add)), new HttpLocalizedOperationResult()); // no change userService.modifyRolesAndUserAdminPrivileges(Arrays.asList("user-1"), new TriStateSelection(Admin.GO_SYSTEM_ADMIN, TriStateSelection.Action.nochange), Arrays.asList(new TriStateSelection("dev", TriStateSelection.Action.nochange)), new HttpLocalizedOperationResult()); CruiseConfig cruiseConfig = goConfigDao.load(); assertThat(cruiseConfig.server().security().getRoles().findByName(new CaseInsensitiveString("dev")).hasMember(new CaseInsensitiveString("user-1")), is(true)); } @Test public void modifyRoles_shouldNotModifyRolesForAUserThatDoesNotExistInDb() throws Exception { assertThat(userDao.findUser("user-1"), is(instanceOf(NullUser.class))); HttpLocalizedOperationResult result = new HttpLocalizedOperationResult(); userService.modifyRolesAndUserAdminPrivileges(Arrays.asList("user-1"), new TriStateSelection(Admin.GO_SYSTEM_ADMIN, TriStateSelection.Action.nochange), Arrays.asList(new TriStateSelection("dev", TriStateSelection.Action.add)), result); assertThat(userDao.findUser("user-1"), is(instanceOf(NullUser.class))); assertThat(result.isSuccessful(), is(false)); assertThat(result.message(localizer), containsString("User 'user-1' does not exist in the database.")); } @Test public void shouldModifyRolesAndAdminPrivilegeAtTheSameTime() throws Exception { configFileHelper.addRole(new RoleConfig(new CaseInsensitiveString("dev"))); addUser(new User("user-1")); HttpLocalizedOperationResult result = new HttpLocalizedOperationResult(); userService.modifyRolesAndUserAdminPrivileges(Arrays.asList("user-1"), new TriStateSelection(Admin.GO_SYSTEM_ADMIN, TriStateSelection.Action.add), Arrays.asList(new TriStateSelection("dev", TriStateSelection.Action.add)), result); CruiseConfig cruiseConfig = goConfigDao.load(); assertThat(cruiseConfig.server().security().getRoles().findByName(new CaseInsensitiveString("dev")).hasMember(new CaseInsensitiveString("user-1")), is(true)); assertThat(cruiseConfig.server().security().adminsConfig().hasUser(new CaseInsensitiveString("user-1"), UserRoleMatcherMother.ALWAYS_FALSE_MATCHER), is(true)); assertThat(result.isSuccessful(), is(true)); } @Test public void shouldAddAdminPrivilegeToMultipleUsers() throws Exception { addUser(new User("user")); addUser(new User("loser")); addUser(new User("boozer")); HttpLocalizedOperationResult result = new HttpLocalizedOperationResult(); userService.modifyRolesAndUserAdminPrivileges(Arrays.asList("user", "boozer"), new TriStateSelection(Admin.GO_SYSTEM_ADMIN, TriStateSelection.Action.add), new ArrayList<>(), result); CruiseConfig cruiseConfig = goConfigDao.load(); final AdminsConfig adminsConfig = cruiseConfig.server().security().adminsConfig(); assertThat(adminsConfig.hasUser(new CaseInsensitiveString("user"), UserRoleMatcherMother.ALWAYS_FALSE_MATCHER), is(true)); assertThat(adminsConfig.hasUser(new CaseInsensitiveString("loser"), UserRoleMatcherMother.ALWAYS_FALSE_MATCHER), is(false)); assertThat(adminsConfig.hasUser(new CaseInsensitiveString("boozer"), UserRoleMatcherMother.ALWAYS_FALSE_MATCHER), is(true)); assertThat(result.isSuccessful(), is(true)); } @Test public void shouldRemoveUserLevelAdminPrivilegeFromMultipleUsers_withoutModifingRoleLevelPrvileges() throws Exception { configFileHelper.addAdmins("user", "boozer"); configFileHelper.addRole(new RoleConfig(new CaseInsensitiveString("mastersOfTheWorld"), new RoleUser(new CaseInsensitiveString("loser")), new RoleUser(new CaseInsensitiveString("boozer")))); configFileHelper.addAdminRoles("mastersOfTheWorld"); addUser(new User("user")); addUser(new User("loser")); addUser(new User("boozer")); CruiseConfig cruiseConfig = goConfigDao.load(); SecurityConfig securityConfig = cruiseConfig.server().security(); AdminsConfig adminsConfig = securityConfig.adminsConfig(); assertThat(adminsConfig.hasUser(new CaseInsensitiveString("user"), UserRoleMatcherMother.ALWAYS_FALSE_MATCHER), is(true)); assertThat(adminsConfig.hasUser(new CaseInsensitiveString("loser"), UserRoleMatcherMother.ALWAYS_FALSE_MATCHER), is(false)); assertThat(adminsConfig.hasUser(new CaseInsensitiveString("boozer"), UserRoleMatcherMother.ALWAYS_FALSE_MATCHER), is(true)); HttpLocalizedOperationResult result = new HttpLocalizedOperationResult(); userService.modifyRolesAndUserAdminPrivileges(Arrays.asList("user", "boozer"), new TriStateSelection(Admin.GO_SYSTEM_ADMIN, TriStateSelection.Action.remove), new ArrayList<>(), result); cruiseConfig = goConfigDao.load(); securityConfig = cruiseConfig.server().security(); adminsConfig = securityConfig.adminsConfig(); assertThat(adminsConfig.hasUser(new CaseInsensitiveString("user"), UserRoleMatcherMother.ALWAYS_FALSE_MATCHER), is(false)); assertThat(adminsConfig.hasUser(new CaseInsensitiveString("loser"), UserRoleMatcherMother.ALWAYS_FALSE_MATCHER), is(false)); assertThat(adminsConfig.hasUser(new CaseInsensitiveString("boozer"), UserRoleMatcherMother.ALWAYS_FALSE_MATCHER), is(false)); final SecurityService.UserRoleMatcherImpl groupMatcher = new SecurityService.UserRoleMatcherImpl(securityConfig); assertThat(adminsConfig.hasUser(new CaseInsensitiveString("user"), groupMatcher), is(false)); assertThat(adminsConfig.hasUser(new CaseInsensitiveString("loser"), groupMatcher), is(true)); assertThat(adminsConfig.hasUser(new CaseInsensitiveString("boozer"), groupMatcher), is(true)); assertThat(result.isSuccessful(), is(true)); } @Test public void shouldNotModifyAdminPrivilegesWhen_NoChange_requested() throws Exception { configFileHelper.addAdmins("user", "boozer"); configFileHelper.addRole(new RoleConfig(new CaseInsensitiveString("mastersOfTheWorld"), new RoleUser(new CaseInsensitiveString("loser")), new RoleUser(new CaseInsensitiveString("boozer")))); configFileHelper.addAdminRoles("mastersOfTheWorld"); addUser(new User("user")); addUser(new User("loser")); addUser(new User("boozer")); HttpLocalizedOperationResult result = new HttpLocalizedOperationResult(); userService.modifyRolesAndUserAdminPrivileges(Arrays.asList("user", "boozer"), new TriStateSelection(Admin.GO_SYSTEM_ADMIN, TriStateSelection.Action.nochange), new ArrayList<>(), result); final CruiseConfig cruiseConfig = goConfigDao.load(); final SecurityConfig securityConfig = cruiseConfig.server().security(); final AdminsConfig adminsConfig = securityConfig.adminsConfig(); assertThat(adminsConfig.hasUser(new CaseInsensitiveString("user"), UserRoleMatcherMother.ALWAYS_FALSE_MATCHER), is(true)); assertThat(adminsConfig.hasUser(new CaseInsensitiveString("loser"), UserRoleMatcherMother.ALWAYS_FALSE_MATCHER), is(false)); assertThat(adminsConfig.hasUser(new CaseInsensitiveString("boozer"), UserRoleMatcherMother.ALWAYS_FALSE_MATCHER), is(true)); assertThat(result.isSuccessful(), is(true)); } @Test public void getRoleSelection() throws Exception { configFileHelper.addRole(new RoleConfig(new CaseInsensitiveString("dev"))); configFileHelper.addRole(new RoleConfig(new CaseInsensitiveString("boy"))); configFileHelper.addRole(new RoleConfig(new CaseInsensitiveString("girl"))); configFileHelper.addRole(new RoleConfig(new CaseInsensitiveString("none"))); addUser(new User("yogi")); addUser(new User("shilpa")); addUser(new User("pavan")); userService.modifyRolesAndUserAdminPrivileges(Arrays.asList("yogi", "shilpa"), new TriStateSelection(Admin.GO_SYSTEM_ADMIN, TriStateSelection.Action.nochange), Arrays.asList(new TriStateSelection("dev", TriStateSelection.Action.add)), new HttpLocalizedOperationResult()); userService.modifyRolesAndUserAdminPrivileges(Arrays.asList("shilpa"), new TriStateSelection(Admin.GO_SYSTEM_ADMIN, TriStateSelection.Action.nochange), Arrays.asList(new TriStateSelection("girl", TriStateSelection.Action.add)), new HttpLocalizedOperationResult()); userService.modifyRolesAndUserAdminPrivileges(Arrays.asList("yogi"), new TriStateSelection(Admin.GO_SYSTEM_ADMIN, TriStateSelection.Action.nochange), Arrays.asList(new TriStateSelection("boy", TriStateSelection.Action.add)), new HttpLocalizedOperationResult()); userService.modifyRolesAndUserAdminPrivileges(Arrays.asList("pavan"), new TriStateSelection(Admin.GO_SYSTEM_ADMIN, TriStateSelection.Action.nochange), Arrays.asList(new TriStateSelection("none", TriStateSelection.Action.add)), new HttpLocalizedOperationResult()); List<TriStateSelection> selections = userService.getAdminAndRoleSelections(Arrays.asList("yogi", "shilpa")).getRoleSelections(); assertThat(selections.size(), is(4)); assertRoleSelection(selections.get(0), "boy", TriStateSelection.Action.nochange); assertRoleSelection(selections.get(1), "dev", TriStateSelection.Action.add); assertRoleSelection(selections.get(2), "girl", TriStateSelection.Action.nochange); assertRoleSelection(selections.get(3), "none", TriStateSelection.Action.remove); } @Test public void getRoleSelectionOnlyForNonPluginRoles() throws Exception { configFileHelper.addSecurityAuthConfig(new SecurityAuthConfig("auth_id", "plugin_id")); configFileHelper.addRole(new RoleConfig(new CaseInsensitiveString("core-role"))); configFileHelper.addRole(new PluginRoleConfig("plugin-role", "auth_id")); addUser(new User("yogi")); addUser(new User("shilpa")); userService.modifyRolesAndUserAdminPrivileges(Arrays.asList("yogi", "shilpa"), new TriStateSelection(Admin.GO_SYSTEM_ADMIN, TriStateSelection.Action.nochange), Arrays.asList(new TriStateSelection("core-role", TriStateSelection.Action.add)), new HttpLocalizedOperationResult()); List<TriStateSelection> selections = userService.getAdminAndRoleSelections(Arrays.asList("yogi", "shilpa")).getRoleSelections(); assertThat(selections.size(), is(1)); assertRoleSelection(selections.get(0), "core-role", TriStateSelection.Action.add); } @Test public void shouldGetAdminSelectionWithCorrectState() throws Exception { configFileHelper.addAdmins("foo", "quux"); assertThat(userService.getAdminAndRoleSelections(Arrays.asList("foo")).getAdminSelection(), is(new TriStateSelection(Admin.GO_SYSTEM_ADMIN, TriStateSelection.Action.add))); assertThat(userService.getAdminAndRoleSelections(Arrays.asList("foo", "bar")).getAdminSelection(), is(new TriStateSelection(Admin.GO_SYSTEM_ADMIN, TriStateSelection.Action.nochange))); assertThat(userService.getAdminAndRoleSelections(Arrays.asList("foo", "quux")).getAdminSelection(), is(new TriStateSelection(Admin.GO_SYSTEM_ADMIN, TriStateSelection.Action.add))); assertThat(userService.getAdminAndRoleSelections(Arrays.asList("baz", "bar")).getAdminSelection(), is(new TriStateSelection(Admin.GO_SYSTEM_ADMIN, TriStateSelection.Action.remove))); } @Test public void shouldDisableAdminSelectionWhenUserIsMemberOfAdminRole() throws Exception { configFileHelper.addRole(new RoleConfig(new CaseInsensitiveString("foo-grp"), new RoleUser(new CaseInsensitiveString("foo")), new RoleUser(new CaseInsensitiveString("foo-one")))); configFileHelper.addRole(new RoleConfig(new CaseInsensitiveString("quux-grp"), new RoleUser(new CaseInsensitiveString("quux")))); configFileHelper.addRole(new RoleConfig(new CaseInsensitiveString("bar-grp"), new RoleUser(new CaseInsensitiveString("bar")), new RoleUser(new CaseInsensitiveString("bar-one")))); configFileHelper.addAdminRoles("foo-grp", "quux-grp"); assertThat(userService.getAdminAndRoleSelections(Arrays.asList("foo")).getAdminSelection(), is(new TriStateSelection(Admin.GO_SYSTEM_ADMIN, TriStateSelection.Action.add, false))); assertThat(userService.getAdminAndRoleSelections(Arrays.asList("foo", "bar")).getAdminSelection(), is(new TriStateSelection(Admin.GO_SYSTEM_ADMIN, TriStateSelection.Action.nochange, false))); assertThat(userService.getAdminAndRoleSelections(Arrays.asList("bar", "baz")).getAdminSelection(), is(new TriStateSelection(Admin.GO_SYSTEM_ADMIN, TriStateSelection.Action.remove))); assertThat(userService.getAdminAndRoleSelections(Arrays.asList("baz")).getAdminSelection(), is(new TriStateSelection(Admin.GO_SYSTEM_ADMIN, TriStateSelection.Action.remove))); assertThat(userService.getAdminAndRoleSelections(Arrays.asList("foo", "quux")).getAdminSelection(), is(new TriStateSelection(Admin.GO_SYSTEM_ADMIN, TriStateSelection.Action.add, false))); } @Test public void shouldUpdateEnabledStateToFalse() throws Exception { User user = new User("user-1"); user.enable(); addUser(user); HttpLocalizedOperationResult result = new HttpLocalizedOperationResult(); userService.save(user, TriState.FALSE, TriState.UNSET, null, null, result); assertThat(result.isSuccessful(), is(true)); assertThat(user.isEnabled(), is(false)); } @Test public void shouldUpdateEnabledStateToTrue() throws Exception { User user = new User("user-1"); user.disable(); addUser(user); HttpLocalizedOperationResult result = new HttpLocalizedOperationResult(); userService.save(user, TriState.TRUE, TriState.UNSET, null, null, result); assertThat(result.isSuccessful(), is(true)); assertThat(user.isEnabled(), is(true)); } @Test public void shouldNotUpdateEnabledStateWhenAskedToBeLeftUnset() throws Exception { User user = new User("user-1"); user.disable(); addUser(user); HttpLocalizedOperationResult result = new HttpLocalizedOperationResult(); userService.save(user, TriState.UNSET, TriState.UNSET, null, null, result); assertThat(user.isEnabled(), is(false)); } @Test public void updateShouldUpdateEmailMeStateToTrue() throws Exception { User user = new User("user-1"); user.enable(); user.setEmailMe(false); addUser(user); HttpLocalizedOperationResult result = new HttpLocalizedOperationResult(); userService.save(user, TriState.UNSET, TriState.TRUE, null, null, result); assertThat(result.isSuccessful(), is(true)); assertThat(user.isEmailMe(), is(true)); } @Test public void updateShouldUpdateEmailMeStateToFalse() throws Exception { User user = new User("user-1"); user.enable(); user.setEmailMe(true); addUser(user); HttpLocalizedOperationResult result = new HttpLocalizedOperationResult(); userService.save(user, TriState.UNSET, TriState.FALSE, null, null, result); assertThat(result.isSuccessful(), is(true)); assertThat(user.isEmailMe(), is(false)); } @Test public void updateShouldUpdateEmailMeStateWHenAskedToBeLeftUnset() throws Exception { User user = new User("user-1"); user.enable(); user.setEmailMe(true); addUser(user); HttpLocalizedOperationResult result = new HttpLocalizedOperationResult(); userService.save(user, TriState.UNSET, TriState.UNSET, null, null, result); assertThat(user.isEmailMe(), is(true)); } @Test public void updateShouldUpdateEmail() throws Exception { User user = new User("user-1"); addUser(user); HttpLocalizedOperationResult result = new HttpLocalizedOperationResult(); userService.save(user, TriState.UNSET, TriState.UNSET, "foo@example.com", null, result); assertThat(result.isSuccessful(), is(true)); assertThat(user.getEmail(), is("foo@example.com")); result = new HttpLocalizedOperationResult(); userService.save(user, TriState.TRUE, TriState.UNSET, "", null, result); assertThat(result.isSuccessful(), is(true)); assertThat(user.getEmail(), is("")); } @Test public void updateShouldNotUpdateEmailWhenNull() throws Exception { User user = new User("user-1"); user.setEmail("foo@example.com"); addUser(user); HttpLocalizedOperationResult result = new HttpLocalizedOperationResult(); userService.save(user, TriState.UNSET, TriState.UNSET, null, null, result); assertThat(result.isSuccessful(), is(true)); assertThat(user.getEmail(), is("foo@example.com")); } @Test public void updateShouldUpdateMatcher() throws Exception { User user = new User("user-1"); addUser(user); HttpLocalizedOperationResult result = new HttpLocalizedOperationResult(); userService.save(user, TriState.UNSET, TriState.UNSET, null, "foo,bar", result); assertThat(result.isSuccessful(), is(true)); assertThat(user.getMatcher(), is("foo,bar")); result = new HttpLocalizedOperationResult(); userService.save(user, TriState.UNSET, TriState.UNSET, null, "", result); assertThat(result.isSuccessful(), is(true)); assertThat(user.getMatcher(), is("")); } @Test public void updateShouldNotUpdateMatcherWhenNull() throws Exception { User user = new User("user-1"); user.setMatcher("foo,bar"); addUser(user); HttpLocalizedOperationResult result = new HttpLocalizedOperationResult(); userService.save(user, TriState.UNSET, TriState.UNSET, null, null, result); assertThat(result.isSuccessful(), is(true)); assertThat(user.getMatcher(), is("foo,bar")); } private void assertRoleSelection(TriStateSelection selection, String roleName, TriStateSelection.Action action) { assertThat(selection.getValue(), is(roleName)); assertThat(selection.getAction(), is(action)); } private void createDisabledUser(String username) { User user = new User(username); user.disable(); addUser(user); } private List<UserSearchModel> users(String... usernames) { List<UserSearchModel> models = new ArrayList<>(); for (String username : usernames) { models.add(new UserSearchModel(new User(username, username, "foo@cruise.com"))); } return models; } private void givingJezViewPermissionToMingle() throws Exception { configFileHelper.turnOnSecurity(); configFileHelper.addPipeline("mingle", "dev"); configFileHelper.setViewPermissionForGroup("defaultGroup", "jez"); configFileHelper.addSecurityWithAdminConfig(); } private void addUser(User user) { userDao.saveOrUpdate(user); } private void addUserWithNotificationFilter(User user, NotificationFilter... filters) { for (NotificationFilter filter : filters) { user.addNotificationFilter(filter); } addUser(user); } private Matcher<? super User> isANullUser() { return is(CoreMatchers.<Object>instanceOf(NullUser.class)); } }