/// <summary> /// Assigns CMS and AD roles to user. /// </summary> /// <param name="user">AD user</param> /// <param name="userInfo">CMS user</param> /// <param name="userRoles">Collection of <see cref="RoleInfo"/> objects user is in – infos are supposed to contain RoleGUID.</param> /// <param name="site">CMS roles</param> /// <param name="siteInfo">Site info object</param> private static void SetMemberships(IPrincipalObject user, UserInfo userInfo, SiteInfo siteInfo, ICollection <RoleInfo> userRoles, KeyValuePair <string, List <Guid> > site) { var roleGuids = Enumerable.Empty <Guid>() .Union(site.Value) // CMS role GUIDs user should be in .Union(user.Groups); // AD role GUIDs user should be in (groups in which the user participates in AD and are imported to CMS) foreach (RoleInfo roleInfo in roleGuids .Except(userRoles.Select(userRole => userRole.RoleGUID)) .Select(groupId => RoleInfo.Provider.Get().OnSite(siteInfo.SiteID).WhereEquals("RoleGuid", groupId).FirstOrDefault()) .Where(roleInfo => (roleInfo != null))) { // Add user to the role UserRoleInfo.Provider.Add(userInfo.UserID, roleInfo.RoleID); // Update collection of user roles (to reflect real roles user is in) userRoles.Add(roleInfo); MessageLog.LogEvent(ResHelper.GetString("Log_AssigningUserToRole", userInfo.UserName, roleInfo.RoleDisplayName)); } }
/// <summary> /// Synchronizes memberships of given user. /// </summary> /// <param name="user">AD user</param> /// <param name="userInfo">CMS user</param> /// <param name="userRoles">Collection of <see cref="RoleInfo"/> objects user is in – infos are supposed to contain RoleGUID and RoleIsDomain.</param> private static void RemoveExcessiveMemberships(IPrincipalObject user, UserInfo userInfo, ISet <RoleInfo> userRoles) { // Add message to log MessageLog.LogEvent(ResHelper.GetString("Log_UpdatingMemberships", userInfo.UserName)); // Get all user's roles that originate in AD and user is no longer member of var removedRoles = new List <RoleInfo>(); foreach (var roleInfo in userRoles .Where(role => role.RoleIsDomain) .Where(userRole => !user.IsPrincipalInGroup(userRole.RoleGUID))) { // Remove user from CMS role UserRoleInfoProvider.DeleteUserRoleInfo(userInfo, roleInfo); // Store removed roles removedRoles.Add(roleInfo); } // Update set of user roles (to reflect real roles user is in) userRoles.ExceptWith(removedRoles); }
private static void ImportWorker_DoWork(object sender, DoWorkEventArgs e) { try { BackgroundWorker worker = (BackgroundWorker)sender; // Save import profile if (ImportProfile.SaveImportProfile && !ImportProfile.UsesConsole) { SaveFile(SaveImportProfile); } // Decide whether to import if (!ImportProfile.ImportNow && !ImportProfile.UsesConsole) { return; } using (new CMSActionContext() { LogEvents = false, ContinuousIntegrationAllowObjectSerialization = false }) { #region "Initialization" // Import canceled if (worker.CancellationPending) { e.Cancel = true; return; } DateTime start = DateTime.Now; // Initialize CMS context CMSInit(); if (ImportProfile.UsesConsole) { // Ensure object in case they are not present in import profile EnsureObjects(); } if (ImportProfile.ImportUsersOnlyFromSelectedRoles) { // Narrow down imported users according to imported roles ImportProfile.Users.Clear(); } // Import canceled if (worker.CancellationPending) { e.Cancel = true; return; } // Initialize cumulative changed users and roles storages var rolesChanged = new CumulatedChanges(WellKnownEventLogEventsEnum.RolesCreated, WellKnownEventLogEventsEnum.RolesUpdated, WellKnownEventLogEventsEnum.RolesDeleted); var usersChanged = new CumulatedChanges(WellKnownEventLogEventsEnum.UsersCreated, WellKnownEventLogEventsEnum.UsersUpdated, WellKnownEventLogEventsEnum.UsersDeleted); #endregion // Delete non-existing objects (this also prevents conflicting code names) if (ImportProfile.DeleteNotExistingObjects) { DeleteNonExistingObjects(usersChanged, rolesChanged); } #region "Role import" foreach (var siteInfo in ImportProfile .Sites .Select(site => SiteInfo.Provider.Get(site.Key)) .Where(info => info != null)) { foreach (Guid groupGuid in ImportProfile.Groups) { // Import canceled if (worker.CancellationPending) { e.Cancel = true; return; } // Try to get group IPrincipalObject group = PrincipalProvider.GetPrincipalObject(groupGuid); // If group is still null if (group == null) { MessageLog.LogEvent(ResHelper.GetString("Log_SkippingNonExistingObject")); warnings++; // If deleting of not existing objects is enabled if (ImportProfile.DeleteNotExistingObjects) { DeleteRole(siteInfo, groupGuid); } } else { // Get role description string roleDescription = String.Empty; if (ImportProfile.ImportRoleDescription && (group.Description != null)) { roleDescription = group.Description; } // Get correct role name format string roleCodeName = group.GetCMSCodeName(true); // Get role display name string roleDisplayName = group.GetCMSDisplayName(); // Get safe role name roleCodeName = ValidationHelper.GetSafeRoleName(roleCodeName, siteInfo.SiteName); if (!String.IsNullOrEmpty(roleCodeName)) { // Add message to log MessageLog.LogEvent(ResHelper.GetString("Log_ImportingRole", roleDisplayName, CMS.Helpers.ResHelper.LocalizeString(siteInfo.DisplayName))); // Import role ImportRole(roleCodeName, roleDisplayName, siteInfo.SiteID, roleDescription, groupGuid, ImportProfile.UpdateObjectData, rolesChanged); if (ImportProfile.ImportUsersOnlyFromSelectedRoles) { ImportProfile.Users.AddRange(PrincipalProvider.GetUsersOf(group).Select(u => u.Identifier)); } } else { // Add message to log MessageLog.LogEvent(ResHelper.GetString("Log_SkippingEmptyRolename", group.Identifier)); warnings++; } } } } // Log created and updated and removed roles to EventLog rolesChanged.WriteEventsToEventLog(); #endregion #region "User import" foreach (var user in ImportProfile .Users .Distinct() .Select(userGuid => PrincipalProvider.GetPrincipalObject(userGuid))) { // Import canceled if (worker.CancellationPending) { e.Cancel = true; return; } if (user == null) { MessageLog.LogEvent(ResHelper.GetString("Log_SkippingNonExistingObject")); continue; } string domainName = user.GetCMSCodeName(true); if (!String.IsNullOrEmpty(domainName)) { // Get user info object UserInfo userInfo = (UserInfo.Provider.Get((Guid)user.Identifier) ?? UserInfo.Provider.Get(domainName)); bool newUser = (userInfo == null); // When is desired to import new users only from selected roles if (newUser && ImportProfile.ImportNewUsersOnlyFromSelectedRoles) { // Skip users that does not belong to one of selected role bool skip = ImportProfile.Groups.Cast <Guid>().All(groupGuid => !user.IsPrincipalInGroup(groupGuid)); if (skip) { MessageLog.LogEvent(ResHelper.GetString("Log_SkippingDoesNotBelongToSelectedRole", domainName)); continue; } } if (ImportProfile.UpdateObjectData || newUser) { if (userInfo == null) { userInfo = new UserInfo(); // Add message to log MessageLog.LogEvent(ResHelper.GetString("Log_ImportingUser", domainName)); } else { // Add message to log MessageLog.LogEvent(ResHelper.GetString("Log_UpdatingUser", domainName)); } using (var transaction = new CMSTransactionScope()) { if (newUser) { userInfo.UserIsDomain = true; userInfo.UserGUID = (Guid)user.Identifier; // Set privilege level UserPrivilegeLevelEnum privilegeLevel = ImportProfile.ConfigureAsCMSEditor ? UserPrivilegeLevelEnum.Editor : UserPrivilegeLevelEnum.None; userInfo.SiteIndependentPrivilegeLevel = privilegeLevel; } if (userInfo.UserIsDomain) { // Set user's properties userInfo.UserIsExternal = true; userInfo.UserName = domainName; userInfo.Enabled = ValidationHelper.GetBoolean(user.Enabled, true); // Bind properties foreach (KeyValuePair <string, string> property in ImportProfile.UserProperties) { // Get attribute object attribute = user.GetProperty(property.Value); if (attribute != null) { try { string attrValue; // Get string representation of the attribute if (attribute is float || attribute is double || attribute is decimal) { attrValue = String.Format(CultureInfo.InvariantCulture, "{0}", attribute); } else if (attribute.GetType() == typeof(byte[])) { attrValue = PrincipalProvider.GetSID(attribute); } else if (attribute.GetType().BaseType == typeof(MarshalByRefObject)) { attrValue = PrincipalProvider.GetTimeFromInterval(attribute); } else { attrValue = attribute.ToString(); } // Set property userInfo.SetValue(property.Key, LimitLengthForField(attrValue, property.Key)); } catch { MessageLog.LogEvent(ResHelper.GetString("Log_ErrorParsingAttr", property.Value)); warnings++; } } else { FormFieldInfo field = UserFormInfo.GetFormField(property.Key); userInfo.SetValue(property.Key, field.GetPropertyValue(FormFieldPropertyEnum.DefaultValue)); } } // Create full name if empty if (String.IsNullOrEmpty(userInfo.FullName)) { userInfo.FullName = user.GetCMSDisplayName(); } // Store user info object and its user-settings if (userInfo.ChangedColumns().Any()) { // Store created/updated user for EventLog // User name is used, because AD accounts does not have to have first and/or given name specified (e.g. Guest, …) usersChanged.Add(userInfo.UserGUID, userInfo.UserName, newUser ? ChangeActionEnum.Created : ChangeActionEnum.Updated); UserInfo.Provider.Set(userInfo); } } else { MessageLog.LogEvent(ResHelper.GetString("Log_UserIsNotDomain", userInfo.UserName)); warnings++; } transaction.Commit(); } } else { MessageLog.LogEvent(ResHelper.GetString("Log_SkippingExistingUser", domainName)); } // Import canceled if (worker.CancellationPending) { e.Cancel = true; return; } // Assign user to sites and roles (for domain users only) if (!userInfo.UserIsDomain) { continue; } #region "Membership (roles) synchronization" if (!newUser && !ImportProfile.UpdateMemberships && !ImportProfile.UpdateMemberships) { // No membership synchronization will be performed continue; } // Initialize collection to cumulate membership changes var memberShipChanges = new CumulatedRolesMembership(); // Load all user roles from DB var userRoles = new HashSet <RoleInfo>(newUser ? Enumerable.Empty <RoleInfo>() // non-existing user cannot be present in a single role (in DB) : RoleInfo.Provider .Get() .WhereIn("RoleID", UserRoleInfo.Provider .Get() .WhereEquals("UserID", userInfo.UserID) .Column("RoleID")) .Columns("RoleID", "RoleGUID", "RoleDisplayName", "RoleIsDomain")); // Store user's roles before membership synchronization memberShipChanges.SetRolesBefore(userRoles); foreach (KeyValuePair <string, List <Guid> > site in ImportProfile.Sites) { // Get site info object var siteInfo = SiteInfo.Provider.Get(site.Key); if (siteInfo != null) { try { // Add user to this site UserSiteInfo.Provider.Add(userInfo.UserID, siteInfo.SiteID); } catch (Exception ex) { MessageLog.LogEvent(ResHelper.GetString("Log_GeneralWarning", ex.Message)); warnings++; } // Assign user to roles already existing in CMS if (newUser || ImportProfile.UpdateMemberships) { SetMemberships(user, userInfo, siteInfo, userRoles, site); } // Remove user from roles they is member no more if (!newUser && ImportProfile.UpdateMemberships) { RemoveExcessiveMemberships(user, userInfo, userRoles); } } else { MessageLog.LogEvent(ResHelper.GetString("Log_SiteNotExist", site.Key)); warnings++; } } // Store user's roles after membership synchronization memberShipChanges.SetRolesAfter(userRoles); // Log created and removed memberships to EventLog memberShipChanges.WriteEventsToEventLog(userInfo.UserName); #endregion } else { // Add message to log MessageLog.LogEvent(ResHelper.GetString("Log_SkippingEmptyUsername", user.Identifier)); warnings++; } } // Log created and updated and deleted users to EventLog usersChanged.WriteEventsToEventLog(); #endregion // Import canceled if (worker.CancellationPending) { e.Cancel = true; return; } TimeSpan duration = DateTime.Now - start; if (!worker.CancellationPending) { // Add message to log MessageLog.LogEvent(warnings == 0 ? ResHelper.GetString("Log_ImportComplete", duration.Hours, duration.Minutes, duration.Seconds) : ResHelper.GetString("Log_ImportCompleteWithWarnings", warnings, duration.Hours, duration.Minutes, duration.Seconds)); } } } catch (Exception ex) { MessageLog.LogError(ResHelper.GetString("Error_General"), ex); } }
/// <summary> /// Loads users of given group. /// </summary> /// <param name="principalKey">Identifier (GUID) of group to load users from.</param> private void LoadGroupUsers(object principalKey) { DataTable usersTable = new DataTable(); usersTable.Columns.Add(new DataColumn(COLUMN_SELECTED, typeof(Boolean))); usersTable.Columns.Add(new DataColumn(COLUMN_DISPLAYNAME, typeof(String))); usersTable.Columns.Add(new DataColumn(COLUMN_USERNAME, typeof(String))); usersTable.Columns.Add(new DataColumn(COLUMN_USERGUID, typeof(Guid))); // Get group based on node selected in tree IPrincipalObject group = ADProvider.GetPrincipalObject(principalKey); if (group != null) { // Get members of group List <IPrincipalObject> users = ADProvider.GetUsersOf(group); foreach (IPrincipalObject user in users) { // Get user's identifier object userIdentifier = user.Identifier; // Get the display name of user string displayName = !string.IsNullOrEmpty(user.DisplayName) ? user.DisplayName : user.Name; // Create new row with the table schema DataRow dr = usersTable.NewRow(); // Add row to table usersTable.Rows.Add(dr); // Add data to row object[] dataRow = { user.IsSelected, displayName, user.GetCMSCodeName(true), userIdentifier }; dr.ItemArray = dataRow; } // Apply sorting usersTable.DefaultView.Sort = COLUMN_DISPLAYNAME; // Bind table as a grid's data source using (InvokeHelper ih = new InvokeHelper(grdUsers)) { ih.InvokeMethod(delegate { grdUsers.DataSource = usersTable; // Adjust columns DataGridViewColumn columnSelected = grdUsers.Columns[COLUMN_SELECTED]; if (columnSelected != null) { columnSelected.HeaderText = ResHelper.GetString("General_Import"); columnSelected.AutoSizeMode = DataGridViewAutoSizeColumnMode.ColumnHeader; } DataGridViewColumn columnDisplayName = grdUsers.Columns[COLUMN_DISPLAYNAME]; if (columnDisplayName != null) { columnDisplayName.HeaderText = ResHelper.GetString("General_DisplayName"); columnDisplayName.AutoSizeMode = DataGridViewAutoSizeColumnMode.Fill; columnDisplayName.ReadOnly = true; } DataGridViewColumn columnUserName = grdUsers.Columns[COLUMN_USERNAME]; if (columnUserName != null) { columnUserName.HeaderText = ResHelper.GetString("General_CMSUsername"); columnUserName.AutoSizeMode = DataGridViewAutoSizeColumnMode.Fill; columnUserName.ReadOnly = true; } DataGridViewColumn columnUserGuid = grdUsers.Columns[COLUMN_USERGUID]; if (columnUserGuid != null) { columnUserGuid.Visible = false; } // Set enabled state btnSelectAllUsers.Enabled = (grdUsers.Rows.Count > 0); btnDeselectAllUsers.Enabled = (grdUsers.Rows.Count > 0); }); } } // Do not interrupt mass actions if ((treeMassActions == null) || (!treeMassActions.IsAlive)) { SetWait(false, string.Empty); } }