Optimise for quick AD user searching
Avoids loading users groups when not needed
This commit is contained in:
@@ -245,6 +245,7 @@ namespace Disco.Services.Interop.ActiveDirectory
|
|||||||
|
|
||||||
#region User Account
|
#region User Account
|
||||||
private static readonly string[] UserLoadProperties = { "name", "distinguishedName", "sAMAccountName", "objectSid", "displayName", "sn", "givenName", "memberOf", "primaryGroupID", "mail", "telephoneNumber" };
|
private static readonly string[] UserLoadProperties = { "name", "distinguishedName", "sAMAccountName", "objectSid", "displayName", "sn", "givenName", "memberOf", "primaryGroupID", "mail", "telephoneNumber" };
|
||||||
|
private static readonly string[] UserQuickLoadProperties = { "name", "distinguishedName", "sAMAccountName", "objectSid", "displayName", "sn", "givenName", "mail", "telephoneNumber" };
|
||||||
|
|
||||||
public static ActiveDirectoryUserAccount RetrieveUserAccount(string Id, params string[] AdditionalProperties)
|
public static ActiveDirectoryUserAccount RetrieveUserAccount(string Id, params string[] AdditionalProperties)
|
||||||
{
|
{
|
||||||
@@ -254,9 +255,13 @@ namespace Disco.Services.Interop.ActiveDirectory
|
|||||||
? UserLoadProperties.Concat(AdditionalProperties).ToArray()
|
? UserLoadProperties.Concat(AdditionalProperties).ToArray()
|
||||||
: UserLoadProperties;
|
: UserLoadProperties;
|
||||||
|
|
||||||
return SearchBySamAccountName(Id, ldapFilter, loadProperites).Select(result => result.AsUserAccount(AdditionalProperties)).FirstOrDefault();
|
return SearchBySamAccountName(Id, ldapFilter, loadProperites).Select(result => result.AsUserAccount(false, AdditionalProperties)).FirstOrDefault();
|
||||||
}
|
}
|
||||||
public static IEnumerable<ActiveDirectoryUserAccount> SearchUserAccounts(string Term, params string[] AdditionalProperties)
|
public static IEnumerable<ActiveDirectoryUserAccount> SearchUserAccounts(string Term, params string[] AdditionalProperties)
|
||||||
|
{
|
||||||
|
return SearchUserAccounts(Term, false, AdditionalProperties);
|
||||||
|
}
|
||||||
|
public static IEnumerable<ActiveDirectoryUserAccount> SearchUserAccounts(string Term, bool Quick, params string[] AdditionalProperties)
|
||||||
{
|
{
|
||||||
const int resultLimit = 30; // Default Search Limit
|
const int resultLimit = 30; // Default Search Limit
|
||||||
|
|
||||||
@@ -272,26 +277,30 @@ namespace Disco.Services.Interop.ActiveDirectory
|
|||||||
|
|
||||||
string ldapFilter = string.Format("(&(objectCategory=Person)(objectClass=user)(|(sAMAccountName=*{0}*)(displayName=*{0}*)))", ADInterop.EscapeLdapQuery(Term));
|
string ldapFilter = string.Format("(&(objectCategory=Person)(objectClass=user)(|(sAMAccountName=*{0}*)(displayName=*{0}*)))", ADInterop.EscapeLdapQuery(Term));
|
||||||
|
|
||||||
string[] loadProperites = (AdditionalProperties != null && AdditionalProperties.Length > 0)
|
string[] loadProperites = Quick
|
||||||
? UserLoadProperties.Concat(AdditionalProperties).ToArray()
|
? UserQuickLoadProperties
|
||||||
: UserLoadProperties;
|
: UserLoadProperties;
|
||||||
|
|
||||||
|
if (AdditionalProperties != null && AdditionalProperties.Length > 0)
|
||||||
|
loadProperites.Concat(AdditionalProperties).ToArray();
|
||||||
|
|
||||||
IEnumerable<ActiveDirectorySearchResult> searchResults;
|
IEnumerable<ActiveDirectorySearchResult> searchResults;
|
||||||
if (searchDomain == null)
|
if (searchDomain == null)
|
||||||
searchResults = ADInterop.SearchScope(ldapFilter, resultLimit, loadProperites);
|
searchResults = ADInterop.SearchScope(ldapFilter, resultLimit, loadProperites);
|
||||||
else
|
else
|
||||||
searchResults = ADInterop.SearchScope(searchDomain, ldapFilter, resultLimit, loadProperites);
|
searchResults = ADInterop.SearchScope(searchDomain, ldapFilter, resultLimit, loadProperites);
|
||||||
|
|
||||||
return searchResults.Select(result => result.AsUserAccount(AdditionalProperties));
|
return searchResults.Select(result => result.AsUserAccount(Quick, AdditionalProperties));
|
||||||
}
|
}
|
||||||
|
|
||||||
private static ActiveDirectoryUserAccount AsUserAccount(this ActiveDirectorySearchResult item, string[] AdditionalProperties)
|
private static ActiveDirectoryUserAccount AsUserAccount(this ActiveDirectorySearchResult item, bool Quick, string[] AdditionalProperties)
|
||||||
{
|
{
|
||||||
string name = item.Result.Properties["name"][0].ToString();
|
string name = item.Result.Properties["name"][0].ToString();
|
||||||
string username = item.Result.Properties["sAMAccountName"][0].ToString();
|
string username = item.Result.Properties["sAMAccountName"][0].ToString();
|
||||||
string distinguishedName = item.Result.Properties["distinguishedName"][0].ToString();
|
string distinguishedName = item.Result.Properties["distinguishedName"][0].ToString();
|
||||||
byte[] objectSid = (byte[])item.Result.Properties["objectSid"][0];
|
byte[] objectSid = (byte[])item.Result.Properties["objectSid"][0];
|
||||||
string objectSidSDDL = ADInterop.ConvertBytesToSDDLString(objectSid);
|
string objectSidSDDL = ADInterop.ConvertBytesToSDDLString(objectSid);
|
||||||
|
List<string> groups = null;
|
||||||
|
|
||||||
ResultPropertyValueCollection displayNameProp = item.Result.Properties["displayName"];
|
ResultPropertyValueCollection displayNameProp = item.Result.Properties["displayName"];
|
||||||
string displayName = username;
|
string displayName = username;
|
||||||
@@ -314,15 +323,19 @@ namespace Disco.Services.Interop.ActiveDirectory
|
|||||||
if (phoneProp.Count > 0)
|
if (phoneProp.Count > 0)
|
||||||
phone = phoneProp[0].ToString();
|
phone = phoneProp[0].ToString();
|
||||||
|
|
||||||
|
// Don't load Groups when doing a quick search
|
||||||
|
if (!Quick)
|
||||||
|
{
|
||||||
int primaryGroupID = (int)item.Result.Properties["primaryGroupID"][0];
|
int primaryGroupID = (int)item.Result.Properties["primaryGroupID"][0];
|
||||||
string primaryGroupSid = ADInterop.ConvertBytesToSDDLString(ADInterop.BuildPrimaryGroupSid(objectSid, primaryGroupID));
|
string primaryGroupSid = ADInterop.ConvertBytesToSDDLString(ADInterop.BuildPrimaryGroupSid(objectSid, primaryGroupID));
|
||||||
var groupDistinguishedNames = item.Result.Properties["memberOf"].Cast<string>().ToList();
|
var groupDistinguishedNames = item.Result.Properties["memberOf"].Cast<string>().ToList();
|
||||||
groupDistinguishedNames.Add(ADGroupCache.GetGroupsDistinguishedNameForSecurityIdentifier(primaryGroupSid));
|
groupDistinguishedNames.Add(ADGroupCache.GetGroupsDistinguishedNameForSecurityIdentifier(primaryGroupSid));
|
||||||
List<string> groups = ADGroupCache.GetGroups(groupDistinguishedNames).ToList();
|
groups = ADGroupCache.GetGroups(groupDistinguishedNames).ToList();
|
||||||
|
}
|
||||||
|
|
||||||
// Additional Properties
|
// Additional Properties
|
||||||
Dictionary<string, object[]> additionalProperties = new Dictionary<string, object[]>();
|
Dictionary<string, object[]> additionalProperties = new Dictionary<string, object[]>();
|
||||||
if (AdditionalProperties != null)
|
if (AdditionalProperties != null && AdditionalProperties.Length > 0)
|
||||||
foreach (string propertyName in AdditionalProperties)
|
foreach (string propertyName in AdditionalProperties)
|
||||||
{
|
{
|
||||||
var property = item.Result.Properties[propertyName];
|
var property = item.Result.Properties[propertyName];
|
||||||
@@ -457,7 +470,7 @@ namespace Disco.Services.Interop.ActiveDirectory
|
|||||||
private static readonly string[] ObjectLoadProperties = { "objectCategory" };
|
private static readonly string[] ObjectLoadProperties = { "objectCategory" };
|
||||||
private static readonly string[] ObjectLoadPropertiesAll = ObjectLoadProperties.Concat(UserLoadProperties).Concat(MachineLoadProperties).Concat(GroupLoadProperties).Distinct().ToArray();
|
private static readonly string[] ObjectLoadPropertiesAll = ObjectLoadProperties.Concat(UserLoadProperties).Concat(MachineLoadProperties).Concat(GroupLoadProperties).Distinct().ToArray();
|
||||||
|
|
||||||
public static IActiveDirectoryObject RetrieveObject(string Id)
|
public static IActiveDirectoryObject RetrieveObject(string Id, bool Quick)
|
||||||
{
|
{
|
||||||
const string ldapFilter = "(&(|(objectCategory=Person)(objectCategory=Computer)(objectCategory=Group))(sAMAccountName={0}))";
|
const string ldapFilter = "(&(|(objectCategory=Person)(objectCategory=Computer)(objectCategory=Group))(sAMAccountName={0}))";
|
||||||
|
|
||||||
@@ -469,7 +482,7 @@ namespace Disco.Services.Interop.ActiveDirectory
|
|||||||
switch (objectCategory)
|
switch (objectCategory)
|
||||||
{
|
{
|
||||||
case "cn=person":
|
case "cn=person":
|
||||||
return result.AsUserAccount(null);
|
return result.AsUserAccount(Quick, null);
|
||||||
case "cn=computer":
|
case "cn=computer":
|
||||||
return result.AsMachineAccount(null);
|
return result.AsMachineAccount(null);
|
||||||
case "cn=group":
|
case "cn=group":
|
||||||
|
|||||||
@@ -171,7 +171,7 @@ namespace Disco.Services.Searching
|
|||||||
|
|
||||||
public static List<User> SearchUsersUpstream(string Term, int? LimitCount = null)
|
public static List<User> SearchUsersUpstream(string Term, int? LimitCount = null)
|
||||||
{
|
{
|
||||||
IEnumerable<ActiveDirectoryUserAccount> matches = ActiveDirectory.SearchUserAccounts(Term);
|
IEnumerable<ActiveDirectoryUserAccount> matches = ActiveDirectory.SearchUserAccounts(Term, Quick: true);
|
||||||
|
|
||||||
if (LimitCount.HasValue)
|
if (LimitCount.HasValue)
|
||||||
matches = matches.Take(LimitCount.Value);
|
matches = matches.Take(LimitCount.Value);
|
||||||
|
|||||||
@@ -208,7 +208,7 @@ namespace Disco.Services.Users
|
|||||||
|
|
||||||
internal static IEnumerable<ActiveDirectoryUserAccount> SearchUsers(DiscoDataContext Database, string Term)
|
internal static IEnumerable<ActiveDirectoryUserAccount> SearchUsers(DiscoDataContext Database, string Term)
|
||||||
{
|
{
|
||||||
var adImportedUsers = ActiveDirectory.SearchUserAccounts(Term);
|
var adImportedUsers = ActiveDirectory.SearchUserAccounts(Term, Quick: true);
|
||||||
foreach (var adU in adImportedUsers.Select(adU => adU.ToRepositoryUser()))
|
foreach (var adU in adImportedUsers.Select(adU => adU.ToRepositoryUser()))
|
||||||
{
|
{
|
||||||
var existingUser = Database.Users.Find(adU.UserId);
|
var existingUser = Database.Users.Find(adU.UserId);
|
||||||
|
|||||||
@@ -108,7 +108,11 @@ namespace Disco.Web.Areas.API.Controllers
|
|||||||
// Validate Subjects
|
// Validate Subjects
|
||||||
if (Subjects != null && Subjects.Length > 0)
|
if (Subjects != null && Subjects.Length > 0)
|
||||||
{
|
{
|
||||||
var subjects = Subjects.Where(s => !string.IsNullOrWhiteSpace(s)).Select(s => s.Trim()).Select(s => new Tuple<string, IActiveDirectoryObject>(s, ActiveDirectory.RetrieveObject(s))).ToList();
|
var subjects = Subjects
|
||||||
|
.Where(s => !string.IsNullOrWhiteSpace(s))
|
||||||
|
.Select(s => s.Trim())
|
||||||
|
.Select(s => Tuple.Create(s, ActiveDirectory.RetrieveObject(s, Quick: true)))
|
||||||
|
.ToList();
|
||||||
var invalidSubjects = subjects.Where(s => s.Item2 == null).ToList();
|
var invalidSubjects = subjects.Where(s => s.Item2 == null).ToList();
|
||||||
|
|
||||||
if (invalidSubjects.Count > 0)
|
if (invalidSubjects.Count > 0)
|
||||||
@@ -242,7 +246,11 @@ namespace Disco.Web.Areas.API.Controllers
|
|||||||
if (Subjects == null || Subjects.Length == 0)
|
if (Subjects == null || Subjects.Length == 0)
|
||||||
throw new ArgumentNullException("Subjects", "At least one Id must be supplied");
|
throw new ArgumentNullException("Subjects", "At least one Id must be supplied");
|
||||||
|
|
||||||
var subjects = Subjects.Where(s => !string.IsNullOrWhiteSpace(s)).Select(s => s.Trim()).Select(s => new Tuple<string, IActiveDirectoryObject>(s, ActiveDirectory.RetrieveObject(s))).ToList();
|
var subjects = Subjects
|
||||||
|
.Where(s => !string.IsNullOrWhiteSpace(s))
|
||||||
|
.Select(s => s.Trim())
|
||||||
|
.Select(s => Tuple.Create(s, ActiveDirectory.RetrieveObject(s, Quick: true)))
|
||||||
|
.ToList();
|
||||||
var invalidSubjects = subjects.Where(s => s.Item2 == null).ToList();
|
var invalidSubjects = subjects.Where(s => s.Item2 == null).ToList();
|
||||||
|
|
||||||
if (invalidSubjects.Count > 0)
|
if (invalidSubjects.Count > 0)
|
||||||
@@ -286,7 +294,7 @@ namespace Disco.Web.Areas.API.Controllers
|
|||||||
else if (!Id.Contains(@"\"))
|
else if (!Id.Contains(@"\"))
|
||||||
Id = string.Format(@"{0}\{1}", ActiveDirectory.PrimaryDomain.NetBiosName, Id);
|
Id = string.Format(@"{0}\{1}", ActiveDirectory.PrimaryDomain.NetBiosName, Id);
|
||||||
|
|
||||||
var subject = ActiveDirectory.RetrieveObject(Id);
|
var subject = ActiveDirectory.RetrieveObject(Id, Quick: true);
|
||||||
|
|
||||||
if (subject == null || !(subject is ActiveDirectoryUserAccount || subject is ActiveDirectoryGroup))
|
if (subject == null || !(subject is ActiveDirectoryUserAccount || subject is ActiveDirectoryGroup))
|
||||||
return Json(null, JsonRequestBehavior.AllowGet);
|
return Json(null, JsonRequestBehavior.AllowGet);
|
||||||
|
|||||||
@@ -288,7 +288,11 @@ namespace Disco.Web.Areas.API.Controllers
|
|||||||
// Validate Subjects
|
// Validate Subjects
|
||||||
if (Subjects != null && Subjects.Length > 0)
|
if (Subjects != null && Subjects.Length > 0)
|
||||||
{
|
{
|
||||||
var subjects = Subjects.Where(s => !string.IsNullOrWhiteSpace(s)).Select(s => s.Trim()).Select(s => new Tuple<string, IActiveDirectoryObject>(s, ActiveDirectory.RetrieveObject(s))).ToList();
|
var subjects = Subjects
|
||||||
|
.Where(s => !string.IsNullOrWhiteSpace(s))
|
||||||
|
.Select(s => s.Trim())
|
||||||
|
.Select(s => Tuple.Create(s, ActiveDirectory.RetrieveObject(s, Quick: true)))
|
||||||
|
.ToList();
|
||||||
var invalidSubjects = subjects.Where(s => s.Item2 == null).ToList();
|
var invalidSubjects = subjects.Where(s => s.Item2 == null).ToList();
|
||||||
|
|
||||||
if (invalidSubjects.Count > 0)
|
if (invalidSubjects.Count > 0)
|
||||||
@@ -382,7 +386,7 @@ namespace Disco.Web.Areas.API.Controllers
|
|||||||
[DiscoAuthorize(Claims.Config.JobQueue.Configure)]
|
[DiscoAuthorize(Claims.Config.JobQueue.Configure)]
|
||||||
public virtual ActionResult Subject(string Id)
|
public virtual ActionResult Subject(string Id)
|
||||||
{
|
{
|
||||||
var subject = ActiveDirectory.RetrieveObject(Id);
|
var subject = ActiveDirectory.RetrieveObject(Id, Quick: true);
|
||||||
|
|
||||||
if (subject == null || !(subject is ActiveDirectoryUserAccount || subject is ActiveDirectoryGroup))
|
if (subject == null || !(subject is ActiveDirectoryUserAccount || subject is ActiveDirectoryGroup))
|
||||||
return Json(null, JsonRequestBehavior.AllowGet);
|
return Json(null, JsonRequestBehavior.AllowGet);
|
||||||
|
|||||||
@@ -28,7 +28,7 @@ namespace Disco.Web.Areas.Config.Controllers
|
|||||||
|
|
||||||
var token = RoleToken.FromAuthorizationRole(ar);
|
var token = RoleToken.FromAuthorizationRole(ar);
|
||||||
var subjects = token.SubjectIds == null ? new List<Models.AuthorizationRole.SubjectDescriptorModel>() :
|
var subjects = token.SubjectIds == null ? new List<Models.AuthorizationRole.SubjectDescriptorModel>() :
|
||||||
token.SubjectIds.Select(subjectId => ActiveDirectory.RetrieveObject(subjectId))
|
token.SubjectIds.Select(subjectId => ActiveDirectory.RetrieveObject(subjectId, Quick: true))
|
||||||
.Where(item => item != null)
|
.Where(item => item != null)
|
||||||
.Select(item => Models.AuthorizationRole.SubjectDescriptorModel.FromActiveDirectoryObject(item))
|
.Select(item => Models.AuthorizationRole.SubjectDescriptorModel.FromActiveDirectoryObject(item))
|
||||||
.OrderBy(item => item.Name).ToList();
|
.OrderBy(item => item.Name).ToList();
|
||||||
@@ -53,7 +53,7 @@ namespace Disco.Web.Areas.Config.Controllers
|
|||||||
.Select(ar => RoleToken.FromAuthorizationRole(ar)).Cast<IRoleToken>().ToList();
|
.Select(ar => RoleToken.FromAuthorizationRole(ar)).Cast<IRoleToken>().ToList();
|
||||||
|
|
||||||
var administratorSubjects = UserService.AdministratorSubjectIds
|
var administratorSubjects = UserService.AdministratorSubjectIds
|
||||||
.Select(subjectId => ActiveDirectory.RetrieveObject(subjectId))
|
.Select(subjectId => ActiveDirectory.RetrieveObject(subjectId, Quick: true))
|
||||||
.Where(item => item != null)
|
.Where(item => item != null)
|
||||||
.Select(item => Models.AuthorizationRole.SubjectDescriptorModel.FromActiveDirectoryObject(item))
|
.Select(item => Models.AuthorizationRole.SubjectDescriptorModel.FromActiveDirectoryObject(item))
|
||||||
.OrderBy(item => item.Name).ToList();
|
.OrderBy(item => item.Name).ToList();
|
||||||
|
|||||||
@@ -29,7 +29,7 @@ namespace Disco.Web.Areas.Config.Controllers
|
|||||||
|
|
||||||
var token = JobQueueToken.FromJobQueue(jq);
|
var token = JobQueueToken.FromJobQueue(jq);
|
||||||
var subjects = token.SubjectIds == null ? new List<Models.JobQueue.ShowModel.SubjectDescriptor>() :
|
var subjects = token.SubjectIds == null ? new List<Models.JobQueue.ShowModel.SubjectDescriptor>() :
|
||||||
token.SubjectIds.Select(subjectId => ActiveDirectory.RetrieveObject(subjectId))
|
token.SubjectIds.Select(subjectId => ActiveDirectory.RetrieveObject(subjectId, Quick: true))
|
||||||
.Where(item => item != null)
|
.Where(item => item != null)
|
||||||
.Select(item => Models.JobQueue.ShowModel.SubjectDescriptor.FromActiveDirectoryObject(item))
|
.Select(item => Models.JobQueue.ShowModel.SubjectDescriptor.FromActiveDirectoryObject(item))
|
||||||
.OrderBy(item => item.Name).ToList();
|
.OrderBy(item => item.Name).ToList();
|
||||||
|
|||||||
@@ -255,7 +255,7 @@ namespace Disco.Web.Controllers
|
|||||||
public virtual ActionResult Administrators()
|
public virtual ActionResult Administrators()
|
||||||
{
|
{
|
||||||
var administratorSubjects = UserService.AdministratorSubjectIds
|
var administratorSubjects = UserService.AdministratorSubjectIds
|
||||||
.Select(subjectId => ActiveDirectory.RetrieveObject(subjectId))
|
.Select(subjectId => ActiveDirectory.RetrieveObject(subjectId, Quick: true))
|
||||||
.Where(item => item != null)
|
.Where(item => item != null)
|
||||||
.Select(item => Disco.Web.Areas.Config.Models.AuthorizationRole.SubjectDescriptorModel.FromActiveDirectoryObject(item))
|
.Select(item => Disco.Web.Areas.Config.Models.AuthorizationRole.SubjectDescriptorModel.FromActiveDirectoryObject(item))
|
||||||
.OrderBy(item => item.Name).ToList();
|
.OrderBy(item => item.Name).ToList();
|
||||||
@@ -284,7 +284,7 @@ namespace Disco.Web.Controllers
|
|||||||
else if (!Id.Contains(@"\"))
|
else if (!Id.Contains(@"\"))
|
||||||
Id = string.Format(@"{0}\{1}", ActiveDirectory.PrimaryDomain.NetBiosName, Id);
|
Id = string.Format(@"{0}\{1}", ActiveDirectory.PrimaryDomain.NetBiosName, Id);
|
||||||
|
|
||||||
var subject = ActiveDirectory.RetrieveObject(Id);
|
var subject = ActiveDirectory.RetrieveObject(Id, Quick: true);
|
||||||
|
|
||||||
if (subject == null || !(subject is ActiveDirectoryUserAccount || subject is ActiveDirectoryGroup))
|
if (subject == null || !(subject is ActiveDirectoryUserAccount || subject is ActiveDirectoryGroup))
|
||||||
return Json(null, JsonRequestBehavior.AllowGet);
|
return Json(null, JsonRequestBehavior.AllowGet);
|
||||||
@@ -302,7 +302,11 @@ namespace Disco.Web.Controllers
|
|||||||
if (Subjects != null || Subjects.Length > 0)
|
if (Subjects != null || Subjects.Length > 0)
|
||||||
{
|
{
|
||||||
|
|
||||||
var subjects = Subjects.Where(s => !string.IsNullOrWhiteSpace(s)).Select(s => s.Trim()).Select(s => new Tuple<string, IActiveDirectoryObject>(s, ActiveDirectory.RetrieveObject(s))).ToList();
|
var subjects = Subjects
|
||||||
|
.Where(s => !string.IsNullOrWhiteSpace(s))
|
||||||
|
.Select(s => s.Trim())
|
||||||
|
.Select(s => Tuple.Create(s, ActiveDirectory.RetrieveObject(s, Quick: true)))
|
||||||
|
.ToList();
|
||||||
var invalidSubjects = subjects.Where(s => s.Item2 == null).ToList();
|
var invalidSubjects = subjects.Where(s => s.Item2 == null).ToList();
|
||||||
|
|
||||||
if (invalidSubjects.Count > 0)
|
if (invalidSubjects.Count > 0)
|
||||||
|
|||||||
Reference in New Issue
Block a user