mirror of
https://github.com/bitwarden/directory-connector
synced 2025-12-21 10:43:16 +00:00
Interface out directory service for Azure implem.
This commit is contained in:
@@ -555,7 +555,7 @@ namespace Bit.Console
|
|||||||
}
|
}
|
||||||
|
|
||||||
Con.WriteLine("Syncing...");
|
Con.WriteLine("Syncing...");
|
||||||
var result = await Sync.SyncAllAsync(force);
|
var result = await Sync.SyncAllAsync(force, true);
|
||||||
|
|
||||||
if(result.Success)
|
if(result.Success)
|
||||||
{
|
{
|
||||||
@@ -595,7 +595,7 @@ namespace Bit.Console
|
|||||||
Con.WriteLine("Querying...");
|
Con.WriteLine("Querying...");
|
||||||
Con.WriteLine();
|
Con.WriteLine();
|
||||||
|
|
||||||
var result = await Sync.GatherAsync(force);
|
var result = await Sync.SyncAllAsync(force, false);
|
||||||
if(result.Success)
|
if(result.Success)
|
||||||
{
|
{
|
||||||
Con.WriteLine("Groups:");
|
Con.WriteLine("Groups:");
|
||||||
|
|||||||
@@ -68,6 +68,9 @@
|
|||||||
<Compile Include="Models\ProfileResponse.cs" />
|
<Compile Include="Models\ProfileResponse.cs" />
|
||||||
<Compile Include="Models\TokenResponse.cs" />
|
<Compile Include="Models\TokenResponse.cs" />
|
||||||
<Compile Include="Services\ApiService.cs" />
|
<Compile Include="Services\ApiService.cs" />
|
||||||
|
<Compile Include="Services\AzureDirectoryService.cs" />
|
||||||
|
<Compile Include="Services\LdapDirectoryService.cs" />
|
||||||
|
<Compile Include="Services\IDirectoryService.cs" />
|
||||||
<Compile Include="Services\SettingsService.cs" />
|
<Compile Include="Services\SettingsService.cs" />
|
||||||
<Compile Include="Utilities\Crypto.cs" />
|
<Compile Include="Utilities\Crypto.cs" />
|
||||||
<Compile Include="Services\TokenService.cs" />
|
<Compile Include="Services\TokenService.cs" />
|
||||||
|
|||||||
32
src/Core/Services/AzureDirectoryService.cs
Normal file
32
src/Core/Services/AzureDirectoryService.cs
Normal file
@@ -0,0 +1,32 @@
|
|||||||
|
using Bit.Core.Models;
|
||||||
|
using System;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
|
||||||
|
namespace Bit.Core.Services
|
||||||
|
{
|
||||||
|
public class AzureDirectoryService : IDirectoryService
|
||||||
|
{
|
||||||
|
private static AzureDirectoryService _instance;
|
||||||
|
|
||||||
|
private AzureDirectoryService() { }
|
||||||
|
|
||||||
|
public static IDirectoryService Instance
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
if(_instance == null)
|
||||||
|
{
|
||||||
|
_instance = new AzureDirectoryService();
|
||||||
|
}
|
||||||
|
|
||||||
|
return _instance;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public Task<Tuple<List<GroupEntry>, List<UserEntry>>> GetEntriesAsync(bool force = false)
|
||||||
|
{
|
||||||
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
14
src/Core/Services/IDirectoryService.cs
Normal file
14
src/Core/Services/IDirectoryService.cs
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
using Bit.Core.Models;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace Bit.Core.Services
|
||||||
|
{
|
||||||
|
public interface IDirectoryService
|
||||||
|
{
|
||||||
|
Task<Tuple<List<GroupEntry>, List<UserEntry>>> GetEntriesAsync(bool force = false);
|
||||||
|
}
|
||||||
|
}
|
||||||
235
src/Core/Services/LdapDirectoryService.cs
Normal file
235
src/Core/Services/LdapDirectoryService.cs
Normal file
@@ -0,0 +1,235 @@
|
|||||||
|
using Bit.Core.Models;
|
||||||
|
using Bit.Core.Utilities;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.DirectoryServices;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace Bit.Core.Services
|
||||||
|
{
|
||||||
|
public class LdapDirectoryService : IDirectoryService
|
||||||
|
{
|
||||||
|
private static LdapDirectoryService _instance;
|
||||||
|
|
||||||
|
private LdapDirectoryService() { }
|
||||||
|
|
||||||
|
public static IDirectoryService Instance
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
if(_instance == null)
|
||||||
|
{
|
||||||
|
_instance = new LdapDirectoryService();
|
||||||
|
}
|
||||||
|
|
||||||
|
return _instance;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<Tuple<List<GroupEntry>, List<UserEntry>>> GetEntriesAsync(bool force = false)
|
||||||
|
{
|
||||||
|
if(!AuthService.Instance.Authenticated || !AuthService.Instance.OrganizationSet)
|
||||||
|
{
|
||||||
|
throw new ApplicationException("Not logged in or have an org set.");
|
||||||
|
}
|
||||||
|
|
||||||
|
if(SettingsService.Instance.Server == null)
|
||||||
|
{
|
||||||
|
throw new ApplicationException("No configuration for directory server.");
|
||||||
|
}
|
||||||
|
|
||||||
|
if(SettingsService.Instance.Sync == null)
|
||||||
|
{
|
||||||
|
throw new ApplicationException("No configuration for sync.");
|
||||||
|
}
|
||||||
|
|
||||||
|
List<GroupEntry> groups = null;
|
||||||
|
if(SettingsService.Instance.Sync.SyncGroups)
|
||||||
|
{
|
||||||
|
groups = await GetGroupsAsync(force);
|
||||||
|
}
|
||||||
|
|
||||||
|
List<UserEntry> users = null;
|
||||||
|
if(SettingsService.Instance.Sync.SyncUsers)
|
||||||
|
{
|
||||||
|
users = await GetUsersAsync(force);
|
||||||
|
}
|
||||||
|
|
||||||
|
return new Tuple<List<GroupEntry>, List<UserEntry>>(groups, users);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static Task<List<GroupEntry>> GetGroupsAsync(bool force = false)
|
||||||
|
{
|
||||||
|
if(!SettingsService.Instance.Sync.SyncGroups)
|
||||||
|
{
|
||||||
|
throw new ApplicationException("Not configured to sync groups.");
|
||||||
|
}
|
||||||
|
|
||||||
|
if(SettingsService.Instance.Server == null)
|
||||||
|
{
|
||||||
|
throw new ApplicationException("No configuration for directory server.");
|
||||||
|
}
|
||||||
|
|
||||||
|
if(SettingsService.Instance.Sync == null)
|
||||||
|
{
|
||||||
|
throw new ApplicationException("No configuration for sync.");
|
||||||
|
}
|
||||||
|
|
||||||
|
if(!AuthService.Instance.Authenticated)
|
||||||
|
{
|
||||||
|
throw new ApplicationException("Not authenticated.");
|
||||||
|
}
|
||||||
|
|
||||||
|
var entry = SettingsService.Instance.Server.GetDirectoryEntry();
|
||||||
|
var filter = string.IsNullOrWhiteSpace(SettingsService.Instance.Sync.GroupFilter) ? null :
|
||||||
|
SettingsService.Instance.Sync.GroupFilter;
|
||||||
|
|
||||||
|
if(!force && !string.IsNullOrWhiteSpace(SettingsService.Instance.Sync.RevisionDateAttribute) &&
|
||||||
|
SettingsService.Instance.LastGroupSyncDate.HasValue)
|
||||||
|
{
|
||||||
|
filter = string.Format("(&{0}({1}>{2}))",
|
||||||
|
filter != null ? string.Format("({0})", filter) : string.Empty,
|
||||||
|
SettingsService.Instance.Sync.RevisionDateAttribute,
|
||||||
|
SettingsService.Instance.LastGroupSyncDate.Value.ToGeneralizedTimeUTC());
|
||||||
|
}
|
||||||
|
|
||||||
|
var searcher = new DirectorySearcher(entry, filter);
|
||||||
|
var result = searcher.FindAll();
|
||||||
|
|
||||||
|
var groups = new List<GroupEntry>();
|
||||||
|
foreach(SearchResult item in result)
|
||||||
|
{
|
||||||
|
var group = new GroupEntry
|
||||||
|
{
|
||||||
|
DistinguishedName = new Uri(item.Path).Segments?.LastOrDefault()
|
||||||
|
};
|
||||||
|
|
||||||
|
if(group.DistinguishedName == null)
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Name
|
||||||
|
if(item.Properties.Contains(SettingsService.Instance.Sync.GroupNameAttribute) &&
|
||||||
|
item.Properties[SettingsService.Instance.Sync.GroupNameAttribute].Count > 0)
|
||||||
|
{
|
||||||
|
group.Name = item.Properties[SettingsService.Instance.Sync.GroupNameAttribute][0].ToString();
|
||||||
|
}
|
||||||
|
else if(item.Properties.Contains("cn") && item.Properties["cn"].Count > 0)
|
||||||
|
{
|
||||||
|
group.Name = item.Properties["cn"][0].ToString();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Dates
|
||||||
|
group.CreationDate = item.Properties.ParseDateTime(SettingsService.Instance.Sync.CreationDateAttribute);
|
||||||
|
group.RevisionDate = item.Properties.ParseDateTime(SettingsService.Instance.Sync.RevisionDateAttribute);
|
||||||
|
|
||||||
|
// Members
|
||||||
|
if(item.Properties.Contains(SettingsService.Instance.Sync.MemberAttribute) &&
|
||||||
|
item.Properties[SettingsService.Instance.Sync.MemberAttribute].Count > 0)
|
||||||
|
{
|
||||||
|
foreach(var member in item.Properties[SettingsService.Instance.Sync.MemberAttribute])
|
||||||
|
{
|
||||||
|
var memberDn = member.ToString();
|
||||||
|
if(!group.Members.Contains(memberDn))
|
||||||
|
{
|
||||||
|
group.Members.Add(memberDn);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
groups.Add(group);
|
||||||
|
}
|
||||||
|
|
||||||
|
return Task.FromResult(groups);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static Task<List<UserEntry>> GetUsersAsync(bool force = false)
|
||||||
|
{
|
||||||
|
if(!SettingsService.Instance.Sync.SyncUsers)
|
||||||
|
{
|
||||||
|
throw new ApplicationException("Not configured to sync users.");
|
||||||
|
}
|
||||||
|
|
||||||
|
if(SettingsService.Instance.Server == null)
|
||||||
|
{
|
||||||
|
throw new ApplicationException("No configuration for directory server.");
|
||||||
|
}
|
||||||
|
|
||||||
|
if(SettingsService.Instance.Sync == null)
|
||||||
|
{
|
||||||
|
throw new ApplicationException("No configuration for sync.");
|
||||||
|
}
|
||||||
|
|
||||||
|
if(!AuthService.Instance.Authenticated)
|
||||||
|
{
|
||||||
|
throw new ApplicationException("Not authenticated.");
|
||||||
|
}
|
||||||
|
|
||||||
|
var entry = SettingsService.Instance.Server.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 != null ? string.Format("({0})", filter) : string.Empty,
|
||||||
|
SettingsService.Instance.Sync.RevisionDateAttribute,
|
||||||
|
SettingsService.Instance.LastUserSyncDate.Value.ToGeneralizedTimeUTC());
|
||||||
|
}
|
||||||
|
|
||||||
|
var searcher = new DirectorySearcher(entry, filter);
|
||||||
|
var result = searcher.FindAll();
|
||||||
|
|
||||||
|
var users = new List<UserEntry>();
|
||||||
|
foreach(SearchResult item in result)
|
||||||
|
{
|
||||||
|
var user = new UserEntry
|
||||||
|
{
|
||||||
|
DistinguishedName = new Uri(item.Path).Segments?.LastOrDefault()
|
||||||
|
};
|
||||||
|
|
||||||
|
if(user.DistinguishedName == null)
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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))
|
||||||
|
{
|
||||||
|
user.Email = string.Concat(
|
||||||
|
item.Properties[SettingsService.Instance.Sync.UserEmailPrefixAttribute][0].ToString(),
|
||||||
|
SettingsService.Instance.Sync.UserEmailSuffix).ToLowerInvariant();
|
||||||
|
}
|
||||||
|
else if(item.Properties.Contains(SettingsService.Instance.Sync.UserEmailAttribute) &&
|
||||||
|
item.Properties[SettingsService.Instance.Sync.UserEmailAttribute].Count > 0)
|
||||||
|
{
|
||||||
|
user.Email = item.Properties[SettingsService.Instance.Sync.UserEmailAttribute][0]
|
||||||
|
.ToString()
|
||||||
|
.ToLowerInvariant();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Dates
|
||||||
|
user.CreationDate = item.Properties.ParseDateTime(SettingsService.Instance.Sync.CreationDateAttribute);
|
||||||
|
user.RevisionDate = item.Properties.ParseDateTime(SettingsService.Instance.Sync.RevisionDateAttribute);
|
||||||
|
|
||||||
|
users.Add(user);
|
||||||
|
}
|
||||||
|
|
||||||
|
return Task.FromResult(users);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,9 +1,7 @@
|
|||||||
using Bit.Core.Models;
|
using Bit.Core.Models;
|
||||||
using Bit.Core.Services;
|
using Bit.Core.Services;
|
||||||
using System;
|
using System;
|
||||||
using System.Collections;
|
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.DirectoryServices;
|
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
@@ -11,268 +9,76 @@ namespace Bit.Core.Utilities
|
|||||||
{
|
{
|
||||||
public static class Sync
|
public static class Sync
|
||||||
{
|
{
|
||||||
public static async Task<SyncResult> SyncAllAsync(bool force = false)
|
public static async Task<SyncResult> SyncAllAsync(bool force = false, bool sendToServer = true)
|
||||||
{
|
{
|
||||||
var now = DateTime.UtcNow;
|
try
|
||||||
var gatherResult = await GatherAsync(force);
|
|
||||||
if(!gatherResult.Success)
|
|
||||||
{
|
{
|
||||||
return gatherResult;
|
var now = DateTime.UtcNow;
|
||||||
}
|
var entriesResult = await GetDirectoryService().GetEntriesAsync(force);
|
||||||
|
var groups = entriesResult.Item1;
|
||||||
|
var users = entriesResult.Item2;
|
||||||
|
|
||||||
var request = new ImportRequest(gatherResult.Groups, gatherResult.Users);
|
FlattenGroupsToUsers(groups, null, groups, users);
|
||||||
var response = await ApiService.Instance.PostImportAsync(request);
|
|
||||||
if(response.Succeeded)
|
if(!sendToServer)
|
||||||
{
|
|
||||||
if(SettingsService.Instance.Sync.SyncGroups)
|
|
||||||
{
|
{
|
||||||
SettingsService.Instance.LastGroupSyncDate = now;
|
return new SyncResult
|
||||||
}
|
|
||||||
|
|
||||||
if(SettingsService.Instance.Sync.SyncUsers)
|
|
||||||
{
|
|
||||||
SettingsService.Instance.LastUserSyncDate = now;
|
|
||||||
}
|
|
||||||
|
|
||||||
return new SyncResult
|
|
||||||
{
|
|
||||||
Success = true,
|
|
||||||
Groups = gatherResult.Groups,
|
|
||||||
Users = gatherResult.Users
|
|
||||||
};
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
return new SyncResult
|
|
||||||
{
|
|
||||||
Success = false,
|
|
||||||
ErrorMessage = response.Errors.FirstOrDefault()?.Message
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static async Task<SyncResult> GatherAsync(bool force = false)
|
|
||||||
{
|
|
||||||
if(!AuthService.Instance.Authenticated || !AuthService.Instance.OrganizationSet)
|
|
||||||
{
|
|
||||||
return new SyncResult
|
|
||||||
{
|
|
||||||
Success = false,
|
|
||||||
ErrorMessage = "Not logged in or have an org set."
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
if(SettingsService.Instance.Server == null)
|
|
||||||
{
|
|
||||||
return new SyncResult
|
|
||||||
{
|
|
||||||
Success = false,
|
|
||||||
ErrorMessage = "No configuration for directory server."
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
if(SettingsService.Instance.Sync == null)
|
|
||||||
{
|
|
||||||
return new SyncResult
|
|
||||||
{
|
|
||||||
Success = false,
|
|
||||||
ErrorMessage = "No configuration for sync."
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
List<GroupEntry> groups = null;
|
|
||||||
if(SettingsService.Instance.Sync.SyncGroups)
|
|
||||||
{
|
|
||||||
groups = await GetGroupsAsync(force);
|
|
||||||
}
|
|
||||||
|
|
||||||
List<UserEntry> users = null;
|
|
||||||
if(SettingsService.Instance.Sync.SyncUsers)
|
|
||||||
{
|
|
||||||
users = await GetUsersAsync(force);
|
|
||||||
}
|
|
||||||
|
|
||||||
FlattenGroupsToUsers(groups, null, groups, users);
|
|
||||||
|
|
||||||
return new SyncResult
|
|
||||||
{
|
|
||||||
Success = true,
|
|
||||||
Groups = groups,
|
|
||||||
Users = users
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
private static Task<List<GroupEntry>> GetGroupsAsync(bool force = false)
|
|
||||||
{
|
|
||||||
if(!SettingsService.Instance.Sync.SyncGroups)
|
|
||||||
{
|
|
||||||
throw new ApplicationException("Not configured to sync groups.");
|
|
||||||
}
|
|
||||||
|
|
||||||
if(SettingsService.Instance.Server == null)
|
|
||||||
{
|
|
||||||
throw new ApplicationException("No configuration for directory server.");
|
|
||||||
}
|
|
||||||
|
|
||||||
if(SettingsService.Instance.Sync == null)
|
|
||||||
{
|
|
||||||
throw new ApplicationException("No configuration for sync.");
|
|
||||||
}
|
|
||||||
|
|
||||||
if(!AuthService.Instance.Authenticated)
|
|
||||||
{
|
|
||||||
throw new ApplicationException("Not authenticated.");
|
|
||||||
}
|
|
||||||
|
|
||||||
var entry = SettingsService.Instance.Server.GetDirectoryEntry();
|
|
||||||
var filter = string.IsNullOrWhiteSpace(SettingsService.Instance.Sync.GroupFilter) ? null :
|
|
||||||
SettingsService.Instance.Sync.GroupFilter;
|
|
||||||
|
|
||||||
if(!force && !string.IsNullOrWhiteSpace(SettingsService.Instance.Sync.RevisionDateAttribute) &&
|
|
||||||
SettingsService.Instance.LastGroupSyncDate.HasValue)
|
|
||||||
{
|
|
||||||
filter = string.Format("(&{0}({1}>{2}))",
|
|
||||||
filter != null ? string.Format("({0})", filter) : string.Empty,
|
|
||||||
SettingsService.Instance.Sync.RevisionDateAttribute,
|
|
||||||
SettingsService.Instance.LastGroupSyncDate.Value.ToGeneralizedTimeUTC());
|
|
||||||
}
|
|
||||||
|
|
||||||
var searcher = new DirectorySearcher(entry, filter);
|
|
||||||
var result = searcher.FindAll();
|
|
||||||
|
|
||||||
var groups = new List<GroupEntry>();
|
|
||||||
foreach(SearchResult item in result)
|
|
||||||
{
|
|
||||||
var group = new GroupEntry
|
|
||||||
{
|
|
||||||
DistinguishedName = new Uri(item.Path).Segments?.LastOrDefault()
|
|
||||||
};
|
|
||||||
|
|
||||||
if(group.DistinguishedName == null)
|
|
||||||
{
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Name
|
|
||||||
if(item.Properties.Contains(SettingsService.Instance.Sync.GroupNameAttribute) &&
|
|
||||||
item.Properties[SettingsService.Instance.Sync.GroupNameAttribute].Count > 0)
|
|
||||||
{
|
|
||||||
group.Name = item.Properties[SettingsService.Instance.Sync.GroupNameAttribute][0].ToString();
|
|
||||||
}
|
|
||||||
else if(item.Properties.Contains("cn") && item.Properties["cn"].Count > 0)
|
|
||||||
{
|
|
||||||
group.Name = item.Properties["cn"][0].ToString();
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Dates
|
|
||||||
group.CreationDate = item.Properties.ParseDateTime(SettingsService.Instance.Sync.CreationDateAttribute);
|
|
||||||
group.RevisionDate = item.Properties.ParseDateTime(SettingsService.Instance.Sync.RevisionDateAttribute);
|
|
||||||
|
|
||||||
// Members
|
|
||||||
if(item.Properties.Contains(SettingsService.Instance.Sync.MemberAttribute) &&
|
|
||||||
item.Properties[SettingsService.Instance.Sync.MemberAttribute].Count > 0)
|
|
||||||
{
|
|
||||||
foreach(var member in item.Properties[SettingsService.Instance.Sync.MemberAttribute])
|
|
||||||
{
|
{
|
||||||
var memberDn = member.ToString();
|
Success = true,
|
||||||
if(!group.Members.Contains(memberDn))
|
Groups = groups,
|
||||||
{
|
Users = users
|
||||||
group.Members.Add(memberDn);
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var request = new ImportRequest(groups, users);
|
||||||
|
var response = await ApiService.Instance.PostImportAsync(request);
|
||||||
|
if(response.Succeeded)
|
||||||
|
{
|
||||||
|
if(SettingsService.Instance.Sync.SyncGroups)
|
||||||
|
{
|
||||||
|
SettingsService.Instance.LastGroupSyncDate = now;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
groups.Add(group);
|
if(SettingsService.Instance.Sync.SyncUsers)
|
||||||
}
|
{
|
||||||
|
SettingsService.Instance.LastUserSyncDate = now;
|
||||||
|
}
|
||||||
|
|
||||||
return Task.FromResult(groups);
|
return new SyncResult
|
||||||
}
|
{
|
||||||
|
Success = true,
|
||||||
private static Task<List<UserEntry>> GetUsersAsync(bool force = false)
|
Groups = groups,
|
||||||
{
|
Users = users
|
||||||
if(!SettingsService.Instance.Sync.SyncUsers)
|
};
|
||||||
{
|
|
||||||
throw new ApplicationException("Not configured to sync users.");
|
|
||||||
}
|
|
||||||
|
|
||||||
if(SettingsService.Instance.Server == null)
|
|
||||||
{
|
|
||||||
throw new ApplicationException("No configuration for directory server.");
|
|
||||||
}
|
|
||||||
|
|
||||||
if(SettingsService.Instance.Sync == null)
|
|
||||||
{
|
|
||||||
throw new ApplicationException("No configuration for sync.");
|
|
||||||
}
|
|
||||||
|
|
||||||
if(!AuthService.Instance.Authenticated)
|
|
||||||
{
|
|
||||||
throw new ApplicationException("Not authenticated.");
|
|
||||||
}
|
|
||||||
|
|
||||||
var entry = SettingsService.Instance.Server.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 != null ? string.Format("({0})", filter) : string.Empty,
|
|
||||||
SettingsService.Instance.Sync.RevisionDateAttribute,
|
|
||||||
SettingsService.Instance.LastUserSyncDate.Value.ToGeneralizedTimeUTC());
|
|
||||||
}
|
|
||||||
|
|
||||||
var searcher = new DirectorySearcher(entry, filter);
|
|
||||||
var result = searcher.FindAll();
|
|
||||||
|
|
||||||
var users = new List<UserEntry>();
|
|
||||||
foreach(SearchResult item in result)
|
|
||||||
{
|
|
||||||
var user = new UserEntry
|
|
||||||
{
|
|
||||||
DistinguishedName = new Uri(item.Path).Segments?.LastOrDefault()
|
|
||||||
};
|
|
||||||
|
|
||||||
if(user.DistinguishedName == null)
|
|
||||||
{
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
// 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))
|
|
||||||
{
|
|
||||||
user.Email = string.Concat(
|
|
||||||
item.Properties[SettingsService.Instance.Sync.UserEmailPrefixAttribute][0].ToString(),
|
|
||||||
SettingsService.Instance.Sync.UserEmailSuffix).ToLowerInvariant();
|
|
||||||
}
|
|
||||||
else if(item.Properties.Contains(SettingsService.Instance.Sync.UserEmailAttribute) &&
|
|
||||||
item.Properties[SettingsService.Instance.Sync.UserEmailAttribute].Count > 0)
|
|
||||||
{
|
|
||||||
user.Email = item.Properties[SettingsService.Instance.Sync.UserEmailAttribute][0]
|
|
||||||
.ToString()
|
|
||||||
.ToLowerInvariant();
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
continue;
|
return new SyncResult
|
||||||
|
{
|
||||||
|
Success = false,
|
||||||
|
ErrorMessage = response.Errors.FirstOrDefault()?.Message
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
// Dates
|
|
||||||
user.CreationDate = item.Properties.ParseDateTime(SettingsService.Instance.Sync.CreationDateAttribute);
|
|
||||||
user.RevisionDate = item.Properties.ParseDateTime(SettingsService.Instance.Sync.RevisionDateAttribute);
|
|
||||||
|
|
||||||
users.Add(user);
|
|
||||||
}
|
}
|
||||||
|
catch (ApplicationException e)
|
||||||
|
{
|
||||||
|
return new SyncResult
|
||||||
|
{
|
||||||
|
Success = false,
|
||||||
|
ErrorMessage = e.Message
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return Task.FromResult(users);
|
private static IDirectoryService GetDirectoryService()
|
||||||
|
{
|
||||||
|
switch(SettingsService.Instance.Server.Type)
|
||||||
|
{
|
||||||
|
case Enums.DirectoryType.AzureActiveDirectory:
|
||||||
|
return AzureDirectoryService.Instance;
|
||||||
|
default:
|
||||||
|
return LdapDirectoryService.Instance;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void FlattenGroupsToUsers(List<GroupEntry> currentGroups, List<UserEntry> currentGroupsUsers,
|
private static void FlattenGroupsToUsers(List<GroupEntry> currentGroups, List<UserEntry> currentGroupsUsers,
|
||||||
|
|||||||
Reference in New Issue
Block a user