diff --git a/src/Console/Program.cs b/src/Console/Program.cs index 8d9a7b9c..a3447aa8 100644 --- a/src/Console/Program.cs +++ b/src/Console/Program.cs @@ -535,7 +535,7 @@ namespace Bit.Console } if(parameters.ContainsKey("gn")) { - config.GroupNameAttribute = parameters["gn"]; + config.Ldap.GroupNameAttribute = parameters["gn"]; } if(parameters.ContainsKey("uf")) @@ -544,34 +544,34 @@ namespace Bit.Console } if(parameters.ContainsKey("ue")) { - config.UserEmailAttribute = parameters["ue"]; + config.Ldap.UserEmailAttribute = parameters["ue"]; } if(parameters.ContainsKey("m")) { - config.MemberAttribute = parameters["m"]; + config.Ldap.MemberAttribute = parameters["m"]; } - config.EmailPrefixSuffix = parameters.ContainsKey("ps"); + config.Ldap.EmailPrefixSuffix = parameters.ContainsKey("ps"); if(parameters.ContainsKey("ep")) { - config.UserEmailPrefixAttribute = parameters["ep"]; + config.Ldap.UserEmailPrefixAttribute = parameters["ep"]; } if(parameters.ContainsKey("es")) { - config.UserEmailSuffix = parameters["es"]; + config.Ldap.UserEmailSuffix = parameters["es"]; } if(parameters.ContainsKey("c")) { - config.CreationDateAttribute = parameters["c"]; + config.Ldap.CreationDateAttribute = parameters["c"]; } if(parameters.ContainsKey("r")) { - config.RevisionDateAttribute = parameters["r"]; + config.Ldap.RevisionDateAttribute = parameters["r"]; } } } @@ -588,19 +588,32 @@ namespace Bit.Console if(config.SyncGroups && Core.Services.SettingsService.Instance.Server.Type != Core.Enums.DirectoryType.AzureActiveDirectory) { + Con.Write("Group object class [{0}]: ", config.Ldap.GroupObjectClass); + input = Con.ReadLine(); + if(!string.IsNullOrEmpty(input)) + { + config.Ldap.GroupObjectClass = input; + } Con.Write("Group filter [{0}]: ", config.GroupFilter); input = Con.ReadLine(); if(!string.IsNullOrEmpty(input)) { config.GroupFilter = input; } - Con.Write("Group name attribute [{0}]: ", config.GroupNameAttribute); + Con.Write("Group name attribute [{0}]: ", config.Ldap.GroupNameAttribute); input = Con.ReadLine(); if(!string.IsNullOrEmpty(input)) { - config.GroupNameAttribute = input; + config.Ldap.GroupNameAttribute = input; } } + Con.Write("Group path [{0}]: ", config.Ldap.GroupPath); + input = Con.ReadLine(); + if(!string.IsNullOrEmpty(input)) + { + config.Ldap.GroupPath = input; + } + Con.Write("Sync users? [{0}]: ", config.SyncUsers ? "y" : "n"); input = Con.ReadLine().ToLower(); if(!string.IsNullOrEmpty(input)) @@ -610,39 +623,51 @@ namespace Bit.Console if(config.SyncUsers && Core.Services.SettingsService.Instance.Server.Type != Core.Enums.DirectoryType.AzureActiveDirectory) { - Con.Write("User filter [{0}]: ", config.UserFilter); + Con.Write("User path [{0}]: ", config.Ldap.UserPath); input = Con.ReadLine(); if(!string.IsNullOrEmpty(input)) { - config.UserFilter = input; + config.Ldap.GroupPath = input; } - Con.Write("User email attribute [{0}]: ", config.UserEmailAttribute); + Con.Write("User object class [{0}]: ", config.Ldap.UserObjectClass); input = Con.ReadLine(); if(!string.IsNullOrEmpty(input)) { - config.GroupNameAttribute = input; + config.Ldap.GroupObjectClass = input; } + Con.Write("User email attribute [{0}]: ", config.Ldap.UserEmailAttribute); + input = Con.ReadLine(); + if(!string.IsNullOrEmpty(input)) + { + config.Ldap.GroupNameAttribute = input; + } + } + Con.Write("User filter [{0}]: ", config.UserFilter); + input = Con.ReadLine(); + if(!string.IsNullOrEmpty(input)) + { + config.UserFilter = input; } if(Core.Services.SettingsService.Instance.Server.Type != Core.Enums.DirectoryType.AzureActiveDirectory) { - Con.Write("Member Of Attribute [{0}]: ", config.MemberAttribute); + Con.Write("Member Of Attribute [{0}]: ", config.Ldap.MemberAttribute); input = Con.ReadLine(); if(!string.IsNullOrEmpty(input)) { - config.MemberAttribute = input; + config.Ldap.MemberAttribute = input; } - Con.Write("Creation Attribute [{0}]: ", config.CreationDateAttribute); + Con.Write("Creation Attribute [{0}]: ", config.Ldap.CreationDateAttribute); input = Con.ReadLine(); if(!string.IsNullOrEmpty(input)) { - config.CreationDateAttribute = input; + config.Ldap.CreationDateAttribute = input; } - Con.Write("Changed Attribute [{0}]: ", config.RevisionDateAttribute); + Con.Write("Changed Attribute [{0}]: ", config.Ldap.RevisionDateAttribute); input = Con.ReadLine(); if(!string.IsNullOrEmpty(input)) { - config.RevisionDateAttribute = input; + config.Ldap.RevisionDateAttribute = input; } } diff --git a/src/Core/Models/SyncConfiguration.cs b/src/Core/Models/SyncConfiguration.cs index 9096c280..755e801a 100644 --- a/src/Core/Models/SyncConfiguration.cs +++ b/src/Core/Models/SyncConfiguration.cs @@ -18,18 +18,15 @@ namespace Bit.Core.Models switch(type) { case DirectoryType.ActiveDirectory: - CreationDateAttribute = "whenCreated"; - RevisionDateAttribute = "whenChanged"; - UserEmailPrefixAttribute = "sAMAccountName"; + Ldap.CreationDateAttribute = "whenCreated"; + Ldap.RevisionDateAttribute = "whenChanged"; + Ldap.UserEmailPrefixAttribute = "sAMAccountName"; + Ldap.UserPath = "Users"; + Ldap.GroupPath = "Users"; break; case DirectoryType.AzureActiveDirectory: GroupFilter = null; UserFilter = null; - MemberAttribute = null; - GroupNameAttribute = null; - UserEmailAttribute = null; - UserEmailPrefixAttribute = null; - UserEmailSuffix = null; break; case DirectoryType.Other: IntervalMinutes = 60; @@ -39,18 +36,27 @@ namespace Bit.Core.Models } } - public string GroupFilter { get; set; } = "(&(objectClass=group))"; - public string UserFilter { get; set; } = "(&(objectClass=person))"; + public string GroupFilter { get; set; } + public string UserFilter { get; set; } public bool SyncGroups { get; set; } = true; public bool SyncUsers { get; set; } = true; - public string MemberAttribute { get; set; } = "member"; - public string GroupNameAttribute { get; set; } = "name"; - public string UserEmailAttribute { get; set; } = "mail"; - public bool EmailPrefixSuffix { get; set; } = false; - public string UserEmailPrefixAttribute { get; set; } = "cn"; - public string UserEmailSuffix { get; set; } = "@companyname.com"; - public string CreationDateAttribute { get; set; } - public string RevisionDateAttribute { get; set; } public int IntervalMinutes { get; set; } = 5; + public LdapSyncConfiguration Ldap { get; set; } = new LdapSyncConfiguration(); + + public class LdapSyncConfiguration + { + public string UserPath { get; set; } + public string GroupPath { get; set; } + public string UserObjectClass { get; set; } = "person"; + public string GroupObjectClass { get; set; } = "group"; + public string MemberAttribute { get; set; } = "member"; + public string GroupNameAttribute { get; set; } = "name"; + public string UserEmailAttribute { get; set; } = "mail"; + public bool EmailPrefixSuffix { get; set; } = false; + public string UserEmailPrefixAttribute { get; set; } = "cn"; + public string UserEmailSuffix { get; set; } = "@companyname.com"; + public string CreationDateAttribute { get; set; } + public string RevisionDateAttribute { get; set; } + } } } diff --git a/src/Core/Services/LdapDirectoryService.cs b/src/Core/Services/LdapDirectoryService.cs index 886601ed..3c4e604f 100644 --- a/src/Core/Services/LdapDirectoryService.cs +++ b/src/Core/Services/LdapDirectoryService.cs @@ -85,19 +85,13 @@ namespace Bit.Core.Services var entry = SettingsService.Instance.Server.Ldap.GetDirectoryEntry(); - string originalFilter; - var filter = originalFilter = string.IsNullOrWhiteSpace(SettingsService.Instance.Sync.GroupFilter) ? null : - SettingsService.Instance.Sync.GroupFilter; + var originalFilter = BuildBaseFilter(SettingsService.Instance.Sync.Ldap.GroupObjectClass, + SettingsService.Instance.Sync.GroupFilter); - var searchSinceRevision = !force && !string.IsNullOrWhiteSpace(SettingsService.Instance.Sync.RevisionDateAttribute) && - SettingsService.Instance.LastGroupSyncDate.HasValue; - if(searchSinceRevision) - { - filter = string.Format("(&{0}({1}>={2}))", - filter, - SettingsService.Instance.Sync.RevisionDateAttribute, - SettingsService.Instance.LastGroupSyncDate.Value.ToGeneralizedTimeUTC()); - } + var filter = originalFilter; + var revisionFilter = BuildRevisionFilter(filter, force, SettingsService.Instance.LastGroupSyncDate); + var searchSinceRevision = filter != revisionFilter; + filter = revisionFilter; var searcher = new DirectorySearcher(entry, filter); var result = searcher.FindAll(); @@ -118,8 +112,8 @@ namespace Bit.Core.Services result = searcher.FindAll(); } - var userFilter = string.IsNullOrWhiteSpace(SettingsService.Instance.Sync.UserFilter) ? null : - SettingsService.Instance.Sync.UserFilter; + var userFilter = BuildBaseFilter(SettingsService.Instance.Sync.Ldap.UserObjectClass, + SettingsService.Instance.Sync.UserFilter); var userSearcher = new DirectorySearcher(entry, userFilter); var userResult = userSearcher.FindAll(); @@ -181,10 +175,10 @@ namespace Bit.Core.Services } // Name - if(item.Properties.Contains(SettingsService.Instance.Sync.GroupNameAttribute) && - item.Properties[SettingsService.Instance.Sync.GroupNameAttribute].Count > 0) + if(item.Properties.Contains(SettingsService.Instance.Sync.Ldap.GroupNameAttribute) && + item.Properties[SettingsService.Instance.Sync.Ldap.GroupNameAttribute].Count > 0) { - group.Name = item.Properties[SettingsService.Instance.Sync.GroupNameAttribute][0].ToString(); + group.Name = item.Properties[SettingsService.Instance.Sync.Ldap.GroupNameAttribute][0].ToString(); } else if(item.Properties.Contains("cn") && item.Properties["cn"].Count > 0) { @@ -196,14 +190,14 @@ namespace Bit.Core.Services } // Dates - group.CreationDate = item.Properties.ParseDateTime(SettingsService.Instance.Sync.CreationDateAttribute); - group.RevisionDate = item.Properties.ParseDateTime(SettingsService.Instance.Sync.RevisionDateAttribute); + group.CreationDate = item.Properties.ParseDateTime(SettingsService.Instance.Sync.Ldap.CreationDateAttribute); + group.RevisionDate = item.Properties.ParseDateTime(SettingsService.Instance.Sync.Ldap.RevisionDateAttribute); // Members - if(item.Properties.Contains(SettingsService.Instance.Sync.MemberAttribute) && - item.Properties[SettingsService.Instance.Sync.MemberAttribute].Count > 0) + if(item.Properties.Contains(SettingsService.Instance.Sync.Ldap.MemberAttribute) && + item.Properties[SettingsService.Instance.Sync.Ldap.MemberAttribute].Count > 0) { - foreach(var member in item.Properties[SettingsService.Instance.Sync.MemberAttribute]) + foreach(var member in item.Properties[SettingsService.Instance.Sync.Ldap.MemberAttribute]) { var memberDn = member.ToString(); if(userIndex.ContainsKey(memberDn) && !group.UserMemberExternalIds.Contains(userIndex[memberDn])) @@ -243,17 +237,9 @@ namespace Bit.Core.Services } var entry = SettingsService.Instance.Server.Ldap.GetDirectoryEntry(); - var filter = string.IsNullOrWhiteSpace(SettingsService.Instance.Sync.UserFilter) ? null : - SettingsService.Instance.Sync.UserFilter; - - if(!force && !string.IsNullOrWhiteSpace(SettingsService.Instance.Sync.RevisionDateAttribute) && - SettingsService.Instance.LastUserSyncDate.HasValue) - { - filter = string.Format("(&{0}({1}>={2}))", - filter, - SettingsService.Instance.Sync.RevisionDateAttribute, - SettingsService.Instance.LastUserSyncDate.Value.ToGeneralizedTimeUTC()); - } + var filter = BuildBaseFilter(SettingsService.Instance.Sync.Ldap.UserObjectClass, + SettingsService.Instance.Sync.UserFilter); + filter = BuildRevisionFilter(filter, force, SettingsService.Instance.LastUserSyncDate); var searcher = new DirectorySearcher(entry, filter); var result = searcher.FindAll(); @@ -293,6 +279,36 @@ namespace Bit.Core.Services return Task.FromResult(users); } + private static string BuildBaseFilter(string objectClass, string subFilter) + { + var filter = BuildObjectClassFilter(objectClass); + if(!string.IsNullOrWhiteSpace(subFilter)) + { + filter = string.Format("(&{0}{1})", filter, subFilter); + } + + return filter; + } + + private static string BuildObjectClassFilter(string objectClass) + { + return string.Format("(&(objectClass={0}))", objectClass); + } + + private static string BuildRevisionFilter(string baseFilter, bool force, DateTime? lastRevisionDate) + { + if(!force && lastRevisionDate.HasValue && + !string.IsNullOrWhiteSpace(SettingsService.Instance.Sync.Ldap.RevisionDateAttribute)) + { + baseFilter = string.Format("(&{0}({1}>={2}))", + baseFilter, + SettingsService.Instance.Sync.Ldap.RevisionDateAttribute, + lastRevisionDate.Value.ToGeneralizedTimeUTC()); + } + + return baseFilter; + } + private static UserEntry BuildUser(SearchResult item, bool deleted) { var user = new UserEntry @@ -319,19 +335,19 @@ namespace Bit.Core.Services user.Disabled = EntryDisabled(item); // Email - if(SettingsService.Instance.Sync.EmailPrefixSuffix && - item.Properties.Contains(SettingsService.Instance.Sync.UserEmailPrefixAttribute) && - item.Properties[SettingsService.Instance.Sync.UserEmailPrefixAttribute].Count > 0 && - !string.IsNullOrWhiteSpace(SettingsService.Instance.Sync.UserEmailSuffix)) + if(SettingsService.Instance.Sync.Ldap.EmailPrefixSuffix && + item.Properties.Contains(SettingsService.Instance.Sync.Ldap.UserEmailPrefixAttribute) && + item.Properties[SettingsService.Instance.Sync.Ldap.UserEmailPrefixAttribute].Count > 0 && + !string.IsNullOrWhiteSpace(SettingsService.Instance.Sync.Ldap.UserEmailSuffix)) { user.Email = string.Concat( - item.Properties[SettingsService.Instance.Sync.UserEmailPrefixAttribute][0].ToString(), - SettingsService.Instance.Sync.UserEmailSuffix).ToLowerInvariant(); + item.Properties[SettingsService.Instance.Sync.Ldap.UserEmailPrefixAttribute][0].ToString(), + SettingsService.Instance.Sync.Ldap.UserEmailSuffix).ToLowerInvariant(); } - else if(item.Properties.Contains(SettingsService.Instance.Sync.UserEmailAttribute) && - item.Properties[SettingsService.Instance.Sync.UserEmailAttribute].Count > 0) + else if(item.Properties.Contains(SettingsService.Instance.Sync.Ldap.UserEmailAttribute) && + item.Properties[SettingsService.Instance.Sync.Ldap.UserEmailAttribute].Count > 0) { - user.Email = item.Properties[SettingsService.Instance.Sync.UserEmailAttribute][0] + user.Email = item.Properties[SettingsService.Instance.Sync.Ldap.UserEmailAttribute][0] .ToString() .ToLowerInvariant(); } @@ -341,8 +357,8 @@ namespace Bit.Core.Services } // Dates - user.CreationDate = item.Properties.ParseDateTime(SettingsService.Instance.Sync.CreationDateAttribute); - user.RevisionDate = item.Properties.ParseDateTime(SettingsService.Instance.Sync.RevisionDateAttribute); + user.CreationDate = item.Properties.ParseDateTime(SettingsService.Instance.Sync.Ldap.CreationDateAttribute); + user.RevisionDate = item.Properties.ParseDateTime(SettingsService.Instance.Sync.Ldap.RevisionDateAttribute); return user; }