public void SyncMembership(ITaskReporter reporter) { var filteredGroups = this.groups.Where(g => g.SyncGroupSource == this.configuration.LdapSyncGroupSource).ToList(); reporter.StartTask("Gruppenmitgliedschaften abgleichen", filteredGroups.Count); // Refetch group members (might have been changed/renamed!). var newGroups = this.GetLdapGroups(); foreach (var group in filteredGroups) { reporter.Progress(group.Name); // Set base for diff with new values. LdapGroup newGroup = newGroups.FirstOrDefault(g => g.SyncGroupId == group.SyncGroupId && g.SyncGroupSource == this.configuration.LdapSyncGroupSource); if (newGroup != null) { group.SetOriginalMembers(newGroup.OrginalMembers); } DirectoryAttributeModification[] addedMembers = group.AddedMembers .Select(m => new DirectoryAttribute("member", m).CreateModification(DirectoryAttributeOperation.Add)) .ToArray(); DirectoryAttributeModification[] removedMembers = group.RemovedMembers .Where(m => !m.EndsWith(this.configuration.LdapGruppenBaseDn)) .Select(m => new DirectoryAttribute("member", m).CreateModification(DirectoryAttributeOperation.Delete, forceValue: true)) .ToArray(); if (addedMembers.Any() || removedMembers.Any()) { string groupDn = $"cn={group.Name},{this.configuration.LdapGruppenBaseDn}"; DirectoryAttributeModification[] modifications = addedMembers.Concat(removedMembers).ToArray(); this.ldap.ModifyEntry(groupDn, modifications); foreach (var item in modifications) { foreach (string name in item.GetValues <string>()) { reporter.Log((item.Operation == DirectoryAttributeOperation.Add ? "Hinzugefügt" : "Entfernt") + ": " + name); } } Log.Source.TraceEvent(TraceEventType.Information, 0, "Updated members of LDAP group '{0}': {1} added, {2} removed.", group.Name, addedMembers.Length, removedMembers.Length); foreach (string modifiedPrint in modifications.SelectMany(Log.Print)) { Log.Source.TraceEvent(TraceEventType.Verbose, 0, "Update to LDAP group '{0}': {1}.", group.Name, modifiedPrint); } } } }
public static LdapGroup FromEntry(Novell.Directory.Ldap.LdapEntry entry) { LdapGroup group = new LdapGroup(); string[] attrs = new string[] { "cn", "sAMAccountName", "distinguishedName", "member" }; System.Reflection.FieldInfo[] fis = typeof(LdapGroup).GetFields(); foreach (System.Reflection.FieldInfo fi in fis) { string fieldName = fi.Name; int ind = System.Array.FindIndex(attrs, x => string.Equals(x, fieldName, System.StringComparison.InvariantCultureIgnoreCase)); if (ind == -1) { continue; } string attributeName = attrs[ind]; Novell.Directory.Ldap.LdapAttribute att = entry.getAttribute(attributeName); if (att == null) { continue; } if (fi.FieldType.IsGenericType) { fi.FieldType.GetMethod("AddRange").Invoke(fi.GetValue(group), new object[] { att.StringValueArray }); } else { fi.SetValue(group, att.StringValue); } } // Next fi return(group); } // End Function FromEntry
public static bool IsDivisionAdminForGroup(this ClaimsPrincipal user, LdapGroup group) { return(user.HasClaim(IsDivisionLgsClaim.ClaimType, group.DivisionId)); }
private void SyncUser(ITaskReporter reporter, PersonModel model, SearchResultEntry entry, bool fullSync) { ICollection <PersonenkategorieModel> kategorien = this.groups.GetKategorien(model.Nr); // this.optigem.GetPersonenkategorien(model.Nr).ToList(); bool disabled = this.IsDisabled(model, kategorien); string baseDn; string requiredBaseDn; string mitgliederBase = "ou=mitglieder," + this.configuration.LdapBenutzerBaseDn; string externBase = "ou=extern," + this.configuration.LdapBenutzerBaseDn; if (disabled) { requiredBaseDn = this.configuration.LdapInaktiveBenutzerBaseDn; baseDn = requiredBaseDn; } else { requiredBaseDn = this.configuration.LdapBenutzerBaseDn; baseDn = kategorien.Any(k => k.Name == "Mitglied") ? mitgliederBase : externBase; } string cn = LdapBuilder.GetCn(model.Username); string dn = $"cn={cn},{baseDn}"; if (disabled && model.EndDatum.HasValue && model.EndDatum.Value < DateTime.Today.AddYears(-2)) { // More than two years inactive => delete in LDAP // No entry in LDAP => ok, NOP if (entry != null) { try { reporter.Log($"Benutzer wird gelöscht (mehr als 2 Jahre inaktiv): {entry.DistinguishedName}"); this.ldap.DeleteEntry(entry.DistinguishedName); } catch (Exception exception) { reporter.Log($"Beim Versuch den Benutzer {cn} zu löschen ist ein Fehler aufgetreten: {exception.Message}"); } } return; } if (entry == null) { SearchResultEntry[] searchResult = this.ldap .PagedSearch($"(&(objectClass=inetOrgPerson)(syncUserId={model.SyncUserId}))", this.configuration.LdapDirectoryBaseDn, LdapBuilder.AllAttributes) .SelectMany(s => s.OfType <SearchResultEntry>()) .ToArray(); if (searchResult.Length == 0) { DirectoryAttribute[] attributes = LdapBuilder.GetAllAttributes(model, disabled).ToArray(); this.ldap.AddEntry(dn, attributes); Log.Source.TraceEvent(TraceEventType.Information, 0, "Added new LDAP user '{0}'.", dn); reporter.Log($"Neuer Benutzer hinzugefügt: {dn}"); } else { entry = searchResult.First(); } } if (entry != null) { string oldDn = entry.DistinguishedName; string oldBaseDn = oldDn.Split(new[] { ',' }, 2).Last(); Log.Source.TraceEvent(TraceEventType.Verbose, 0, "Syncing LDAP user '{0}'.", oldDn); if (!oldDn.EndsWith(requiredBaseDn) || (oldBaseDn == externBase && baseDn == mitgliederBase) || (oldBaseDn == mitgliederBase && baseDn == externBase)) { this.ldap.MoveEntry(oldDn, baseDn, $"cn={cn}"); Log.Source.TraceEvent(TraceEventType.Information, 0, "Moved LDAP user from '{0}' to '{1}'.", oldDn, dn); reporter.Log($"Benutzer von {oldDn} nach {dn} verschoben."); } else { // User was not moved. Set baseDn to actual baseDn. baseDn = oldBaseDn; dn = $"cn={cn},{baseDn}"; string oldCn = entry.Attributes["cn"][0]?.ToString(); if (oldCn != cn) { dn = $"cn={cn},{oldBaseDn}"; this.ldap.MoveEntry(oldDn, oldBaseDn, $"cn={cn}"); Log.Source.TraceEvent(TraceEventType.Information, 0, "Renamed LDAP user from '{0}' to '{1}'.", oldCn, cn); reporter.Log($"Benutzer von {oldCn} nach {cn} umbenannt."); } } DirectoryAttributeModification[] diffAttributes = null; if (fullSync) { diffAttributes = LdapBuilder.GetDiff( LdapBuilder.GetUpdateAttributes(model, disabled), entry, LdapBuilder.CreateAttributes.Union(new[] { "cn", "dn" }).ToArray()) .ToArray(); } else { // only update disabled attribute diffAttributes = LdapBuilder.GetDiff( LdapBuilder.GetUpdateAttributes(model, disabled), entry, LdapBuilder.AllAttributes.Except(new[] { "typo3disabled" }).ToArray()) .ToArray(); } if (diffAttributes?.Any() ?? false) { this.ldap.ModifyEntry(dn, diffAttributes); Log.Source.TraceEvent(TraceEventType.Information, 0, "Updated LDAP user '{0}'.", dn); foreach (var diff in diffAttributes) { var oldAttr = entry.Attributes.Values?.OfType <DirectoryAttribute>().FirstOrDefault(a => string.Equals(a.Name, diff.Name, StringComparison.InvariantCultureIgnoreCase)); string oldValue = oldAttr == null ? string.Empty : string.Join("', '", oldAttr.GetValues <string>()); Debug.Assert(oldValue != string.Join("', '", diff.GetValues <string>())); reporter.Log($"{diff.Name} auf '{string.Join("', '", diff.GetValues<string>())}' gesetzt (alt: '{oldValue}')."); } foreach (string attributeChange in diffAttributes.SelectMany(Log.Print)) { Log.Source.TraceEvent(TraceEventType.Verbose, 0, "Updated LDAP user '{0}': {1}", cn, attributeChange); } } } if (!disabled) { foreach (PersonenkategorieModel kategorie in kategorien) { LdapGroup group = this.groups.Get(kategorie); if (group == null) { Log.Source.TraceEvent(TraceEventType.Warning, 0, "LDAP group does not exist: '{0}'", kategorie.Name); } else { group.MemberList.Add(dn); } } } }
/// <summary> /// Gets all groups found via LDAP /// </summary> /// <param name="ldapConfig">LDAP configuration</param> public LdapGroup[] GetGroups(LdapSettings ldapConfig) { List <LdapGroup> groups = new List <LdapGroup>(); // Connect to group directory via LDAP string ldapStr = GetLdapStr(ldapConfig); using DirectoryEntry entry = Connect($"{ldapStr}/{ldapConfig.LdapGroupDN},{ldapConfig.LdapBaseDN}"); // Apply search filter using DirectorySearcher searcher = new DirectorySearcher(entry); searcher.Filter = ldapConfig.LdapGroupFilter; // Return all found groups foreach (SearchResult result in searcher.FindAll()) { using DirectoryEntry groupEntry = result?.GetDirectoryEntry(); if (groupEntry == null) { continue; } // Obtain attributes object guidData = groupEntry.Properties[ldapConfig.LdapGroupGuidAttr]?.Value; string groupName = groupEntry.Properties[ldapConfig.LdapGroupNameAttr]?.Value?.ToString(); if (guidData == null || !(guidData is byte[]) || string.IsNullOrWhiteSpace(groupName)) { continue; } string guid = (new Guid((byte[])guidData)).ToString(); var group = new LdapGroup(guid, groupName); // Get all members object[] members = groupEntry.Properties[ldapConfig.LdapMember]?.Value as object[]; if (members == null) { continue; } // Add all found member to group foreach (object memberObj in members) { string userDN = memberObj.ToString(); if (string.IsNullOrWhiteSpace(userDN) || !userDN.Contains(ldapConfig.LdapBaseDN, StringComparison.CurrentCultureIgnoreCase)) { // Skip users not part of the LDAP service continue; } // Get user entry using DirectoryEntry user = Connect($"{ldapStr}/{userDN}"); if (user == null) { continue; } object userGuidData = user.Properties[ldapConfig.LdapUserGuidAttr]?.Value; string userName = user.Properties[ldapConfig.LdapUserNameAttr]?.Value?.ToString(); if (userGuidData == null || !(userGuidData is byte[]) || string.IsNullOrWhiteSpace(userName)) { // Skip users without GUID or name continue; } string userGuid = (new Guid((byte[])userGuidData)).ToString(); _logger.LogDebug("{0} (Guid: {1}) is in group: {2}", userName, userGuid, groupName); group.UserGuids.Add(userGuid); } groups.Add(group); } return(groups.ToArray()); }
/// <summary> /// Creates a new role based on information from LDAP /// </summary> /// <param name="ldapGroup">LDAP group information</param> public static Role FromLDAP(LdapGroup ldapGroup) => new Role(ldapGroup.Name) { Origin = Origins.LDAP, LdapGuid = ldapGroup.LdapGuid };
/// <summary> /// Reactivates a role (group) /// </summary> /// <param name="ldapGroup">LDAP group information</param> internal void Reactivate(LdapGroup ldapGroup) { IsDeleted = false; Name = ldapGroup.Name; }
/// <summary> /// Removes the Deleted-Mark from a role (group) again and rehydrates the information from LDAP /// </summary> /// <param name="roleManager"></param> /// <param name="role"></param> /// <param name="ldapGroup"></param> public static async Task <IdentityResult> ReactivateRoleAsync(this RoleManager <Role> roleManager, Role role, LdapGroup ldapGroup) { role.Reactivate(ldapGroup); return(await roleManager.UpdateAsync(role)); }