package teamcity.crowd.plugin.loginmodule; import com.atlassian.crowd.model.group.Group; import com.atlassian.crowd.model.user.User; import com.google.common.base.Function; import com.google.common.base.Optional; import com.google.common.base.Predicate; import com.google.common.base.Strings; import com.google.common.collect.Collections2; import com.google.common.collect.Lists; import com.intellij.openapi.diagnostic.Logger; import jetbrains.buildServer.groups.SUserGroup; import jetbrains.buildServer.groups.UserGroup; import jetbrains.buildServer.groups.UserGroupManager; import jetbrains.buildServer.serverSide.auth.ServerPrincipal; import jetbrains.buildServer.users.SUser; import jetbrains.buildServer.users.UserModel; import teamcity.crowd.plugin.CrowdPluginAuthenticationScheme; import teamcity.crowd.plugin.PluginCrowdClient; import teamcity.crowd.plugin.utils.CrowdPluginConfiguration; import teamcity.crowd.plugin.utils.LoggerFactory; import javax.annotation.Nullable; import java.util.List; import static java.lang.String.format; public class LoggedInUserService { private final GroupNameToGroupKey groupNameToGroupKey; private final UserGroupManager userGroupManager; private final PluginCrowdClient pluginCrowdClient; private final UserModel userModel; private final LoggerFactory loggerFactory; private boolean shouldCreateGroups = false; private boolean doNotRemoveInternalGroups = false; public static final String ALL_USERS_GROUP = "All Users"; public static final String CREATED_BY_PLUGIN_MESSAGE = "Created by Crowd Plugin"; public LoggedInUserService( UserGroupManager userGroupManager, PluginCrowdClient pluginCrowdClient, UserModel userModel, LoggerFactory loggerFactory, CrowdPluginConfiguration crowdPluginConfiguration) { groupNameToGroupKey = new GroupNameToGroupKey(userGroupManager); this.userGroupManager = userGroupManager; this.pluginCrowdClient = pluginCrowdClient; this.userModel = userModel; this.loggerFactory = loggerFactory; this.shouldCreateGroups = crowdPluginConfiguration.shouldCreateGroups(); this.doNotRemoveInternalGroups = crowdPluginConfiguration.doNotRemoveInternalGroups(); } public ServerPrincipal updateMembership(User user) { final Optional<SUser> possibleAccount = findUserAccountFor(user); SUser teamCityUser; if (!possibleAccount.isPresent()) { teamCityUser = createUserAccount(user); } else { teamCityUser = updateUserDetails(possibleAccount.get(), user); } updateUserGroups(teamCityUser); return new ServerPrincipal(CrowdPluginAuthenticationScheme.REALM, user.getName()); } private SUser updateUserDetails(SUser teamCityUser, User user) { final jetbrains.buildServer.users.User associatedUser = teamCityUser.getAssociatedUser(); if ( ! associatedUser.getName().equals(user.getDisplayName()) || ! associatedUser.getEmail().equals(user.getEmailAddress()) ) { teamCityUser.updateUserAccount(user.getName(), user.getDisplayName(), user.getEmailAddress()); } return teamCityUser; } private void updateUserGroups(SUser teamCityUser) { Logger logger = loggerFactory.getServerLogger(); final List<String> userGroupsInCrowd = userGroupsInCrowd(teamCityUser); final List<String> allTeamCityGroupsUserIsAMemberOfAlready = allTeamCityUserGroups(teamCityUser); final List<String> listOfGropusUserShouldBeRemovedFrom = groupsToBeRemovedFrom( doNotRemoveInternalGroups ? allTeamCityNonInternalUserGroups(teamCityUser) : allTeamCityGroupsUserIsAMemberOfAlready, userGroupsInCrowd); for (String userGroup : userGroupsInCrowd) { if (!allTeamCityGroupsUserIsAMemberOfAlready.contains(userGroup)) { SUserGroup teamCityGroup = userGroupManager.findUserGroupByName(userGroup); if (teamCityGroup == null && shouldCreateGroups) { Optional<String> groupKey = groupNameToGroupKey.transform(userGroup); if ( groupKey.isPresent() ) { teamCityGroup = userGroupManager.createUserGroup( groupKey.get(), userGroup, CREATED_BY_PLUGIN_MESSAGE); } } if (teamCityGroup != null) { teamCityGroup.addUser(teamCityUser); logger.info(format("Added user [%s] to group [%s]", teamCityUser.getUsername(), userGroup)); } } } for (String groupName : listOfGropusUserShouldBeRemovedFrom) { logger.info(format("Removing user [%s] from group [%s]", teamCityUser.getUsername(), groupName)); final SUserGroup teamCityGroup = userGroupManager.findUserGroupByName(groupName); teamCityGroup.removeUser(teamCityUser); } teamCityUser.getUserGroups(); } private List<String> groupsToBeRemovedFrom(List<String> temCityGroups, final List<String> crowdGroups) { return Lists.newArrayList(Collections2.filter(temCityGroups, new Predicate<String>() { @Override public boolean apply(String input) { return !crowdGroups.contains(input) && !ALL_USERS_GROUP.toLowerCase().equals(input.toLowerCase()); } })); } private List<String> userGroupsInCrowd(SUser teamCityUser) { return Lists.newArrayList(Collections2.transform( pluginCrowdClient.getUserGroups(teamCityUser.getUsername()), new Function<Group, String>() { @Override public String apply(@Nullable Group input) { return input.getName(); } })); } private List<String> allTeamCityUserGroups(SUser teamCityUser) { return Lists.newArrayList(Collections2.transform( teamCityUser.getUserGroups(), new Function<UserGroup, String>() { @Override public String apply(@Nullable UserGroup input) { return input.getName(); } })); } private List<String> allTeamCityNonInternalUserGroups(SUser teamCityUser) { return Lists.newArrayList( Collections2.filter( Collections2.transform( teamCityUser.getUserGroups(), new Function<UserGroup, String>() { @Override public String apply(@Nullable UserGroup input) { if (input.getDescription().equals(CREATED_BY_PLUGIN_MESSAGE)) return input.getName(); else return null; } }), new Predicate<String>() { @Override public boolean apply(final String input) { return !Strings.isNullOrEmpty(input); } })); } private SUser createUserAccount(User user) { loggerFactory.getServerLogger().info("User [" + user.getName() + "] doesn't exists in TeamCity. Creating!"); SUser userAccount = userModel.createUserAccount(CrowdPluginAuthenticationScheme.REALM, user.getName()); userAccount.updateUserAccount(user.getName(), user.getDisplayName(), user.getEmailAddress()); return userAccount; } private Optional<SUser> findUserAccountFor(User user) { final SUser userAccount = userModel.findUserAccount(CrowdPluginAuthenticationScheme.REALM, user.getName()); if (userAccount != null) { return Optional.of(userAccount); } return Optional.absent(); } }